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')
72 def __init__(self, **kwargs):
73 """Initialize RallyBase object."""
74 super(RallyBase, self).__init__(**kwargs)
75 assert self.orig_cloud
77 if self.orig_cloud.get_role("admin"):
79 elif self.orig_cloud.get_role("Admin"):
82 raise Exception("Cannot detect neither admin nor Admin")
83 self.orig_cloud.grant_role(
84 role_name, user=self.project.user.id,
85 project=self.project.project.id,
86 domain=self.project.domain.id)
87 self.results_dir = os.path.join(
88 getattr(config.CONF, 'dir_results'), self.case_name)
92 self.scenario_dir = ''
94 self.start_time = None
98 self.flavor_alt = None
101 self.network_extensions = []
104 def build_task_args(self, test_name):
105 """Build arguments for the Rally task."""
106 task_args = {'service_list': [test_name]}
107 task_args['image_name'] = str(self.image.name)
108 task_args['flavor_name'] = str(self.flavor.name)
109 task_args['flavor_alt_name'] = str(self.flavor_alt.name)
110 task_args['glance_image_location'] = str(self.filename)
111 task_args['glance_image_format'] = str(self.image_format)
112 task_args['tmpl_dir'] = str(self.template_dir)
113 task_args['sup_dir'] = str(self.support_dir)
114 task_args['users_amount'] = self.users_amount
115 task_args['tenants_amount'] = self.tenants_amount
116 task_args['use_existing_users'] = False
117 task_args['iterations'] = self.iterations_amount
118 task_args['concurrency'] = self.concurrency
119 task_args['smoke'] = self.smoke
120 task_args['volume_version'] = self.volume_version
121 task_args['volume_service_type'] = self.volume_service_type
122 task_args['block_migration'] = env.get("BLOCK_MIGRATION").lower()
125 task_args['floating_network'] = str(self.ext_net.name)
127 task_args['floating_network'] = ''
130 task_args['netid'] = str(self.network.id)
132 task_args['netid'] = ''
136 def _prepare_test_list(self, test_name):
137 """Build the list of test cases to be executed."""
138 test_yaml_file_name = 'opnfv-{}.yaml'.format(test_name)
139 scenario_file_name = os.path.join(self.rally_scenario_dir,
142 if not os.path.exists(scenario_file_name):
143 scenario_file_name = os.path.join(self.scenario_dir,
146 if not os.path.exists(scenario_file_name):
147 raise Exception("The scenario '%s' does not exist."
148 % scenario_file_name)
150 LOGGER.debug('Scenario fetched from : %s', scenario_file_name)
151 test_file_name = os.path.join(self.temp_dir, test_yaml_file_name)
153 if not os.path.exists(self.temp_dir):
154 os.makedirs(self.temp_dir)
156 self.apply_blacklist(scenario_file_name, test_file_name)
157 return test_file_name
160 def get_verifier_deployment_id():
162 Returns deployment id for active Rally deployment
164 cmd = ("rally deployment list | awk '/" +
165 getattr(config.CONF, 'rally_deployment_name') +
167 proc = subprocess.Popen(cmd, shell=True,
168 stdout=subprocess.PIPE,
169 stderr=subprocess.STDOUT)
170 deployment_uuid = proc.stdout.readline().rstrip()
171 return deployment_uuid.decode("utf-8")
174 def create_rally_deployment(environ=None):
175 # pylint: disable=unexpected-keyword-arg
176 """Create new rally deployment"""
177 # set the architecture to default
178 pod_arch = env.get("POD_ARCH")
179 arch_filter = ['aarch64']
181 if pod_arch and pod_arch in arch_filter:
182 LOGGER.info("Apply aarch64 specific to rally config...")
183 with open(RallyBase.rally_aar4_patch_path, "r") as pfile:
184 rally_patch_conf = pfile.read()
186 for line in fileinput.input(RallyBase.rally_conf_path):
188 if "cirros|testvm" in line:
189 print(rally_patch_conf)
191 LOGGER.info("Creating Rally environment...")
193 cmd = ['rally', 'deployment', 'destroy',
195 str(getattr(config.CONF, 'rally_deployment_name'))]
196 output = subprocess.check_output(cmd)
197 LOGGER.info("%s\n%s", " ".join(cmd), output.decode("utf-8"))
198 except subprocess.CalledProcessError:
201 cmd = ['rally', 'deployment', 'create', '--fromenv',
202 '--name', str(getattr(config.CONF, 'rally_deployment_name'))]
203 output = subprocess.check_output(cmd, env=environ)
204 LOGGER.info("%s\n%s", " ".join(cmd), output.decode("utf-8"))
206 cmd = ['rally', 'deployment', 'check']
207 output = subprocess.check_output(cmd)
208 LOGGER.info("%s\n%s", " ".join(cmd), output.decode("utf-8"))
209 return RallyBase.get_verifier_deployment_id()
212 def update_keystone_default_role(rally_conf='/etc/rally/rally.conf'):
213 """Set keystone_default_role in rally.conf"""
214 if env.get("NEW_USER_ROLE").lower() != "member":
215 rconfig = configparser.RawConfigParser()
216 rconfig.read(rally_conf)
217 if not rconfig.has_section('openstack'):
218 rconfig.add_section('openstack')
220 'openstack', 'keystone_default_role', env.get("NEW_USER_ROLE"))
221 with open(rally_conf, 'w') as config_file:
222 rconfig.write(config_file)
225 def clean_rally_conf(rally_conf='/etc/rally/rally.conf'):
226 """Clean Rally config"""
227 if env.get("NEW_USER_ROLE").lower() != "member":
228 rconfig = configparser.RawConfigParser()
229 rconfig.read(rally_conf)
230 if rconfig.has_option('openstack', 'keystone_default_role'):
231 rconfig.remove_option('openstack', 'keystone_default_role')
232 with open(rally_conf, 'w') as config_file:
233 rconfig.write(config_file)
236 def get_task_id(cmd_raw):
238 Get task id from command rally result.
241 :return: task_id as string
243 taskid_re = re.compile('^Task +(.*): started$')
244 for line in cmd_raw.splitlines(True):
246 match = taskid_re.match(line.decode("utf-8"))
248 return match.group(1)
252 def task_succeed(json_raw):
254 Parse JSON from rally JSON results.
259 rally_report = json.loads(json_raw)
260 tasks = rally_report.get('tasks')
263 if task.get('status') != 'finished' or \
264 task.get('pass_sla') is not True:
270 def _migration_supported(self):
271 """Determine if migration is supported."""
272 if self.compute_cnt > 1:
276 def _network_trunk_supported(self):
277 """Determine if network trunk service is available"""
278 if 'trunk' in self.network_extensions:
284 """Exclude scenario."""
287 with open(RallyBase.blacklist_file, 'r') as black_list_file:
288 black_list_yaml = yaml.safe_load(black_list_file)
290 deploy_scenario = env.get('DEPLOY_SCENARIO')
291 if (bool(deploy_scenario) and
292 'scenario' in black_list_yaml.keys()):
293 for item in black_list_yaml['scenario']:
294 scenarios = item['scenarios']
295 in_it = RallyBase.in_iterable_re
296 if in_it(deploy_scenario, scenarios):
297 tests = item['tests']
298 black_tests.extend(tests)
299 except Exception: # pylint: disable=broad-except
300 LOGGER.debug("Scenario exclusion not applied.")
305 def in_iterable_re(needle, haystack):
307 Check if given needle is in the iterable haystack, using regex.
309 :param needle: string to be matched
310 :param haystack: iterable of strings (optionally regex patterns)
311 :return: True if needle is eqial to any of the elements in haystack,
312 or if a nonempty regex pattern in haystack is found in needle.
314 # match without regex
315 if needle in haystack:
318 for pattern in haystack:
319 # match if regex pattern is set and found in the needle
320 if pattern and re.search(pattern, needle) is not None:
326 """Exclude functionalities."""
331 with open(RallyBase.blacklist_file, 'r') as black_list_file:
332 black_list_yaml = yaml.safe_load(black_list_file)
334 if env.get('BLOCK_MIGRATION').lower() == 'true':
335 func_list.append("block_migration")
336 if not self._migration_supported():
337 func_list.append("no_migration")
338 if not self._network_trunk_supported():
339 func_list.append("no_net_trunk_service")
341 func_list.append("no_floating_ip")
343 if 'functionality' in black_list_yaml.keys():
344 for item in black_list_yaml['functionality']:
345 functions = item['functions']
346 for func in func_list:
347 if func in functions:
348 tests = item['tests']
349 black_tests.extend(tests)
350 except Exception: # pylint: disable=broad-except
351 LOGGER.debug("Functionality exclusion not applied.")
355 def apply_blacklist(self, case_file_name, result_file_name):
356 """Apply blacklist."""
357 LOGGER.debug("Applying blacklist...")
358 cases_file = open(case_file_name, 'r')
359 result_file = open(result_file_name, 'w')
361 black_tests = list(set(self.excl_func() +
362 self.excl_scenario()))
365 LOGGER.debug("Blacklisted tests: %s", str(black_tests))
368 for cases_line in cases_file:
370 for black_tests_line in black_tests:
371 if re.search(black_tests_line,
372 cases_line.strip().rstrip(':')):
376 result_file.write(str(cases_line))
378 if cases_line.isspace():
385 def file_is_empty(file_name):
386 """Determine is a file is empty."""
388 if os.stat(file_name).st_size > 0:
390 except Exception: # pylint: disable=broad-except
395 def _save_results(self, test_name, task_id):
396 """ Generate and save task execution results"""
397 # check for result directory and create it otherwise
398 if not os.path.exists(self.results_dir):
399 LOGGER.debug('%s does not exist, we create it.',
401 os.makedirs(self.results_dir)
403 # put detailed result to log
404 cmd = (["rally", "task", "detailed", "--uuid", task_id])
405 LOGGER.debug('running command: %s', cmd)
406 output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
407 LOGGER.info("%s\n%s", " ".join(cmd), output.decode("utf-8"))
409 # save report as JSON
410 report_json_name = '{}.json'.format(test_name)
411 report_json_dir = os.path.join(self.results_dir, report_json_name)
412 cmd = (["rally", "task", "report", "--json", "--uuid", task_id,
413 "--out", report_json_dir])
414 LOGGER.debug('running command: %s', cmd)
415 output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
416 LOGGER.info("%s\n%s", " ".join(cmd), output.decode("utf-8"))
418 json_results = open(report_json_dir).read()
419 self._append_summary(json_results, test_name)
421 # parse JSON operation result
422 if self.task_succeed(json_results):
423 LOGGER.info('Test scenario: "%s" OK.', test_name)
425 LOGGER.info('Test scenario: "%s" Failed.', test_name)
427 def run_task(self, test_name):
429 LOGGER.info('Starting test scenario "%s" ...', test_name)
430 LOGGER.debug('running command: %s', self.run_cmd)
431 proc = subprocess.Popen(self.run_cmd, stdout=subprocess.PIPE,
432 stderr=subprocess.STDOUT)
434 output = proc.communicate(timeout=self.task_timeout)[0]
435 except subprocess.TimeoutExpired:
438 LOGGER.error("Failed to complete run task")
439 raise Exception("Failed to complete run task")
440 task_id = self.get_task_id(output)
441 LOGGER.debug('task_id : %s', task_id)
443 LOGGER.error("Failed to retrieve task_id")
444 LOGGER.error("Result:\n%s", output.decode("utf-8"))
445 raise Exception("Failed to retrieve task id")
446 self._save_results(test_name, task_id)
448 def _append_summary(self, json_raw, test_name):
449 # pylint: disable=too-many-locals
450 """Update statistics summary info."""
453 overall_duration = 0.0
457 rally_report = json.loads(json_raw)
458 for task in rally_report.get('tasks'):
459 for subtask in task.get('subtasks'):
461 for workload in subtask.get('workloads'):
462 if workload.get('full_duration'):
463 overall_duration += workload.get('full_duration')
465 if workload.get('data'):
466 nb_tests += len(workload.get('data'))
468 for result in workload.get('data'):
469 if not result.get('error'):
475 failures.append(subtask['title'])
477 success.append(subtask['title'])
479 scenario_summary = {'test_name': test_name,
480 'overall_duration': overall_duration,
481 'nb_tests': nb_tests,
482 'nb_success': nb_success,
484 'failures': failures,
485 'task_status': self.task_succeed(json_raw)}
486 self.summary.append(scenario_summary)
488 def prepare_run(self, **kwargs):
489 """Prepare resources needed by test scenarios."""
491 LOGGER.debug('Validating run tests...')
492 for test in kwargs.get('tests', self.stests):
493 if test in self.stests:
494 self.tests.append(test)
496 raise Exception("Test name '%s' is invalid" % test)
498 if not os.path.exists(self.task_dir):
499 os.makedirs(self.task_dir)
501 task = os.path.join(self.rally_dir, 'task.yaml')
502 if not os.path.exists(task):
503 LOGGER.error("Task file '%s' does not exist.", task)
504 raise Exception("Task file '{}' does not exist.".
506 self.task_file = os.path.join(self.task_dir, 'task.yaml')
507 shutil.copyfile(task, self.task_file)
509 task_macro = os.path.join(self.rally_dir, 'macro')
510 if not os.path.exists(task_macro):
511 LOGGER.error("Task macro dir '%s' does not exist.", task_macro)
512 raise Exception("Task macro dir '{}' does not exist.".
514 macro_dir = os.path.join(self.task_dir, 'macro')
515 if os.path.exists(macro_dir):
516 shutil.rmtree(macro_dir)
517 shutil.copytree(task_macro, macro_dir)
519 self.update_keystone_default_role()
520 self.compute_cnt = len(self.cloud.list_hypervisors())
521 self.network_extensions = self.cloud.get_network_extensions()
522 self.flavor_alt = self.create_flavor_alt()
523 self.services = [service.name for service in
524 self.cloud.list_services()]
526 LOGGER.debug("flavor: %s", self.flavor_alt)
528 def prepare_task(self, test_name):
529 """Prepare resources for test run."""
530 file_name = self._prepare_test_list(test_name)
531 if self.file_is_empty(file_name):
532 LOGGER.info('No tests for scenario "%s"', test_name)
534 self.run_cmd = (["rally", "task", "start", "--abort-on-sla-failure",
535 "--task", self.task_file, "--task-args",
536 str(self.build_task_args(test_name))])
539 def run_tests(self, **kwargs):
541 optional = kwargs.get('optional', [])
542 for test in self.tests:
543 if test in self.services or test not in optional:
544 if self.prepare_task(test):
547 def _generate_report(self):
548 """Generate test execution summary report."""
555 res_table = prettytable.PrettyTable(
557 field_names=['Module', 'Duration', 'nb. Test Run', 'Success'])
558 res_table.align['Module'] = "l"
559 res_table.align['Duration'] = "r"
560 res_table.align['Success'] = "r"
562 # for each scenario we draw a row for the table
563 for item in self.summary:
564 if item['task_status'] is True:
566 total_duration += item['overall_duration']
567 total_nb_tests += item['nb_tests']
568 total_nb_success += item['nb_success']
570 success_avg = 100 * item['nb_success'] / item['nb_tests']
571 except ZeroDivisionError:
573 success_str = str("{:0.2f}".format(success_avg)) + '%'
574 duration_str = time.strftime("%H:%M:%S",
575 time.gmtime(item['overall_duration']))
576 res_table.add_row([item['test_name'], duration_str,
577 item['nb_tests'], success_str])
578 payload.append({'module': item['test_name'],
579 'details': {'duration': item['overall_duration'],
580 'nb tests': item['nb_tests'],
581 'success rate': success_str,
582 'success': item['success'],
583 'failures': item['failures']}})
585 total_duration_str = time.strftime("%H:%M:%S",
586 time.gmtime(total_duration))
588 self.result = 100 * total_nb_success / total_nb_tests
589 except ZeroDivisionError:
591 success_rate = "{:0.2f}".format(self.result)
592 success_rate_str = str(success_rate) + '%'
593 res_table.add_row(["", "", "", ""])
594 res_table.add_row(["TOTAL:", total_duration_str, total_nb_tests,
597 LOGGER.info("Rally Summary Report:\n\n%s\n", res_table.get_string())
598 LOGGER.info("Rally '%s' success_rate is %s%% in %s/%s modules",
599 self.case_name, success_rate, nb_modules,
601 payload.append({'summary': {'duration': total_duration,
602 'nb tests': total_nb_tests,
603 'nb success': success_rate}})
604 self.details = payload
607 def export_task(file_name, export_type="html"):
608 """Export all task results (e.g. html or xunit report)
611 subprocess.CalledProcessError: if Rally doesn't return 0
616 cmd = ["rally", "task", "export", "--type", export_type,
618 str(getattr(config.CONF, 'rally_deployment_name')),
620 LOGGER.debug('running command: %s', cmd)
621 output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
622 LOGGER.info("%s\n%s", " ".join(cmd), output.decode("utf-8"))
625 def verify_report(file_name, uuid, export_type="html"):
626 """Generate the verifier report (e.g. html or xunit report)
629 subprocess.CalledProcessError: if Rally doesn't return 0
634 cmd = ["rally", "verify", "report", "--type", export_type,
635 "--uuid", uuid, "--to", file_name]
636 LOGGER.debug('running command: %s', cmd)
637 output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
638 LOGGER.info("%s\n%s", " ".join(cmd), output.decode("utf-8"))
641 """Cleanup of OpenStack resources. Should be called on completion."""
642 self.clean_rally_conf()
643 self.clean_rally_logs()
645 self.orig_cloud.delete_flavor(self.flavor_alt.id)
646 super(RallyBase, self).clean()
648 def is_successful(self):
649 """The overall result of the test."""
650 for item in self.summary:
651 if item['task_status'] is False:
652 return testcase.TestCase.EX_TESTCASE_FAILED
654 return super(RallyBase, self).is_successful()
657 def update_rally_logs(res_dir, rally_conf='/etc/rally/rally.conf'):
658 """Print rally logs in res dir"""
659 if not os.path.exists(res_dir):
661 rconfig = configparser.RawConfigParser()
662 rconfig.read(rally_conf)
663 rconfig.set('DEFAULT', 'debug', True)
664 rconfig.set('DEFAULT', 'use_stderr', False)
665 rconfig.set('DEFAULT', 'log-file', 'rally.log')
666 rconfig.set('DEFAULT', 'log_dir', res_dir)
667 with open(rally_conf, 'w') as config_file:
668 rconfig.write(config_file)
671 def clean_rally_logs(rally_conf='/etc/rally/rally.conf'):
672 """Clean Rally config"""
673 rconfig = configparser.RawConfigParser()
674 rconfig.read(rally_conf)
675 if rconfig.has_option('DEFAULT', 'use_stderr'):
676 rconfig.remove_option('DEFAULT', 'use_stderr')
677 if rconfig.has_option('DEFAULT', 'debug'):
678 rconfig.remove_option('DEFAULT', 'debug')
679 if rconfig.has_option('DEFAULT', 'log-file'):
680 rconfig.remove_option('DEFAULT', 'log-file')
681 if rconfig.has_option('DEFAULT', 'log_dir'):
682 rconfig.remove_option('DEFAULT', 'log_dir')
683 with open(rally_conf, 'w') as config_file:
684 rconfig.write(config_file)
686 def run(self, **kwargs):
688 self.start_time = time.time()
690 assert super(RallyBase, self).run(
691 **kwargs) == testcase.TestCase.EX_OK
692 self.update_rally_logs(self.res_dir)
693 self.create_rally_deployment(environ=self.project.get_environ())
694 self.prepare_run(**kwargs)
695 self.run_tests(**kwargs)
696 self._generate_report()
698 "{}/{}.html".format(self.results_dir, self.case_name))
700 "{}/{}.xml".format(self.results_dir, self.case_name),
701 export_type="junit-xml")
702 res = testcase.TestCase.EX_OK
703 except Exception: # pylint: disable=broad-except
704 LOGGER.exception('Error with run:')
706 res = testcase.TestCase.EX_RUN_ERROR
707 self.stop_time = time.time()
711 class RallySanity(RallyBase):
712 """Rally sanity testcase implementation."""
714 def __init__(self, **kwargs):
715 """Initialize RallySanity object."""
716 if "case_name" not in kwargs:
717 kwargs["case_name"] = "rally_sanity"
718 super(RallySanity, self).__init__(**kwargs)
720 self.scenario_dir = os.path.join(self.rally_scenario_dir, 'sanity')
723 class RallyFull(RallyBase):
724 """Rally full testcase implementation."""
728 def __init__(self, **kwargs):
729 """Initialize RallyFull object."""
730 if "case_name" not in kwargs:
731 kwargs["case_name"] = "rally_full"
732 super(RallyFull, self).__init__(**kwargs)
734 self.scenario_dir = os.path.join(self.rally_scenario_dir, 'full')
737 class RallyJobs(RallyBase):
738 """Rally OpenStack CI testcase implementation."""
743 def __init__(self, **kwargs):
744 """Initialize RallyJobs object."""
745 if "case_name" not in kwargs:
746 kwargs["case_name"] = "rally_jobs"
747 super(RallyJobs, self).__init__(**kwargs)
748 self.task_file = os.path.join(self.rally_dir, 'rally_jobs.yaml')
749 self.task_yaml = None
751 def prepare_run(self, **kwargs):
752 """Create resources needed by test scenarios."""
753 super(RallyJobs, self).prepare_run(**kwargs)
754 with open(os.path.join(self.rally_dir,
755 'rally_jobs.yaml'), 'r') as task_file:
756 self.task_yaml = yaml.safe_load(task_file)
758 for task in self.task_yaml:
759 if task not in self.tests:
760 raise Exception("Test '%s' not in '%s'" %
763 def apply_blacklist(self, case_file_name, result_file_name):
764 # pylint: disable=too-many-branches
765 """Apply blacklist."""
766 LOGGER.debug("Applying blacklist...")
767 black_tests = list(set(self.excl_func() +
768 self.excl_scenario()))
770 LOGGER.debug("Blacklisted tests: %s", str(black_tests))
772 template = YAML(typ='jinja2')
773 with open(case_file_name, 'r') as fname:
774 cases = template.load(fname)
775 if cases.get("version", 1) == 1:
776 # scenarios in dictionary
777 for name in cases.keys():
778 if self.in_iterable_re(name, black_tests):
781 # workloads in subtasks
782 for sind, subtask in reversed(list(
783 enumerate(cases.get('subtasks', [])))):
784 for wind, workload in reversed(list(
785 enumerate(subtask.get('workloads', [])))):
786 scenario = workload.get('scenario', {})
787 for name in scenario.keys():
788 if self.in_iterable_re(name, black_tests):
789 cases['subtasks'][sind]['workloads'].pop(wind)
791 if 'workloads' in cases['subtasks'][sind]:
792 if not cases['subtasks'][sind]['workloads']:
793 cases['subtasks'].pop(sind)
794 # scenarios in subtasks
795 for sind, subtask in reversed(list(
796 enumerate(cases.get('subtasks', [])))):
797 scenario = subtask.get('scenario', {})
798 for name in scenario.keys():
799 if self.in_iterable_re(name, black_tests):
800 cases['subtasks'].pop(sind)
803 with open(result_file_name, 'w') as fname:
804 template.dump(cases, fname)
806 def build_task_args(self, test_name):
807 """Build arguments for the Rally task."""
810 task_args['floating_network'] = str(self.ext_net.name)
812 task_args['floating_network'] = ''
813 task_args['image_name'] = str(self.image.name)
814 task_args['flavor_name'] = str(self.flavor.name)
818 def _remove_plugins_extra():
819 inst_dir = getattr(config.CONF, 'dir_rally_inst')
821 shutil.rmtree(os.path.join(inst_dir, 'plugins'))
822 shutil.rmtree(os.path.join(inst_dir, 'extra'))
823 except Exception: # pylint: disable=broad-except
826 def prepare_task(self, test_name):
827 """Prepare resources for test run."""
828 self._remove_plugins_extra()
829 jobs_dir = os.path.join(
830 getattr(config.CONF, 'dir_rally_data'), test_name, 'rally-jobs')
831 inst_dir = getattr(config.CONF, 'dir_rally_inst')
832 shutil.copytree(os.path.join(jobs_dir, 'plugins'),
833 os.path.join(inst_dir, 'plugins'))
834 shutil.copytree(os.path.join(jobs_dir, 'extra'),
835 os.path.join(inst_dir, 'extra'))
837 task_name = self.task_yaml.get(test_name).get("task")
838 task = os.path.join(jobs_dir, task_name)
839 if not os.path.exists(task):
840 raise Exception("The scenario '%s' does not exist." % task)
841 LOGGER.debug('Scenario fetched from : %s', task)
843 if not os.path.exists(self.temp_dir):
844 os.makedirs(self.temp_dir)
845 task_file_name = os.path.join(self.temp_dir, task_name)
846 self.apply_blacklist(task, task_file_name)
847 self.run_cmd = (["rally", "task", "start", "--task", task_file_name,
848 "--task-args", str(self.build_task_args(test_name))])
852 self._remove_plugins_extra()
853 super(RallyJobs, self).clean()