blob: f390ae4d88f60bab1d5b9f4bada2319dea5d75b3 [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
Ian Wienand98c35f32013-07-23 20:34:23 +100017import os
Attila Fazekas53943322014-02-10 16:07:34 +010018import sys
Jay Pipes051075a2012-04-28 17:39:37 -040019
Jordan Pittier35a63752016-08-30 13:09:12 +020020import debtcollector.moves
Matthew Treinish78561ad2013-07-26 11:41:56 -040021import fixtures
Doug Hellmann583ce2c2015-03-11 14:55:46 +000022from oslo_log import log as logging
Chris Hoge296558c2015-02-19 00:29:49 -060023import six
ivan-zhu1feeb382013-01-24 10:14:39 +080024import testtools
Jay Pipes051075a2012-04-28 17:39:37 -040025
Matthew Treinish3e046852013-07-23 16:00:24 -040026from tempest import clients
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +010027from tempest.common import credentials_factory as credentials
Andrea Frittolicd368412017-08-14 21:37:56 +010028from tempest.common import utils
nithya-ganesan222efd72015-01-22 12:20:27 +000029import tempest.common.validation_resources as vresources
Attila Fazekasdc216422013-01-29 15:12:14 +010030from tempest import config
Matthew Treinish3787e4c2016-10-07 21:25:33 -040031from tempest.lib.common import cred_client
Matthew Treinishb19c55d2017-07-17 12:38:35 -040032from tempest.lib.common import fixed_network
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -050033from tempest.lib import decorators
Andrea Frittoli (andreaf)af4f7cf2016-06-13 15:12:26 +010034from tempest.lib import exceptions as lib_exc
Jay Pipes051075a2012-04-28 17:39:37 -040035
36LOG = logging.getLogger(__name__)
37
Sean Dague86bd8422013-12-20 09:56:44 -050038CONF = config.CONF
39
Ken'ichi Ohmichi44f01272017-01-27 18:44:14 -080040# TODO(oomichi): This test.idempotent_id should be removed after all projects
41# switch to use decorators.idempotent_id.
42idempotent_id = debtcollector.moves.moved_function(
43 decorators.idempotent_id, 'idempotent_id', __name__,
44 version='Mitaka', removal_version='?')
Matthew Treinishc1802bc2015-12-03 18:48:11 -050045
Jay Pipes051075a2012-04-28 17:39:37 -040046
Jordan Pittier3b46d272017-04-12 16:17:28 +020047attr = debtcollector.moves.moved_function(
48 decorators.attr, 'attr', __name__,
49 version='Pike', removal_version='?')
Chris Yeoh55530bb2013-02-08 16:04:27 +103050
51
Andrea Frittolicd368412017-08-14 21:37:56 +010052services = debtcollector.moves.moved_function(
53 utils.services, 'services', __name__,
54 version='Pike', removal_version='?')
Andrea Frittoli07acf262017-04-09 19:36:37 +020055
56
Andrea Frittolicd368412017-08-14 21:37:56 +010057requires_ext = debtcollector.moves.moved_function(
58 utils.requires_ext, 'requires_ext', __name__,
59 version='Pike', removal_version='?')
Matthew Treinish16c43792013-09-09 19:55:23 +000060
Matthew Treinish3d8c7322014-08-03 23:53:28 -040061
Andrea Frittolicd368412017-08-14 21:37:56 +010062is_extension_enabled = debtcollector.moves.moved_function(
63 utils.is_extension_enabled, 'is_extension_enabled', __name__,
64 version='Pike', removal_version='?')
Ian Wienand98c35f32013-07-23 20:34:23 +100065
Attila Fazekasf86fa312013-07-30 19:56:39 +020066at_exit_set = set()
67
68
69def validate_tearDownClass():
70 if at_exit_set:
Sean Dagueeb1523b2014-03-10 10:17:44 -040071 LOG.error(
72 "tearDownClass does not call the super's "
73 "tearDownClass in these classes: \n"
74 + str(at_exit_set))
75
Attila Fazekasf86fa312013-07-30 19:56:39 +020076
77atexit.register(validate_tearDownClass)
78
Attila Fazekas53943322014-02-10 16:07:34 +010079
Matthew Treinish2474f412014-11-17 18:11:56 -050080class BaseTestCase(testtools.testcase.WithAttributes,
81 testtools.TestCase):
Andrea Frittolia5ddd552014-08-19 18:30:00 +010082 """The test base class defines Tempest framework for class level fixtures.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +000083
Andrea Frittolia5ddd552014-08-19 18:30:00 +010084 `setUpClass` and `tearDownClass` are defined here and cannot be overwritten
85 by subclasses (enforced via hacking rule T105).
86
87 Set-up is split in a series of steps (setup stages), which can be
88 overwritten by test classes. Set-up stages are:
89 - skip_checks
90 - setup_credentials
91 - setup_clients
92 - resource_setup
93
94 Tear-down is also split in a series of steps (teardown stages), which are
95 stacked for execution only if the corresponding setup stage had been
96 reached during the setup phase. Tear-down stages are:
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -070097 - clear_credentials (defined in the base test class)
Andrea Frittolia5ddd552014-08-19 18:30:00 +010098 - resource_cleanup
99 """
Attila Fazekasc43fec82013-04-09 23:17:52 +0200100
Attila Fazekasf86fa312013-07-30 19:56:39 +0200101 setUpClassCalled = False
102
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000103 # NOTE(andreaf) credentials holds a list of the credentials to be allocated
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100104 # at class setup time. Credential types can be 'primary', 'alt', 'admin' or
105 # a list of roles - the first element of the list being a label, and the
106 # rest the actual roles
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000107 credentials = []
nithya-ganesan222efd72015-01-22 12:20:27 +0000108 # Resources required to validate a server using ssh
109 validation_resources = {}
Matthew Treinish9f756a02014-01-15 10:26:07 -0500110 network_resources = {}
111
Sean Dague2ef32ac2014-06-09 11:32:23 -0400112 # NOTE(sdague): log_format is defined inline here instead of using the oslo
113 # default because going through the config path recouples config to the
114 # stress tests too early, and depending on testr order will fail unit tests
115 log_format = ('%(asctime)s %(process)d %(levelname)-8s '
116 '[%(name)s] %(message)s')
117
Ryota MIBU60687e52015-12-09 18:37:39 +0900118 # Client manager class to use in this test case.
119 client_manager = clients.Manager
120
Sean Dague02620fd2016-03-02 15:52:51 -0500121 # A way to adjust slow test classes
122 TIMEOUT_SCALING_FACTOR = 1
123
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200124 @classmethod
125 def setUpClass(cls):
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100126 # It should never be overridden by descendants
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200127 if hasattr(super(BaseTestCase, cls), 'setUpClass'):
128 super(BaseTestCase, cls).setUpClass()
Attila Fazekasf86fa312013-07-30 19:56:39 +0200129 cls.setUpClassCalled = True
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100130 # Stack of (name, callable) to be invoked in reverse order at teardown
131 cls.teardowns = []
132 # All the configuration checks that may generate a skip
133 cls.skip_checks()
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100134 try:
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100135 # Allocation of all required credentials and client managers
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700136 cls.teardowns.append(('credentials', cls.clear_credentials))
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100137 cls.setup_credentials()
138 # Shortcuts to clients
139 cls.setup_clients()
140 # Additional class-wide test resources
141 cls.teardowns.append(('resources', cls.resource_cleanup))
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100142 cls.resource_setup()
143 except Exception:
144 etype, value, trace = sys.exc_info()
Jordan Pittier525ec712016-12-07 17:51:26 +0100145 LOG.info("%s raised in %s.setUpClass. Invoking tearDownClass.",
146 etype, cls.__name__)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100147 cls.tearDownClass()
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100148 try:
Matthew Treinish843227d2015-04-23 10:17:17 -0400149 six.reraise(etype, value, trace)
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100150 finally:
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100151 del trace # to avoid circular refs
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200152
Attila Fazekasf86fa312013-07-30 19:56:39 +0200153 @classmethod
154 def tearDownClass(cls):
Martin Kopecae155b72017-06-26 09:41:21 +0000155 # insert pdb breakpoint when pause_teardown is enabled
156 if CONF.pause_teardown:
157 cls.insert_pdb_breakpoint()
Attila Fazekas5d275302013-08-29 12:35:12 +0200158 at_exit_set.discard(cls)
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100159 # It should never be overridden by descendants
Attila Fazekasf86fa312013-07-30 19:56:39 +0200160 if hasattr(super(BaseTestCase, cls), 'tearDownClass'):
161 super(BaseTestCase, cls).tearDownClass()
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100162 # Save any existing exception, we always want to re-raise the original
163 # exception only
164 etype, value, trace = sys.exc_info()
165 # If there was no exception during setup we shall re-raise the first
166 # exception in teardown
167 re_raise = (etype is None)
168 while cls.teardowns:
169 name, teardown = cls.teardowns.pop()
170 # Catch any exception in tearDown so we can re-raise the original
171 # exception at the end
172 try:
173 teardown()
174 except Exception as te:
175 sys_exec_info = sys.exc_info()
176 tetype = sys_exec_info[0]
177 # TODO(andreaf): Till we have the ability to cleanup only
178 # resources that were successfully setup in resource_cleanup,
179 # log AttributeError as info instead of exception.
180 if tetype is AttributeError and name == 'resources':
Jordan Pittier525ec712016-12-07 17:51:26 +0100181 LOG.info("tearDownClass of %s failed: %s", name, te)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100182 else:
Jordan Pittier525ec712016-12-07 17:51:26 +0100183 LOG.exception("teardown of %s failed: %s", name, te)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100184 if not etype:
185 etype, value, trace = sys_exec_info
Joshua Whitebd769602016-02-02 09:30:11 -0800186 # If exceptions were raised during teardown, and not before, re-raise
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100187 # the first one
188 if re_raise and etype is not None:
189 try:
Matthew Treinish843227d2015-04-23 10:17:17 -0400190 six.reraise(etype, value, trace)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100191 finally:
192 del trace # to avoid circular refs
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100193
Martin Kopecae155b72017-06-26 09:41:21 +0000194 def tearDown(self):
195 super(BaseTestCase, self).tearDown()
196 # insert pdb breakpoint when pause_teardown is enabled
197 if CONF.pause_teardown:
198 BaseTestCase.insert_pdb_breakpoint()
199
200 @classmethod
201 def insert_pdb_breakpoint(cls):
202 """Add pdb breakpoint.
203
204 This can help in debugging process, cleaning of resources is
205 paused, so they can be examined.
206 """
207 import pdb
208 pdb.set_trace()
209
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100210 @classmethod
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100211 def skip_checks(cls):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000212 """Class level skip checks.
213
214 Subclasses verify in here all conditions that might prevent the
215 execution of the entire test class.
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100216 Checks implemented here may not make use API calls, and should rely on
217 configuration alone.
218 In general skip checks that require an API call are discouraged.
219 If one is really needed it may be implemented either in the
220 resource_setup or at test level.
221 """
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100222 identity_version = cls.get_identity_version()
223 if 'admin' in cls.credentials and not credentials.is_admin_available(
224 identity_version=identity_version):
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000225 msg = "Missing Identity Admin API credentials in configuration."
226 raise cls.skipException(msg)
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100227 if 'alt' in cls.credentials and not credentials.is_alt_available(
228 identity_version=identity_version):
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000229 msg = "Missing a 2nd set of API credentials in configuration."
230 raise cls.skipException(msg)
Andrea Frittoli (andreaf)41601412015-05-12 16:39:03 +0100231 if hasattr(cls, 'identity_version'):
232 if cls.identity_version == 'v2':
233 if not CONF.identity_feature_enabled.api_v2:
234 raise cls.skipException("Identity api v2 is not enabled")
235 elif cls.identity_version == 'v3':
236 if not CONF.identity_feature_enabled.api_v3:
237 raise cls.skipException("Identity api v3 is not enabled")
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100238
239 @classmethod
240 def setup_credentials(cls):
edannon6cc6fbc2016-05-03 11:56:12 +0300241 """Allocate credentials and create the client managers from them.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000242
edannon6cc6fbc2016-05-03 11:56:12 +0300243 For every element of credentials param function creates tenant/user,
244 Then it creates client manager for that credential.
245
246 Network related tests must override this function with
247 set_network_resources() method, otherwise it will create
248 network resources(network resources are created in a later step).
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000249 """
250 for credentials_type in cls.credentials:
251 # This may raise an exception in case credentials are not available
252 # In that case we want to let the exception through and the test
253 # fail accordingly
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100254 if isinstance(credentials_type, six.string_types):
255 manager = cls.get_client_manager(
256 credential_type=credentials_type)
257 setattr(cls, 'os_%s' % credentials_type, manager)
Jordan Pittier8160d312017-04-18 11:52:23 +0200258 # NOTE(jordanP): Tempest should use os_primary, os_admin
259 # and os_alt throughout its code base but we keep the aliases
260 # around for a while for Tempest plugins. Aliases should be
261 # removed eventually.
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100262 # Setup some common aliases
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100263 if credentials_type == 'primary':
Jordan Pittier8160d312017-04-18 11:52:23 +0200264 cls.os = debtcollector.moves.moved_read_only_property(
265 'os', 'os_primary', version='Pike',
Jakub Libosvar7835ca12017-05-04 16:44:23 +0200266 removal_version='Queens')
Jordan Pittier8160d312017-04-18 11:52:23 +0200267 cls.manager =\
268 debtcollector.moves.moved_read_only_property(
269 'manager', 'os_primary', version='Pike',
Jakub Libosvar7835ca12017-05-04 16:44:23 +0200270 removal_version='Queens')
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100271 if credentials_type == 'admin':
Jordan Pittier8160d312017-04-18 11:52:23 +0200272 cls.os_adm = debtcollector.moves.moved_read_only_property(
273 'os_adm', 'os_admin', version='Pike',
Jakub Libosvar7835ca12017-05-04 16:44:23 +0200274 removal_version='Queens')
Jordan Pittier8160d312017-04-18 11:52:23 +0200275 cls.admin_manager =\
276 debtcollector.moves.moved_read_only_property(
277 'admin_manager', 'os_admin', version='Pike',
Jakub Libosvar7835ca12017-05-04 16:44:23 +0200278 removal_version='Queens')
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100279 if credentials_type == 'alt':
Jordan Pittier8160d312017-04-18 11:52:23 +0200280 cls.alt_manager =\
281 debtcollector.moves.moved_read_only_property(
282 'alt_manager', 'os_alt', version='Pike',
Jakub Libosvar7835ca12017-05-04 16:44:23 +0200283 removal_version='Queens')
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100284 elif isinstance(credentials_type, list):
285 manager = cls.get_client_manager(roles=credentials_type[1:],
286 force_new=True)
287 setattr(cls, 'os_roles_%s' % credentials_type[0], manager)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100288
289 @classmethod
290 def setup_clients(cls):
291 """Create links to the clients into the test object."""
292 # TODO(andreaf) There is a fair amount of code that could me moved from
293 # base / test classes in here. Ideally tests should be able to only
294 # specify which client is `client` and nothing else.
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100295 pass
Attila Fazekasf86fa312013-07-30 19:56:39 +0200296
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000297 @classmethod
298 def resource_setup(cls):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000299 """Class level resource setup for test cases."""
Andrea Frittoli1fa7a602017-08-09 16:28:55 +0100300 if (CONF.validation.ip_version_for_ssh not in (4, 6) and
301 CONF.service_available.neutron):
302 msg = "Invalid IP version %s in ip_version_for_ssh. Use 4 or 6"
303 raise lib_exc.InvalidConfiguration(
304 msg % CONF.validation.ip_version_for_ssh)
Andrea Frittolicf999a82017-05-24 10:44:46 +0100305 if hasattr(cls, "os_primary"):
Andrea Frittoli8871fca2017-08-10 23:43:25 +0100306 vr = cls.validation_resources
nithya-ganesan222efd72015-01-22 12:20:27 +0000307 cls.validation_resources = vresources.create_validation_resources(
Andrea Frittoli8871fca2017-08-10 23:43:25 +0100308 cls.os_primary,
Andrea Frittoli1fa7a602017-08-09 16:28:55 +0100309 use_neutron=CONF.service_available.neutron,
310 ethertype='IPv' + str(CONF.validation.ip_version_for_ssh),
311 floating_network_id=CONF.network.public_network_id,
Andrea Frittoli8871fca2017-08-10 23:43:25 +0100312 floating_network_name=CONF.network.floating_network_name,
313 **vr)
nithya-ganesan222efd72015-01-22 12:20:27 +0000314 else:
zhangguoqing6c096642016-01-04 06:17:21 +0000315 LOG.warning("Client manager not found, validation resources not"
316 " created")
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000317
318 @classmethod
319 def resource_cleanup(cls):
320 """Class level resource cleanup for test cases.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000321
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000322 Resource cleanup must be able to handle the case of partially setup
323 resources, in case a failure during `resource_setup` should happen.
324 """
nithya-ganesan222efd72015-01-22 12:20:27 +0000325 if cls.validation_resources:
Andrea Frittolicf999a82017-05-24 10:44:46 +0100326 if hasattr(cls, "os_primary"):
Andrea Frittoli8871fca2017-08-10 23:43:25 +0100327 vr = cls.validation_resources
Andrea Frittoli463a8a62017-08-09 16:55:33 +0100328 vresources.clear_validation_resources(
Andrea Frittoli8871fca2017-08-10 23:43:25 +0100329 cls.os_primary,
330 use_neutron=CONF.service_available.neutron, **vr)
nithya-ganesan222efd72015-01-22 12:20:27 +0000331 cls.validation_resources = {}
332 else:
zhangguoqing6c096642016-01-04 06:17:21 +0000333 LOG.warning("Client manager not found, validation resources "
334 "not deleted")
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000335
Attila Fazekasf86fa312013-07-30 19:56:39 +0200336 def setUp(self):
337 super(BaseTestCase, self).setUp()
338 if not self.setUpClassCalled:
339 raise RuntimeError("setUpClass does not calls the super's"
340 "setUpClass in the "
341 + self.__class__.__name__)
342 at_exit_set.add(self.__class__)
Matthew Treinish78561ad2013-07-26 11:41:56 -0400343 test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
344 try:
Sean Dague02620fd2016-03-02 15:52:51 -0500345 test_timeout = int(test_timeout) * self.TIMEOUT_SCALING_FACTOR
Matthew Treinish78561ad2013-07-26 11:41:56 -0400346 except ValueError:
347 test_timeout = 0
348 if test_timeout > 0:
Attila Fazekasf86fa312013-07-30 19:56:39 +0200349 self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400350
351 if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or
352 os.environ.get('OS_STDOUT_CAPTURE') == '1'):
Attila Fazekasf86fa312013-07-30 19:56:39 +0200353 stdout = self.useFixture(fixtures.StringStream('stdout')).stream
354 self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400355 if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or
356 os.environ.get('OS_STDERR_CAPTURE') == '1'):
Attila Fazekasf86fa312013-07-30 19:56:39 +0200357 stderr = self.useFixture(fixtures.StringStream('stderr')).stream
358 self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
Attila Fazekas31388072013-08-15 08:58:07 +0200359 if (os.environ.get('OS_LOG_CAPTURE') != 'False' and
360 os.environ.get('OS_LOG_CAPTURE') != '0'):
Attila Fazekas31388072013-08-15 08:58:07 +0200361 self.useFixture(fixtures.LoggerFixture(nuke_handlers=False,
Sean Dague2ef32ac2014-06-09 11:32:23 -0400362 format=self.log_format,
Attila Fazekas90445be2013-10-24 16:46:03 +0200363 level=None))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400364
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100365 @property
366 def credentials_provider(self):
367 return self._get_credentials_provider()
368
Jamie Lennox15350172015-08-17 10:54:25 +1000369 @property
370 def identity_utils(self):
371 """A client that abstracts v2 and v3 identity operations.
372
373 This can be used for creating and tearing down projects in tests. It
374 should not be used for testing identity features.
375 """
376 if CONF.identity.auth_version == 'v2':
377 client = self.os_admin.identity_client
Daniel Mellado7aea5342016-02-09 09:10:12 +0000378 users_client = self.os_admin.users_client
Daniel Melladob04da902015-11-20 17:43:12 +0100379 project_client = self.os_admin.tenants_client
Daniel Mellado6b16b922015-12-07 12:43:08 +0000380 roles_client = self.os_admin.roles_client
Daniel Mellado91a26b62016-02-11 11:13:04 +0000381 domains_client = None
Jamie Lennox15350172015-08-17 10:54:25 +1000382 else:
383 client = self.os_admin.identity_v3_client
Daniel Mellado7aea5342016-02-09 09:10:12 +0000384 users_client = self.os_admin.users_v3_client
Arx Cruz24bcb882016-02-10 15:20:16 +0100385 project_client = self.os_admin.projects_client
386 roles_client = self.os_admin.roles_v3_client
Daniel Mellado91a26b62016-02-11 11:13:04 +0000387 domains_client = self.os_admin.domains_client
Jamie Lennox15350172015-08-17 10:54:25 +1000388
389 try:
390 domain = client.auth_provider.credentials.project_domain_name
391 except AttributeError:
392 domain = 'Default'
393
Daniel Melladob04da902015-11-20 17:43:12 +0100394 return cred_client.get_creds_client(client, project_client,
Daniel Mellado82c83a52015-12-09 15:16:49 +0000395 users_client,
Daniel Mellado7aea5342016-02-09 09:10:12 +0000396 roles_client,
Daniel Mellado91a26b62016-02-11 11:13:04 +0000397 domains_client,
Daniel Melladob04da902015-11-20 17:43:12 +0100398 project_domain_name=domain)
Jamie Lennox15350172015-08-17 10:54:25 +1000399
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100400 @classmethod
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100401 def get_identity_version(cls):
402 """Returns the identity version used by the test class"""
403 identity_version = getattr(cls, 'identity_version', None)
404 return identity_version or CONF.identity.auth_version
405
406 @classmethod
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100407 def _get_credentials_provider(cls):
408 """Returns a credentials provider
409
410 If no credential provider exists yet creates one.
Andrea Frittoli9e01dbb2017-04-20 15:28:30 +0100411 It always use the configuration value from identity.auth_version,
412 since we always want to provision accounts with the current version
413 of the identity API.
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100414 """
415 if (not hasattr(cls, '_creds_provider') or not cls._creds_provider or
416 not cls._creds_provider.name == cls.__name__):
417 force_tenant_isolation = getattr(cls, 'force_tenant_isolation',
418 False)
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100419
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700420 cls._creds_provider = credentials.get_credentials_provider(
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100421 name=cls.__name__, network_resources=cls.network_resources,
Andrea Frittoli9e01dbb2017-04-20 15:28:30 +0100422 force_tenant_isolation=force_tenant_isolation)
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100423 return cls._creds_provider
424
Matthew Treinish3e046852013-07-23 16:00:24 -0400425 @classmethod
Andrea Frittoli (andreaf)41601412015-05-12 16:39:03 +0100426 def get_client_manager(cls, credential_type=None, roles=None,
427 force_new=None):
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100428 """Returns an OpenStack client manager
429
430 Returns an OpenStack client manager based on either credential_type
431 or a list of roles. If neither is specified, it defaults to
432 credential_type 'primary'
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100433 :param credential_type: string - primary, alt or admin
434 :param roles: list of roles
435
lei zhangdd552b22015-11-25 20:41:48 +0800436 :returns: the created client manager
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100437 :raises skipException: if the requested credentials are not available
Ryan Hsu6c4bb3d2013-10-21 21:22:50 -0700438 """
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100439 if all([roles, credential_type]):
440 msg = "Cannot get credentials by type and roles at the same time"
441 raise ValueError(msg)
442 if not any([roles, credential_type]):
443 credential_type = 'primary'
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100444 cred_provider = cls._get_credentials_provider()
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100445 if roles:
446 for role in roles:
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100447 if not cred_provider.is_role_available(role):
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100448 skip_msg = (
449 "%s skipped because the configured credential provider"
450 " is not able to provide credentials with the %s role "
451 "assigned." % (cls.__name__, role))
452 raise cls.skipException(skip_msg)
453 params = dict(roles=roles)
454 if force_new is not None:
455 params.update(force_new=force_new)
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100456 creds = cred_provider.get_creds_by_roles(**params)
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000457 else:
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100458 credentials_method = 'get_%s_creds' % credential_type
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100459 if hasattr(cred_provider, credentials_method):
460 creds = getattr(cred_provider, credentials_method)()
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100461 else:
Andrea Frittoli (andreaf)af4f7cf2016-06-13 15:12:26 +0100462 raise lib_exc.InvalidCredentials(
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100463 "Invalid credentials type %s" % credential_type)
Jordan Pittiere4be9072017-01-04 19:17:35 +0100464 manager = cls.client_manager(credentials=creds.credentials)
Andrea Frittoli73224672016-12-09 21:08:19 +0000465 # NOTE(andreaf) Ensure credentials have user and project id fields.
466 # It may not be the case when using pre-provisioned credentials.
467 manager.auth_provider.set_auth()
468 return manager
Ryan Hsu6c4bb3d2013-10-21 21:22:50 -0700469
470 @classmethod
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700471 def clear_credentials(cls):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000472 """Clears creds if set"""
Attila Fazekas5b0d9262015-05-20 10:17:39 +0200473 if hasattr(cls, '_creds_provider'):
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700474 cls._creds_provider.clear_creds()
Ryan Hsu6c4bb3d2013-10-21 21:22:50 -0700475
476 @classmethod
nithya-ganesan222efd72015-01-22 12:20:27 +0000477 def set_validation_resources(cls, keypair=None, floating_ip=None,
478 security_group=None,
479 security_group_rules=None):
480 """Specify which ssh server validation resources should be created.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000481
nithya-ganesan222efd72015-01-22 12:20:27 +0000482 Each of the argument must be set to either None, True or False, with
483 None - use default from config (security groups and security group
484 rules get created when set to None)
485 False - Do not create the validation resource
486 True - create the validation resource
487
488 @param keypair
489 @param security_group
490 @param security_group_rules
491 @param floating_ip
492 """
Matthew Treinishe5cca002015-05-11 15:36:50 -0400493 if not CONF.validation.run_validation:
494 return
Jordan Pittier79cd1822016-12-08 17:20:35 +0100495
nithya-ganesan222efd72015-01-22 12:20:27 +0000496 if keypair is None:
Jordan Pittier79cd1822016-12-08 17:20:35 +0100497 keypair = (CONF.validation.auth_method.lower() == "keypair")
498
nithya-ganesan222efd72015-01-22 12:20:27 +0000499 if floating_ip is None:
Jordan Pittier79cd1822016-12-08 17:20:35 +0100500 floating_ip = (CONF.validation.connect_method.lower() ==
501 "floating")
502
nithya-ganesan222efd72015-01-22 12:20:27 +0000503 if security_group is None:
Brandon Palmc6cc91d2015-08-19 13:20:21 -0500504 security_group = CONF.validation.security_group
Jordan Pittier79cd1822016-12-08 17:20:35 +0100505
nithya-ganesan222efd72015-01-22 12:20:27 +0000506 if security_group_rules is None:
Brandon Palmc6cc91d2015-08-19 13:20:21 -0500507 security_group_rules = CONF.validation.security_group_rules
508
nithya-ganesan222efd72015-01-22 12:20:27 +0000509 if not cls.validation_resources:
510 cls.validation_resources = {
511 'keypair': keypair,
512 'security_group': security_group,
513 'security_group_rules': security_group_rules,
514 'floating_ip': floating_ip}
515
516 @classmethod
Andrea Frittoli7d5ed592015-02-10 01:10:23 +0000517 def set_network_resources(cls, network=False, router=False, subnet=False,
Matthew Treinish9f756a02014-01-15 10:26:07 -0500518 dhcp=False):
519 """Specify which network resources should be created
520
521 @param network
522 @param router
523 @param subnet
524 @param dhcp
525 """
Salvatore Orlando5a337242014-01-15 22:49:22 +0000526 # network resources should be set only once from callers
527 # in order to ensure that even if it's called multiple times in
528 # a chain of overloaded methods, the attribute is set only
529 # in the leaf class
Andrea Frittoli7d5ed592015-02-10 01:10:23 +0000530 if not cls.network_resources:
531 cls.network_resources = {
Salvatore Orlando5a337242014-01-15 22:49:22 +0000532 'network': network,
533 'router': router,
534 'subnet': subnet,
535 'dhcp': dhcp}
Matthew Treinish9f756a02014-01-15 10:26:07 -0500536
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530537 @classmethod
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000538 def get_tenant_network(cls, credentials_type='primary'):
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530539 """Get the network to be used in testing
540
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000541 :param credentials_type: The type of credentials for which to get the
542 tenant network
543
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530544 :return: network dict including 'id' and 'name'
545 """
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000546 # Get a manager for the given credentials_type, but at least
547 # always fall back on getting the manager for primary credentials
548 if isinstance(credentials_type, six.string_types):
549 manager = cls.get_client_manager(credential_type=credentials_type)
550 elif isinstance(credentials_type, list):
551 manager = cls.get_client_manager(roles=credentials_type[1:])
552 else:
553 manager = cls.get_client_manager()
554
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700555 # Make sure cred_provider exists and get a network client
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000556 networks_client = manager.compute_networks_client
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100557 cred_provider = cls._get_credentials_provider()
Andrea Frittoli700711e2015-04-02 11:39:38 +0100558 # In case of nova network, isolated tenants are not able to list the
Joshua Whitebd769602016-02-02 09:30:11 -0800559 # network configured in fixed_network_name, even if they can use it
Andrea Frittoli700711e2015-04-02 11:39:38 +0100560 # for their servers, so using an admin network client to validate
561 # the network name
562 if (not CONF.service_available.neutron and
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100563 credentials.is_admin_available(
564 identity_version=cls.get_identity_version())):
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100565 admin_creds = cred_provider.get_admin_creds()
Andrea Frittoli (andreaf)848c4a12016-06-09 11:09:02 +0100566 admin_manager = clients.Manager(admin_creds.credentials)
John Warren9487a182015-09-14 18:12:56 -0400567 networks_client = admin_manager.compute_networks_client
Andrea Frittoli (andreaf)940f8c62015-10-30 16:39:24 +0900568 return fixed_network.get_tenant_network(
569 cred_provider, networks_client, CONF.compute.fixed_network_name)
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530570
Andrea Frittoli71c71e92017-04-07 17:45:21 +0100571 def assertEmpty(self, items, msg=None):
572 """Asserts whether a sequence or collection is empty
Mark Maglana5885eb32014-02-28 10:57:34 -0800573
Andrea Frittoli71c71e92017-04-07 17:45:21 +0100574 :param items: sequence or collection to be tested
575 :param msg: message to be passed to the AssertionError
576 :raises AssertionError: when items is not empty
577 """
zhufl92ade4b2017-03-03 15:20:10 +0800578 if msg is None:
Andrea Frittoli71c71e92017-04-07 17:45:21 +0100579 msg = "sequence or collection is not empty: %s" % items
Masayuki Igawa0c0f0142017-04-10 17:22:02 +0900580 self.assertFalse(items, msg)
Andrea Frittoli71c71e92017-04-07 17:45:21 +0100581
582 def assertNotEmpty(self, items, msg=None):
583 """Asserts whether a sequence or collection is not empty
584
585 :param items: sequence or collection to be tested
586 :param msg: message to be passed to the AssertionError
587 :raises AssertionError: when items is empty
588 """
589 if msg is None:
590 msg = "sequence or collection is empty."
Masayuki Igawa0c0f0142017-04-10 17:22:02 +0900591 self.assertTrue(items, msg)