3 # Copyright (c) 2015 All rights reserved
4 # This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
8 # http://www.apache.org/licenses/LICENSE-2.0
11 from __future__ import division
23 from functest.core import testcase
24 from functest.opnfv_tests.openstack.snaps import snaps_utils
25 from functest.opnfv_tests.openstack.tempest import conf_utils
26 from functest.utils.constants import CONST
27 import functest.utils.functest_utils as ft_utils
29 from snaps.config.flavor import FlavorConfig
30 from snaps.config.network import NetworkConfig, SubnetConfig
31 from snaps.config.project import ProjectConfig
32 from snaps.config.user import UserConfig
34 from snaps.openstack import create_flavor
35 from snaps.openstack.create_flavor import OpenStackFlavor
36 from snaps.openstack.tests import openstack_tests
37 from snaps.openstack.utils import deploy_utils
40 """ logging configuration """
41 logger = logging.getLogger(__name__)
44 class TempestCommon(testcase.TestCase):
46 def __init__(self, **kwargs):
47 super(TempestCommon, self).__init__(**kwargs)
48 self.resources = TempestResourcesManager(**kwargs)
51 self.VERIFIER_ID = conf_utils.get_verifier_id()
52 self.VERIFIER_REPO_DIR = conf_utils.get_verifier_repo_dir(
54 self.DEPLOYMENT_ID = conf_utils.get_verifier_deployment_id()
55 self.DEPLOYMENT_DIR = conf_utils.get_verifier_deployment_dir(
56 self.VERIFIER_ID, self.DEPLOYMENT_ID)
57 self.VERIFICATION_ID = None
60 def read_file(filename):
61 with open(filename) as src:
62 return [line.strip() for line in src.readlines()]
64 def generate_test_list(self, verifier_repo_dir):
65 logger.debug("Generating test case list...")
66 if self.MODE == 'defcore':
68 conf_utils.TEMPEST_DEFCORE, conf_utils.TEMPEST_RAW_LIST)
69 elif self.MODE == 'custom':
70 if os.path.isfile(conf_utils.TEMPEST_CUSTOM):
72 conf_utils.TEMPEST_CUSTOM, conf_utils.TEMPEST_RAW_LIST)
74 raise Exception("Tempest test list file %s NOT found."
75 % conf_utils.TEMPEST_CUSTOM)
77 if self.MODE == 'smoke':
79 elif self.MODE == 'full':
82 testr_mode = 'tempest.api.' + self.MODE
84 "testr list-tests {1} > {2};"
85 "cd -;".format(verifier_repo_dir,
87 conf_utils.TEMPEST_RAW_LIST))
88 ft_utils.execute_command(cmd)
90 def apply_tempest_blacklist(self):
91 logger.debug("Applying tempest blacklist...")
92 cases_file = self.read_file(conf_utils.TEMPEST_RAW_LIST)
93 result_file = open(conf_utils.TEMPEST_LIST, 'w')
96 installer_type = CONST.__getattribute__('INSTALLER_TYPE')
97 deploy_scenario = CONST.__getattribute__('DEPLOY_SCENARIO')
98 if (bool(installer_type) * bool(deploy_scenario)):
99 # if INSTALLER_TYPE and DEPLOY_SCENARIO are set we read the
101 black_list_file = open(conf_utils.TEMPEST_BLACKLIST)
102 black_list_yaml = yaml.safe_load(black_list_file)
103 black_list_file.close()
104 for item in black_list_yaml:
105 scenarios = item['scenarios']
106 installers = item['installers']
107 if (deploy_scenario in scenarios and
108 installer_type in installers):
109 tests = item['tests']
111 black_tests.append(test)
115 logger.debug("Tempest blacklist file does not exist.")
117 for cases_line in cases_file:
118 for black_tests_line in black_tests:
119 if black_tests_line in cases_line:
122 result_file.write(str(cases_line) + '\n')
125 def run_verifier_tests(self):
126 self.OPTION += (" --load-list {} --detailed"
127 .format(conf_utils.TEMPEST_LIST))
129 cmd_line = "rally verify start " + self.OPTION
130 logger.info("Starting Tempest test suite: '%s'." % cmd_line)
132 header = ("Tempest environment:\n"
133 " SUT: %s\n Scenario: %s\n Node: %s\n Date: %s\n" %
134 (CONST.__getattribute__('INSTALLER_TYPE'),
135 CONST.__getattribute__('DEPLOY_SCENARIO'),
136 CONST.__getattribute__('NODE_NAME'),
137 time.strftime("%a %b %d %H:%M:%S %Z %Y")))
140 os.path.join(conf_utils.TEMPEST_RESULTS_DIR, "tempest.log"), 'w+')
142 os.path.join(conf_utils.TEMPEST_RESULTS_DIR,
143 "tempest-error.log"), 'w+')
144 f_env = open(os.path.join(conf_utils.TEMPEST_RESULTS_DIR,
145 "environment.log"), 'w+')
148 p = subprocess.Popen(
149 cmd_line, shell=True,
150 stdout=subprocess.PIPE,
155 for line in iter(p.stdout.readline, b''):
156 if re.search("\} tempest\.", line):
157 logger.info(line.replace('\n', ''))
158 elif re.search('Starting verification', line):
159 logger.info(line.replace('\n', ''))
160 first_pos = line.index("UUID=") + len("UUID=")
161 last_pos = line.index(") for deployment")
162 self.VERIFICATION_ID = line[first_pos:last_pos]
163 logger.debug('Verification UUID: %s', self.VERIFICATION_ID)
171 def parse_verifier_result(self):
172 if self.VERIFICATION_ID is None:
173 raise Exception('Verification UUID not found')
175 cmd_line = "rally verify show --uuid {}".format(self.VERIFICATION_ID)
176 logger.info("Showing result for a verification: '%s'." % cmd_line)
177 p = subprocess.Popen(cmd_line,
179 stdout=subprocess.PIPE,
180 stderr=subprocess.STDOUT)
181 for line in p.stdout:
182 new_line = line.replace(' ', '').split('|')
183 if 'Tests' in new_line:
187 if 'Testscount' in new_line:
188 num_tests = new_line[2]
189 elif 'Success' in new_line:
190 num_success = new_line[2]
191 elif 'Skipped' in new_line:
192 num_skipped = new_line[2]
193 elif 'Failures' in new_line:
194 num_failures = new_line[2]
197 num_executed = int(num_tests) - int(num_skipped)
199 self.result = 100 * int(num_success) / int(num_executed)
200 except ZeroDivisionError:
202 if int(num_tests) > 0:
203 logger.info("All tests have been skipped")
205 logger.error("No test has been executed")
208 with open(os.path.join(conf_utils.TEMPEST_RESULTS_DIR,
209 "tempest.log"), 'r') as logfile:
210 output = logfile.read()
212 success_testcases = []
213 for match in re.findall('.*\{0\} (.*?)[. ]*success ', output):
214 success_testcases.append(match)
215 failed_testcases = []
216 for match in re.findall('.*\{0\} (.*?)[. ]*fail ', output):
217 failed_testcases.append(match)
218 skipped_testcases = []
219 for match in re.findall('.*\{0\} (.*?)[. ]*skip:', output):
220 skipped_testcases.append(match)
222 self.details = {"tests": int(num_tests),
223 "failures": int(num_failures),
224 "success": success_testcases,
225 "errors": failed_testcases,
226 "skipped": skipped_testcases}
230 logger.info("Tempest %s success_rate is %s%%"
231 % (self.case_name, self.result))
235 self.start_time = time.time()
237 if not os.path.exists(conf_utils.TEMPEST_RESULTS_DIR):
238 os.makedirs(conf_utils.TEMPEST_RESULTS_DIR)
239 resources = self.resources.create()
240 compute_cnt = snaps_utils.get_active_compute_cnt(
241 self.resources.os_creds)
242 conf_utils.configure_tempest(
244 image_id=resources.get("image_id"),
245 flavor_id=resources.get("flavor_id"),
246 compute_cnt=compute_cnt)
247 self.generate_test_list(self.VERIFIER_REPO_DIR)
248 self.apply_tempest_blacklist()
249 self.run_verifier_tests()
250 self.parse_verifier_result()
251 res = testcase.TestCase.EX_OK
252 except Exception as e:
253 logger.error('Error with run: %s' % e)
254 res = testcase.TestCase.EX_RUN_ERROR
256 self.resources.cleanup()
258 self.stop_time = time.time()
262 class TempestSmokeSerial(TempestCommon):
264 def __init__(self, **kwargs):
265 if "case_name" not in kwargs:
266 kwargs["case_name"] = 'tempest_smoke_serial'
267 TempestCommon.__init__(self, **kwargs)
269 self.OPTION = "--concurrency 1"
272 class TempestSmokeParallel(TempestCommon):
274 def __init__(self, **kwargs):
275 if "case_name" not in kwargs:
276 kwargs["case_name"] = 'tempest_smoke_parallel'
277 TempestCommon.__init__(self, **kwargs)
282 class TempestFullParallel(TempestCommon):
284 def __init__(self, **kwargs):
285 if "case_name" not in kwargs:
286 kwargs["case_name"] = 'tempest_full_parallel'
287 TempestCommon.__init__(self, **kwargs)
291 class TempestCustom(TempestCommon):
293 def __init__(self, **kwargs):
294 if "case_name" not in kwargs:
295 kwargs["case_name"] = 'tempest_custom'
296 TempestCommon.__init__(self, **kwargs)
298 self.OPTION = "--concurrency 1"
301 class TempestDefcore(TempestCommon):
303 def __init__(self, **kwargs):
304 if "case_name" not in kwargs:
305 kwargs["case_name"] = 'tempest_defcore'
306 TempestCommon.__init__(self, **kwargs)
307 self.MODE = "defcore"
308 self.OPTION = "--concurrency 1"
311 class TempestResourcesManager(object):
313 def __init__(self, **kwargs):
315 if 'os_creds' in kwargs:
316 self.os_creds = kwargs['os_creds']
318 self.os_creds = openstack_tests.get_credentials(
319 os_env_file=CONST.__getattribute__('openstack_creds'))
321 self.guid = '-' + str(uuid.uuid4())
323 self.creators = list()
325 if hasattr(CONST, 'snaps_images_cirros'):
326 self.cirros_image_config = CONST.__getattribute__(
327 'snaps_images_cirros')
329 self.cirros_image_config = None
331 def create(self, use_custom_images=False, use_custom_flavors=False,
332 create_project=False):
334 logger.debug("Creating project (tenant) for Tempest suite")
335 project_name = CONST.__getattribute__(
336 'tempest_identity_tenant_name') + self.guid
337 project_creator = deploy_utils.create_project(
338 self.os_creds, ProjectConfig(
340 description=CONST.__getattribute__(
341 'tempest_identity_tenant_description')))
342 if (project_creator is None or
343 project_creator.get_project() is None):
344 raise Exception("Failed to create tenant")
345 project_id = project_creator.get_project().id
346 self.creators.append(project_creator)
348 logger.debug("Creating user for Tempest suite")
349 user_creator = deploy_utils.create_user(
350 self.os_creds, UserConfig(
351 name=CONST.__getattribute__(
352 'tempest_identity_user_name') + self.guid,
353 password=CONST.__getattribute__(
354 'tempest_identity_user_password'),
355 project_name=project_name))
356 if user_creator is None or user_creator.get_user() is None:
357 raise Exception("Failed to create user")
358 user_id = user_creator.get_user().id
359 self.creators.append(user_creator)
365 logger.debug("Creating private network for Tempest suite")
366 network_creator = deploy_utils.create_network(
367 self.os_creds, NetworkConfig(
368 name=CONST.__getattribute__(
369 'tempest_private_net_name') + self.guid,
370 project_name=project_name,
371 subnet_settings=[SubnetConfig(
372 name=CONST.__getattribute__(
373 'tempest_private_subnet_name') + self.guid,
374 cidr=CONST.__getattribute__('tempest_private_subnet_cidr'))
376 if network_creator is None or network_creator.get_network() is None:
377 raise Exception("Failed to create private network")
378 self.creators.append(network_creator)
385 logger.debug("Creating image for Tempest suite")
386 image_base_name = CONST.__getattribute__(
387 'openstack_image_name') + self.guid
388 os_image_settings = openstack_tests.cirros_image_settings(
389 image_base_name, public=True,
390 image_metadata=self.cirros_image_config)
391 logger.debug("Creating image for Tempest suite")
392 image_creator = deploy_utils.create_image(
393 self.os_creds, os_image_settings)
394 if image_creator is None:
395 raise Exception('Failed to create image')
396 self.creators.append(image_creator)
397 image_id = image_creator.get_image().id
399 if use_custom_images:
400 logger.debug("Creating 2nd image for Tempest suite")
401 image_base_name_alt = CONST.__getattribute__(
402 'openstack_image_name_alt') + self.guid
403 os_image_settings_alt = openstack_tests.cirros_image_settings(
404 image_base_name_alt, public=True,
405 image_metadata=self.cirros_image_config)
406 logger.debug("Creating 2nd image for Tempest suite")
407 image_creator_alt = deploy_utils.create_image(
408 self.os_creds, os_image_settings_alt)
409 if image_creator_alt is None:
410 raise Exception('Failed to create image')
411 self.creators.append(image_creator_alt)
412 image_id_alt = image_creator_alt.get_image().id
414 if (CONST.__getattribute__('tempest_use_custom_flavors') == 'True' or
416 logger.info("Creating flavor for Tempest suite")
417 scenario = CONST.__getattribute__('DEPLOY_SCENARIO')
418 flavor_metadata = None
419 if 'ovs' in scenario or 'fdio' in scenario:
420 flavor_metadata = create_flavor.MEM_PAGE_SIZE_LARGE
421 flavor_creator = OpenStackFlavor(
422 self.os_creds, FlavorConfig(
423 name=CONST.__getattribute__(
424 'openstack_flavor_name') + self.guid,
425 ram=CONST.__getattribute__('openstack_flavor_ram'),
426 disk=CONST.__getattribute__('openstack_flavor_disk'),
427 vcpus=CONST.__getattribute__('openstack_flavor_vcpus'),
428 metadata=flavor_metadata))
429 flavor = flavor_creator.create()
431 raise Exception('Failed to create flavor')
432 self.creators.append(flavor_creator)
433 flavor_id = flavor.id
435 if use_custom_flavors:
436 logger.info("Creating 2nd flavor for Tempest suite")
437 scenario = CONST.__getattribute__('DEPLOY_SCENARIO')
438 flavor_metadata_alt = None
439 if 'ovs' in scenario or 'fdio' in scenario:
440 flavor_metadata_alt = create_flavor.MEM_PAGE_SIZE_LARGE
441 CONST.__setattr__('openstack_flavor_ram', 1024)
442 flavor_creator_alt = OpenStackFlavor(
443 self.os_creds, FlavorConfig(
444 name=CONST.__getattribute__(
445 'openstack_flavor_name_alt') + self.guid,
446 ram=CONST.__getattribute__('openstack_flavor_ram'),
447 disk=CONST.__getattribute__('openstack_flavor_disk'),
448 vcpus=CONST.__getattribute__('openstack_flavor_vcpus'),
449 metadata=flavor_metadata_alt))
450 flavor_alt = flavor_creator_alt.create()
451 if flavor_alt is None:
452 raise Exception('Failed to create flavor')
453 self.creators.append(flavor_creator_alt)
454 flavor_id_alt = flavor_alt.id
456 print("RESOURCES CREATE: image_id: %s, image_id_alt: %s, "
457 "flavor_id: %s, flavor_id_alt: %s" % (
458 image_id, image_id_alt, flavor_id, flavor_id_alt,))
461 'image_id': image_id,
462 'image_id_alt': image_id_alt,
463 'flavor_id': flavor_id,
464 'flavor_id_alt': flavor_id_alt
468 result['project_id'] = project_id
469 result['tenant_id'] = project_id # for compatibility
470 result['user_id'] = user_id
476 Cleanup all OpenStack objects. Should be called on completion.
478 for creator in reversed(self.creators):
481 except Exception as e:
482 logger.error('Unexpected error cleaning - %s', e)