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 """Rally testcases implementation."""
13 from __future__ import division
14 from __future__ import print_function
27 from ruamel.yaml import YAML
28 from six.moves import configparser
29 from xtesting.core import testcase
32 from functest.core import singlevm
33 from functest.utils import config
34 from functest.utils import env
36 LOGGER = logging.getLogger(__name__)
39 class RallyBase(singlevm.VmReady2):
40 """Base class form Rally testcases implementation."""
42 # pylint: disable=too-many-instance-attributes, too-many-public-methods
43 stests = ['authenticate', 'glance', 'cinder', 'gnocchi', 'heat',
44 'keystone', 'neutron', 'nova', 'quotas', 'swift', 'barbican']
46 rally_conf_path = "/etc/rally/rally.conf"
47 rally_aar4_patch_path = pkg_resources.resource_filename(
48 'functest', 'ci/rally_aarch64_patch.conf')
49 rally_dir = pkg_resources.resource_filename(
50 'functest', 'opnfv_tests/openstack/rally')
51 rally_scenario_dir = pkg_resources.resource_filename(
52 'functest', 'opnfv_tests/openstack/rally/scenario')
53 template_dir = pkg_resources.resource_filename(
54 'functest', 'opnfv_tests/openstack/rally/scenario/templates')
55 support_dir = pkg_resources.resource_filename(
56 'functest', 'opnfv_tests/openstack/rally/scenario/support')
59 iterations_amount = 10
62 volume_service_type = "volumev3"
63 blacklist_file = os.path.join(rally_dir, "blacklist.yaml")
64 task_dir = os.path.join(getattr(config.CONF, 'dir_rally_data'), 'task')
65 temp_dir = os.path.join(task_dir, 'var')
71 def __init__(self, **kwargs):
72 """Initialize RallyBase object."""
73 super(RallyBase, self).__init__(**kwargs)
74 assert self.orig_cloud
76 if self.orig_cloud.get_role("admin"):
78 elif self.orig_cloud.get_role("Admin"):
81 raise Exception("Cannot detect neither admin nor Admin")
82 self.orig_cloud.grant_role(
83 role_name, user=self.project.user.id,
84 project=self.project.project.id,
85 domain=self.project.domain.id)
86 self.results_dir = os.path.join(
87 getattr(config.CONF, 'dir_results'), self.case_name)
91 self.scenario_dir = ''
93 self.start_time = None
97 self.flavor_alt = None
100 self.network_extensions = []
103 def build_task_args(self, test_name):
104 """Build arguments for the Rally task."""
105 task_args = {'service_list': [test_name]}
106 task_args['image_name'] = str(self.image.name)
107 task_args['flavor_name'] = str(self.flavor.name)
108 task_args['flavor_alt_name'] = str(self.flavor_alt.name)
109 task_args['glance_image_location'] = str(self.filename)
110 task_args['glance_image_format'] = str(self.image_format)
111 task_args['tmpl_dir'] = str(self.template_dir)
112 task_args['sup_dir'] = str(self.support_dir)
113 task_args['users_amount'] = self.users_amount
114 task_args['tenants_amount'] = self.tenants_amount
115 task_args['use_existing_users'] = False
116 task_args['iterations'] = self.iterations_amount
117 task_args['concurrency'] = self.concurrency
118 task_args['smoke'] = self.smoke
119 task_args['volume_version'] = self.volume_version
120 task_args['volume_service_type'] = self.volume_service_type
121 task_args['block_migration'] = env.get("BLOCK_MIGRATION").lower()
124 task_args['floating_network'] = str(self.ext_net.name)
126 task_args['floating_network'] = ''
129 task_args['netid'] = str(self.network.id)
131 task_args['netid'] = ''
135 def _prepare_test_list(self, test_name):
136 """Build the list of test cases to be executed."""
137 test_yaml_file_name = 'opnfv-{}.yaml'.format(test_name)
138 scenario_file_name = os.path.join(self.rally_scenario_dir,
141 if not os.path.exists(scenario_file_name):
142 scenario_file_name = os.path.join(self.scenario_dir,
145 if not os.path.exists(scenario_file_name):
146 raise Exception("The scenario '%s' does not exist."
147 % scenario_file_name)
149 LOGGER.debug('Scenario fetched from : %s', scenario_file_name)
150 test_file_name = os.path.join(self.temp_dir, test_yaml_file_name)
152 if not os.path.exists(self.temp_dir):
153 os.makedirs(self.temp_dir)
155 self.apply_blacklist(scenario_file_name, test_file_name)
156 return test_file_name
159 def get_verifier_deployment_id():
161 Returns deployment id for active Rally deployment
163 cmd = ("rally deployment list | awk '/" +
164 getattr(config.CONF, 'rally_deployment_name') +
166 proc = subprocess.Popen(cmd, shell=True,
167 stdout=subprocess.PIPE,
168 stderr=subprocess.STDOUT)
169 deployment_uuid = proc.stdout.readline().rstrip()
170 return deployment_uuid.decode("utf-8")
173 def create_rally_deployment(environ=None):
174 """Create new rally deployment"""
175 # set the architecture to default
176 pod_arch = env.get("POD_ARCH")
177 arch_filter = ['aarch64']
179 if pod_arch and pod_arch in arch_filter:
180 LOGGER.info("Apply aarch64 specific to rally config...")
181 with open(RallyBase.rally_aar4_patch_path, "r") as pfile:
182 rally_patch_conf = pfile.read()
184 for line in fileinput.input(RallyBase.rally_conf_path):
186 if "cirros|testvm" in line:
187 print(rally_patch_conf)
189 LOGGER.info("Creating Rally environment...")
191 cmd = ['rally', 'deployment', 'destroy',
193 str(getattr(config.CONF, 'rally_deployment_name'))]
194 output = subprocess.check_output(cmd)
195 LOGGER.info("%s\n%s", " ".join(cmd), output.decode("utf-8"))
196 except subprocess.CalledProcessError:
199 cmd = ['rally', 'deployment', 'create', '--fromenv',
200 '--name', str(getattr(config.CONF, 'rally_deployment_name'))]
201 output = subprocess.check_output(cmd, env=environ)
202 LOGGER.info("%s\n%s", " ".join(cmd), output.decode("utf-8"))
204 cmd = ['rally', 'deployment', 'check']
205 output = subprocess.check_output(cmd)
206 LOGGER.info("%s\n%s", " ".join(cmd), output.decode("utf-8"))
207 return RallyBase.get_verifier_deployment_id()
210 def update_keystone_default_role(rally_conf='/etc/rally/rally.conf'):
211 """Set keystone_default_role in rally.conf"""
212 if env.get("NEW_USER_ROLE").lower() != "member":
213 rconfig = configparser.RawConfigParser()
214 rconfig.read(rally_conf)
215 if not rconfig.has_section('openstack'):
216 rconfig.add_section('openstack')
218 'openstack', 'keystone_default_role', env.get("NEW_USER_ROLE"))
219 with open(rally_conf, 'w') as config_file:
220 rconfig.write(config_file)
223 def clean_rally_conf(rally_conf='/etc/rally/rally.conf'):
224 """Clean Rally config"""
225 if env.get("NEW_USER_ROLE").lower() != "member":
226 rconfig = configparser.RawConfigParser()
227 rconfig.read(rally_conf)
228 if rconfig.has_option('openstack', 'keystone_default_role'):
229 rconfig.remove_option('openstack', 'keystone_default_role')
230 with open(rally_conf, 'w') as config_file:
231 rconfig.write(config_file)
234 def get_task_id(cmd_raw):
236 Get task id from command rally result.
239 :return: task_id as string
241 taskid_re = re.compile('^Task +(.*): started$')
242 for line in cmd_raw.splitlines(True):
244 match = taskid_re.match(line.decode("utf-8"))
246 return match.group(1)
250 def task_succeed(json_raw):
252 Parse JSON from rally JSON results.
257 rally_report = json.loads(json_raw)
258 tasks = rally_report.get('tasks')
261 if task.get('status') != 'finished' or \
262 task.get('pass_sla') is not True:
268 def _migration_supported(self):
269 """Determine if migration is supported."""
270 if self.compute_cnt > 1:
274 def _network_trunk_supported(self):
275 """Determine if network trunk service is available"""
276 if 'trunk' in self.network_extensions:
282 """Exclude scenario."""
285 with open(RallyBase.blacklist_file, 'r') as black_list_file:
286 black_list_yaml = yaml.safe_load(black_list_file)
288 deploy_scenario = env.get('DEPLOY_SCENARIO')
289 if (bool(deploy_scenario) and
290 'scenario' in black_list_yaml.keys()):
291 for item in black_list_yaml['scenario']:
292 scenarios = item['scenarios']
293 in_it = RallyBase.in_iterable_re
294 if in_it(deploy_scenario, scenarios):
295 tests = item['tests']
296 black_tests.extend(tests)
297 except Exception: # pylint: disable=broad-except
298 LOGGER.debug("Scenario exclusion not applied.")
303 def in_iterable_re(needle, haystack):
305 Check if given needle is in the iterable haystack, using regex.
307 :param needle: string to be matched
308 :param haystack: iterable of strings (optionally regex patterns)
309 :return: True if needle is eqial to any of the elements in haystack,
310 or if a nonempty regex pattern in haystack is found in needle.
312 # match without regex
313 if needle in haystack:
316 for pattern in haystack:
317 # match if regex pattern is set and found in the needle
318 if pattern and re.search(pattern, needle) is not None:
324 """Exclude functionalities."""
329 with open(RallyBase.blacklist_file, 'r') as black_list_file:
330 black_list_yaml = yaml.safe_load(black_list_file)
332 if env.get('BLOCK_MIGRATION').lower() == 'true':
333 func_list.append("block_migration")
334 if not self._migration_supported():
335 func_list.append("no_migration")
336 if not self._network_trunk_supported():
337 func_list.append("no_net_trunk_service")
339 func_list.append("no_floating_ip")
341 if 'functionality' in black_list_yaml.keys():
342 for item in black_list_yaml['functionality']:
343 functions = item['functions']
344 for func in func_list:
345 if func in functions:
346 tests = item['tests']
347 black_tests.extend(tests)
348 except Exception: # pylint: disable=broad-except
349 LOGGER.debug("Functionality exclusion not applied.")
353 def apply_blacklist(self, case_file_name, result_file_name):
354 """Apply blacklist."""
355 LOGGER.debug("Applying blacklist...")
356 cases_file = open(case_file_name, 'r')
357 result_file = open(result_file_name, 'w')
359 black_tests = list(set(self.excl_func() +
360 self.excl_scenario()))
363 LOGGER.debug("Blacklisted tests: %s", str(black_tests))
366 for cases_line in cases_file:
368 for black_tests_line in black_tests:
369 if re.search(black_tests_line,
370 cases_line.strip().rstrip(':')):
374 result_file.write(str(cases_line))
376 if cases_line.isspace():
383 def file_is_empty(file_name):
384 """Determine is a file is empty."""
386 if os.stat(file_name).st_size > 0:
388 except Exception: # pylint: disable=broad-except
393 def _save_results(self, test_name, task_id):
394 """ Generate and save task execution results"""
395 # check for result directory and create it otherwise
396 if not os.path.exists(self.results_dir):
397 LOGGER.debug('%s does not exist, we create it.',
399 os.makedirs(self.results_dir)
401 # put detailed result to log
402 cmd = (["rally", "task", "detailed", "--uuid", task_id])
403 LOGGER.debug('running command: %s', cmd)
404 output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
405 LOGGER.info("%s\n%s", " ".join(cmd), output.decode("utf-8"))
407 # save report as JSON
408 report_json_name = '{}.json'.format(test_name)
409 report_json_dir = os.path.join(self.results_dir, report_json_name)
410 cmd = (["rally", "task", "report", "--json", "--uuid", task_id,
411 "--out", report_json_dir])
412 LOGGER.debug('running command: %s', cmd)
413 output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
414 LOGGER.info("%s\n%s", " ".join(cmd), output.decode("utf-8"))
416 json_results = open(report_json_dir).read()
417 self._append_summary(json_results, test_name)
419 # parse JSON operation result
420 if self.task_succeed(json_results):
421 LOGGER.info('Test scenario: "%s" OK.', test_name)
423 LOGGER.info('Test scenario: "%s" Failed.', test_name)
425 def run_task(self, test_name):
427 LOGGER.info('Starting test scenario "%s" ...', test_name)
428 LOGGER.debug('running command: %s', self.run_cmd)
429 proc = subprocess.Popen(self.run_cmd, stdout=subprocess.PIPE,
430 stderr=subprocess.STDOUT)
431 output = proc.communicate()[0]
433 task_id = self.get_task_id(output)
434 LOGGER.debug('task_id : %s', task_id)
436 LOGGER.error("Failed to retrieve task_id")
437 LOGGER.error("Result:\n%s", output.decode("utf-8"))
438 raise Exception("Failed to retrieve task id")
439 self._save_results(test_name, task_id)
441 def _append_summary(self, json_raw, test_name):
442 # pylint: disable=too-many-locals
443 """Update statistics summary info."""
446 overall_duration = 0.0
450 rally_report = json.loads(json_raw)
451 for task in rally_report.get('tasks'):
452 for subtask in task.get('subtasks'):
454 for workload in subtask.get('workloads'):
455 if workload.get('full_duration'):
456 overall_duration += workload.get('full_duration')
458 if workload.get('data'):
459 nb_tests += len(workload.get('data'))
461 for result in workload.get('data'):
462 if not result.get('error'):
468 failures.append(subtask['title'])
470 success.append(subtask['title'])
472 scenario_summary = {'test_name': test_name,
473 'overall_duration': overall_duration,
474 'nb_tests': nb_tests,
475 'nb_success': nb_success,
477 'failures': failures,
478 'task_status': self.task_succeed(json_raw)}
479 self.summary.append(scenario_summary)
481 def prepare_run(self, **kwargs):
482 """Prepare resources needed by test scenarios."""
484 LOGGER.debug('Validating run tests...')
485 for test in kwargs.get('tests', self.stests):
486 if test in self.stests:
487 self.tests.append(test)
489 raise Exception("Test name '%s' is invalid" % test)
491 if not os.path.exists(self.task_dir):
492 os.makedirs(self.task_dir)
494 task = os.path.join(self.rally_dir, 'task.yaml')
495 if not os.path.exists(task):
496 LOGGER.error("Task file '%s' does not exist.", task)
497 raise Exception("Task file '{}' does not exist.".
499 self.task_file = os.path.join(self.task_dir, 'task.yaml')
500 shutil.copyfile(task, self.task_file)
502 task_macro = os.path.join(self.rally_dir, 'macro')
503 if not os.path.exists(task_macro):
504 LOGGER.error("Task macro dir '%s' does not exist.", task_macro)
505 raise Exception("Task macro dir '{}' does not exist.".
507 macro_dir = os.path.join(self.task_dir, 'macro')
508 if os.path.exists(macro_dir):
509 shutil.rmtree(macro_dir)
510 shutil.copytree(task_macro, macro_dir)
512 self.update_keystone_default_role()
513 self.compute_cnt = len(self.cloud.list_hypervisors())
514 self.network_extensions = self.cloud.get_network_extensions()
515 self.flavor_alt = self.create_flavor_alt()
516 self.services = [service.name for service in
517 self.cloud.list_services()]
519 LOGGER.debug("flavor: %s", self.flavor_alt)
521 def prepare_task(self, test_name):
522 """Prepare resources for test run."""
523 file_name = self._prepare_test_list(test_name)
524 if self.file_is_empty(file_name):
525 LOGGER.info('No tests for scenario "%s"', test_name)
527 self.run_cmd = (["rally", "task", "start", "--abort-on-sla-failure",
528 "--task", self.task_file, "--task-args",
529 str(self.build_task_args(test_name))])
532 def run_tests(self, **kwargs):
534 optional = kwargs.get('optional', [])
535 for test in self.tests:
536 if test in self.services or test not in optional:
537 if self.prepare_task(test):
540 def _generate_report(self):
541 """Generate test execution summary report."""
548 res_table = prettytable.PrettyTable(
550 field_names=['Module', 'Duration', 'nb. Test Run', 'Success'])
551 res_table.align['Module'] = "l"
552 res_table.align['Duration'] = "r"
553 res_table.align['Success'] = "r"
555 # for each scenario we draw a row for the table
556 for item in self.summary:
557 if item['task_status'] is True:
559 total_duration += item['overall_duration']
560 total_nb_tests += item['nb_tests']
561 total_nb_success += item['nb_success']
563 success_avg = 100 * item['nb_success'] / item['nb_tests']
564 except ZeroDivisionError:
566 success_str = str("{:0.2f}".format(success_avg)) + '%'
567 duration_str = time.strftime("%H:%M:%S",
568 time.gmtime(item['overall_duration']))
569 res_table.add_row([item['test_name'], duration_str,
570 item['nb_tests'], success_str])
571 payload.append({'module': item['test_name'],
572 'details': {'duration': item['overall_duration'],
573 'nb tests': item['nb_tests'],
574 'success rate': success_str,
575 'success': item['success'],
576 'failures': item['failures']}})
578 total_duration_str = time.strftime("%H:%M:%S",
579 time.gmtime(total_duration))
581 self.result = 100 * total_nb_success / total_nb_tests
582 except ZeroDivisionError:
584 success_rate = "{:0.2f}".format(self.result)
585 success_rate_str = str(success_rate) + '%'
586 res_table.add_row(["", "", "", ""])
587 res_table.add_row(["TOTAL:", total_duration_str, total_nb_tests,
590 LOGGER.info("Rally Summary Report:\n\n%s\n", res_table.get_string())
591 LOGGER.info("Rally '%s' success_rate is %s%% in %s/%s modules",
592 self.case_name, success_rate, nb_modules,
594 payload.append({'summary': {'duration': total_duration,
595 'nb tests': total_nb_tests,
596 'nb success': success_rate}})
597 self.details = payload
600 def export_task(file_name, export_type="html"):
601 """Export all task results (e.g. html or xunit report)
604 subprocess.CalledProcessError: if Rally doesn't return 0
609 cmd = ["rally", "task", "export", "--type", export_type,
611 str(getattr(config.CONF, 'rally_deployment_name')),
613 LOGGER.debug('running command: %s', cmd)
614 output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
615 LOGGER.info("%s\n%s", " ".join(cmd), output.decode("utf-8"))
618 def verify_report(file_name, uuid, export_type="html"):
619 """Generate the verifier report (e.g. html or xunit report)
622 subprocess.CalledProcessError: if Rally doesn't return 0
627 cmd = ["rally", "verify", "report", "--type", export_type,
628 "--uuid", uuid, "--to", file_name]
629 LOGGER.debug('running command: %s', cmd)
630 output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
631 LOGGER.info("%s\n%s", " ".join(cmd), output.decode("utf-8"))
634 """Cleanup of OpenStack resources. Should be called on completion."""
635 self.clean_rally_conf()
636 self.clean_rally_logs()
638 self.orig_cloud.delete_flavor(self.flavor_alt.id)
639 super(RallyBase, self).clean()
641 def is_successful(self):
642 """The overall result of the test."""
643 for item in self.summary:
644 if item['task_status'] is False:
645 return testcase.TestCase.EX_TESTCASE_FAILED
647 return super(RallyBase, self).is_successful()
650 def update_rally_logs(res_dir, rally_conf='/etc/rally/rally.conf'):
651 """Print rally logs in res dir"""
652 if not os.path.exists(res_dir):
654 rconfig = configparser.RawConfigParser()
655 rconfig.read(rally_conf)
656 rconfig.set('DEFAULT', 'debug', True)
657 rconfig.set('DEFAULT', 'use_stderr', False)
658 rconfig.set('DEFAULT', 'log-file', 'rally.log')
659 rconfig.set('DEFAULT', 'log_dir', res_dir)
660 with open(rally_conf, 'w') as config_file:
661 rconfig.write(config_file)
664 def clean_rally_logs(rally_conf='/etc/rally/rally.conf'):
665 """Clean Rally config"""
666 rconfig = configparser.RawConfigParser()
667 rconfig.read(rally_conf)
668 if rconfig.has_option('DEFAULT', 'use_stderr'):
669 rconfig.remove_option('DEFAULT', 'use_stderr')
670 if rconfig.has_option('DEFAULT', 'debug'):
671 rconfig.remove_option('DEFAULT', 'debug')
672 if rconfig.has_option('DEFAULT', 'log-file'):
673 rconfig.remove_option('DEFAULT', 'log-file')
674 if rconfig.has_option('DEFAULT', 'log_dir'):
675 rconfig.remove_option('DEFAULT', 'log_dir')
676 with open(rally_conf, 'w') as config_file:
677 rconfig.write(config_file)
679 def run(self, **kwargs):
681 self.start_time = time.time()
683 assert super(RallyBase, self).run(
684 **kwargs) == testcase.TestCase.EX_OK
685 self.update_rally_logs(self.res_dir)
686 self.create_rally_deployment(environ=self.project.get_environ())
687 self.prepare_run(**kwargs)
688 self.run_tests(**kwargs)
689 self._generate_report()
691 "{}/{}.html".format(self.results_dir, self.case_name))
693 "{}/{}.xml".format(self.results_dir, self.case_name),
694 export_type="junit-xml")
695 res = testcase.TestCase.EX_OK
696 except Exception: # pylint: disable=broad-except
697 LOGGER.exception('Error with run:')
699 res = testcase.TestCase.EX_RUN_ERROR
700 self.stop_time = time.time()
704 class RallySanity(RallyBase):
705 """Rally sanity testcase implementation."""
707 def __init__(self, **kwargs):
708 """Initialize RallySanity object."""
709 if "case_name" not in kwargs:
710 kwargs["case_name"] = "rally_sanity"
711 super(RallySanity, self).__init__(**kwargs)
713 self.scenario_dir = os.path.join(self.rally_scenario_dir, 'sanity')
716 class RallyFull(RallyBase):
717 """Rally full testcase implementation."""
719 def __init__(self, **kwargs):
720 """Initialize RallyFull object."""
721 if "case_name" not in kwargs:
722 kwargs["case_name"] = "rally_full"
723 super(RallyFull, self).__init__(**kwargs)
725 self.scenario_dir = os.path.join(self.rally_scenario_dir, 'full')
728 class RallyJobs(RallyBase):
729 """Rally OpenStack CI testcase implementation."""
733 def __init__(self, **kwargs):
734 """Initialize RallyJobs object."""
735 if "case_name" not in kwargs:
736 kwargs["case_name"] = "rally_jobs"
737 super(RallyJobs, self).__init__(**kwargs)
738 self.task_file = os.path.join(self.rally_dir, 'rally_jobs.yaml')
739 self.task_yaml = None
741 def prepare_run(self, **kwargs):
742 """Create resources needed by test scenarios."""
743 super(RallyJobs, self).prepare_run(**kwargs)
744 with open(os.path.join(self.rally_dir,
745 'rally_jobs.yaml'), 'r') as task_file:
746 self.task_yaml = yaml.safe_load(task_file)
748 for task in self.task_yaml:
749 if task not in self.tests:
750 raise Exception("Test '%s' not in '%s'" %
753 def apply_blacklist(self, case_file_name, result_file_name):
754 # pylint: disable=too-many-branches
755 """Apply blacklist."""
756 LOGGER.debug("Applying blacklist...")
757 black_tests = list(set(self.excl_func() +
758 self.excl_scenario()))
760 LOGGER.debug("Blacklisted tests: %s", str(black_tests))
762 template = YAML(typ='jinja2')
763 with open(case_file_name, 'r') as fname:
764 cases = template.load(fname)
765 if cases.get("version", 1) == 1:
766 # scenarios in dictionary
767 for name in cases.keys():
768 if self.in_iterable_re(name, black_tests):
771 # workloads in subtasks
772 for sind, subtask in reversed(list(
773 enumerate(cases.get('subtasks', [])))):
774 for wind, workload in reversed(list(
775 enumerate(subtask.get('workloads', [])))):
776 scenario = workload.get('scenario', {})
777 for name in scenario.keys():
778 if self.in_iterable_re(name, black_tests):
779 cases['subtasks'][sind]['workloads'].pop(wind)
781 if 'workloads' in cases['subtasks'][sind]:
782 if not cases['subtasks'][sind]['workloads']:
783 cases['subtasks'].pop(sind)
784 # scenarios in subtasks
785 for sind, subtask in reversed(list(
786 enumerate(cases.get('subtasks', [])))):
787 scenario = subtask.get('scenario', {})
788 for name in scenario.keys():
789 if self.in_iterable_re(name, black_tests):
790 cases['subtasks'].pop(sind)
793 with open(result_file_name, 'w') as fname:
794 template.dump(cases, fname)
796 def build_task_args(self, test_name):
797 """Build arguments for the Rally task."""
800 task_args['floating_network'] = str(self.ext_net.name)
802 task_args['floating_network'] = ''
803 task_args['image_name'] = str(self.image.name)
804 task_args['flavor_name'] = str(self.flavor.name)
808 def _remove_plugins_extra():
809 inst_dir = getattr(config.CONF, 'dir_rally_inst')
811 shutil.rmtree(os.path.join(inst_dir, 'plugins'))
812 shutil.rmtree(os.path.join(inst_dir, 'extra'))
813 except Exception: # pylint: disable=broad-except
816 def prepare_task(self, test_name):
817 """Prepare resources for test run."""
818 self._remove_plugins_extra()
819 jobs_dir = os.path.join(
820 getattr(config.CONF, 'dir_rally_data'), test_name, 'rally-jobs')
821 inst_dir = getattr(config.CONF, 'dir_rally_inst')
822 shutil.copytree(os.path.join(jobs_dir, 'plugins'),
823 os.path.join(inst_dir, 'plugins'))
824 shutil.copytree(os.path.join(jobs_dir, 'extra'),
825 os.path.join(inst_dir, 'extra'))
827 task_name = self.task_yaml.get(test_name).get("task")
828 task = os.path.join(jobs_dir, task_name)
829 if not os.path.exists(task):
830 raise Exception("The scenario '%s' does not exist." % task)
831 LOGGER.debug('Scenario fetched from : %s', task)
833 if not os.path.exists(self.temp_dir):
834 os.makedirs(self.temp_dir)
835 task_file_name = os.path.join(self.temp_dir, task_name)
836 self.apply_blacklist(task, task_file_name)
837 self.run_cmd = (["rally", "task", "start", "--task", task_file_name,
838 "--task-args", str(self.build_task_args(test_name))])
842 self._remove_plugins_extra()
843 super(RallyJobs, self).clean()