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 TESTS = ['authenticate', 'glance', 'cinder', 'gnocchi', 'heat',
44 'keystone', 'neutron', 'nova', 'quotas']
46 RALLY_CONF_PATH = "/etc/rally/rally.conf"
47 RALLY_AARCH64_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')
70 def __init__(self, **kwargs):
71 """Initialize RallyBase object."""
72 super(RallyBase, self).__init__(**kwargs)
73 assert self.orig_cloud
75 if self.orig_cloud.get_role("admin"):
77 elif self.orig_cloud.get_role("Admin"):
80 raise Exception("Cannot detect neither admin nor Admin")
81 self.orig_cloud.grant_role(
82 role_name, user=self.project.user.id,
83 project=self.project.project.id,
84 domain=self.project.domain.id)
85 self.results_dir = os.path.join(
86 getattr(config.CONF, 'dir_results'), self.case_name)
90 self.scenario_dir = ''
92 self.start_time = None
96 self.flavor_alt = None
99 self.network_extensions = []
102 def build_task_args(self, test_name):
103 """Build arguments for the Rally task."""
104 task_args = {'service_list': [test_name]}
105 task_args['image_name'] = str(self.image.name)
106 task_args['flavor_name'] = str(self.flavor.name)
107 task_args['flavor_alt_name'] = str(self.flavor_alt.name)
108 task_args['glance_image_location'] = str(self.filename)
109 task_args['glance_image_format'] = str(self.image_format)
110 task_args['tmpl_dir'] = str(self.TEMPLATE_DIR)
111 task_args['sup_dir'] = str(self.SUPPORT_DIR)
112 task_args['users_amount'] = self.USERS_AMOUNT
113 task_args['tenants_amount'] = self.TENANTS_AMOUNT
114 task_args['use_existing_users'] = False
115 task_args['iterations'] = self.ITERATIONS_AMOUNT
116 task_args['concurrency'] = self.CONCURRENCY
117 task_args['smoke'] = self.smoke
118 task_args['volume_version'] = self.VOLUME_VERSION
119 task_args['volume_service_type'] = self.VOLUME_SERVICE_TYPE
122 task_args['floating_network'] = str(self.ext_net.name)
124 task_args['floating_network'] = ''
127 task_args['netid'] = str(self.network.id)
129 task_args['netid'] = ''
133 def _prepare_test_list(self, test_name):
134 """Build the list of test cases to be executed."""
135 test_yaml_file_name = 'opnfv-{}.yaml'.format(test_name)
136 scenario_file_name = os.path.join(self.RALLY_SCENARIO_DIR,
139 if not os.path.exists(scenario_file_name):
140 scenario_file_name = os.path.join(self.scenario_dir,
143 if not os.path.exists(scenario_file_name):
144 raise Exception("The scenario '%s' does not exist."
145 % scenario_file_name)
147 LOGGER.debug('Scenario fetched from : %s', scenario_file_name)
148 test_file_name = os.path.join(self.TEMP_DIR, test_yaml_file_name)
150 if not os.path.exists(self.TEMP_DIR):
151 os.makedirs(self.TEMP_DIR)
153 self.apply_blacklist(scenario_file_name, test_file_name)
154 return test_file_name
157 def get_verifier_deployment_id():
159 Returns deployment id for active Rally deployment
161 cmd = ("rally deployment list | awk '/" +
162 getattr(config.CONF, 'rally_deployment_name') +
164 proc = subprocess.Popen(cmd, shell=True,
165 stdout=subprocess.PIPE,
166 stderr=subprocess.STDOUT)
167 deployment_uuid = proc.stdout.readline().rstrip()
168 return deployment_uuid
171 def create_rally_deployment(environ=None):
172 """Create new rally deployment"""
173 # set the architecture to default
174 pod_arch = env.get("POD_ARCH")
175 arch_filter = ['aarch64']
177 if pod_arch and pod_arch in arch_filter:
178 LOGGER.info("Apply aarch64 specific to rally config...")
179 with open(RallyBase.RALLY_AARCH64_PATCH_PATH, "r") as pfile:
180 rally_patch_conf = pfile.read()
182 for line in fileinput.input(RallyBase.RALLY_CONF_PATH):
184 if "cirros|testvm" in line:
185 print(rally_patch_conf)
187 LOGGER.info("Creating Rally environment...")
189 cmd = ['rally', 'deployment', 'destroy',
191 str(getattr(config.CONF, 'rally_deployment_name'))]
192 output = subprocess.check_output(cmd)
193 LOGGER.info("%s\n%s", " ".join(cmd), output)
194 except subprocess.CalledProcessError:
197 cmd = ['rally', 'deployment', 'create', '--fromenv',
198 '--name', str(getattr(config.CONF, 'rally_deployment_name'))]
199 output = subprocess.check_output(cmd, env=environ)
200 LOGGER.info("%s\n%s", " ".join(cmd), output)
202 cmd = ['rally', 'deployment', 'check']
203 output = subprocess.check_output(cmd)
204 LOGGER.info("%s\n%s", " ".join(cmd), output)
205 return RallyBase.get_verifier_deployment_id()
208 def update_keystone_default_role(rally_conf='/etc/rally/rally.conf'):
209 """Set keystone_default_role in rally.conf"""
210 if env.get("NEW_USER_ROLE").lower() != "member":
211 rconfig = configparser.RawConfigParser()
212 rconfig.read(rally_conf)
213 if not rconfig.has_section('openstack'):
214 rconfig.add_section('openstack')
216 'openstack', 'keystone_default_role', env.get("NEW_USER_ROLE"))
217 with open(rally_conf, 'wb') as config_file:
218 rconfig.write(config_file)
221 def clean_rally_conf(rally_conf='/etc/rally/rally.conf'):
222 """Clean Rally config"""
223 if env.get("NEW_USER_ROLE").lower() != "member":
224 rconfig = configparser.RawConfigParser()
225 rconfig.read(rally_conf)
226 if rconfig.has_option('openstack', 'keystone_default_role'):
227 rconfig.remove_option('openstack', 'keystone_default_role')
228 with open(rally_conf, 'wb') as config_file:
229 rconfig.write(config_file)
232 def get_task_id(cmd_raw):
234 Get task id from command rally result.
237 :return: task_id as string
239 taskid_re = re.compile('^Task +(.*): started$')
240 for line in cmd_raw.splitlines(True):
242 match = taskid_re.match(line)
244 return match.group(1)
248 def task_succeed(json_raw):
250 Parse JSON from rally JSON results.
255 rally_report = json.loads(json_raw)
256 tasks = rally_report.get('tasks')
259 if task.get('status') != 'finished' or \
260 task.get('pass_sla') is not True:
266 def _migration_supported(self):
267 """Determine if migration is supported."""
268 if self.compute_cnt > 1:
272 def _network_trunk_supported(self):
273 """Determine if network trunk service is available"""
274 if 'trunk' in self.network_extensions:
280 """Exclude scenario."""
283 with open(RallyBase.BLACKLIST_FILE, 'r') as black_list_file:
284 black_list_yaml = yaml.safe_load(black_list_file)
286 deploy_scenario = env.get('DEPLOY_SCENARIO')
287 if (bool(deploy_scenario) and
288 'scenario' in black_list_yaml.keys()):
289 for item in black_list_yaml['scenario']:
290 scenarios = item['scenarios']
291 in_it = RallyBase.in_iterable_re
292 if in_it(deploy_scenario, scenarios):
293 tests = item['tests']
294 black_tests.extend(tests)
295 except Exception: # pylint: disable=broad-except
296 LOGGER.debug("Scenario exclusion not applied.")
301 def in_iterable_re(needle, haystack):
303 Check if given needle is in the iterable haystack, using regex.
305 :param needle: string to be matched
306 :param haystack: iterable of strings (optionally regex patterns)
307 :return: True if needle is eqial to any of the elements in haystack,
308 or if a nonempty regex pattern in haystack is found in needle.
310 # match without regex
311 if needle in haystack:
314 for pattern in haystack:
315 # match if regex pattern is set and found in the needle
316 if pattern and re.search(pattern, needle) is not None:
322 """Exclude functionalities."""
327 with open(RallyBase.BLACKLIST_FILE, 'r') as black_list_file:
328 black_list_yaml = yaml.safe_load(black_list_file)
330 if not self._migration_supported():
331 func_list.append("no_migration")
332 if not self._network_trunk_supported():
333 func_list.append("no_net_trunk_service")
335 if 'functionality' in black_list_yaml.keys():
336 for item in black_list_yaml['functionality']:
337 functions = item['functions']
338 for func in func_list:
339 if func in functions:
340 tests = item['tests']
341 black_tests.extend(tests)
342 except Exception: # pylint: disable=broad-except
343 LOGGER.debug("Functionality exclusion not applied.")
347 def apply_blacklist(self, case_file_name, result_file_name):
348 """Apply blacklist."""
349 LOGGER.debug("Applying blacklist...")
350 cases_file = open(case_file_name, 'r')
351 result_file = open(result_file_name, 'w')
353 black_tests = list(set(self.excl_func() +
354 self.excl_scenario()))
357 LOGGER.debug("Blacklisted tests: %s", str(black_tests))
360 for cases_line in cases_file:
362 for black_tests_line in black_tests:
363 if re.search(black_tests_line,
364 cases_line.strip().rstrip(':')):
368 result_file.write(str(cases_line))
370 if cases_line.isspace():
377 def file_is_empty(file_name):
378 """Determine is a file is empty."""
380 if os.stat(file_name).st_size > 0:
382 except Exception: # pylint: disable=broad-except
387 def _save_results(self, test_name, task_id):
388 """ Generate and save task execution results"""
389 # check for result directory and create it otherwise
390 if not os.path.exists(self.results_dir):
391 LOGGER.debug('%s does not exist, we create it.',
393 os.makedirs(self.results_dir)
395 # put detailed result to log
396 cmd = (["rally", "task", "detailed", "--uuid", task_id])
397 LOGGER.debug('running command: %s', cmd)
398 output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
399 LOGGER.info("%s\n%s", " ".join(cmd), output)
401 # save report as JSON
402 report_json_name = '{}.json'.format(test_name)
403 report_json_dir = os.path.join(self.results_dir, report_json_name)
404 cmd = (["rally", "task", "report", "--json", "--uuid", task_id,
405 "--out", report_json_dir])
406 LOGGER.debug('running command: %s', cmd)
407 output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
408 LOGGER.info("%s\n%s", " ".join(cmd), output)
410 json_results = open(report_json_dir).read()
411 self._append_summary(json_results, test_name)
413 # parse JSON operation result
414 if self.task_succeed(json_results):
415 LOGGER.info('Test scenario: "%s" OK.', test_name)
417 LOGGER.info('Test scenario: "%s" Failed.', test_name)
419 def run_task(self, test_name):
421 LOGGER.info('Starting test scenario "%s" ...', test_name)
422 LOGGER.debug('running command: %s', self.run_cmd)
423 proc = subprocess.Popen(self.run_cmd, stdout=subprocess.PIPE,
424 stderr=subprocess.STDOUT)
425 output = proc.communicate()[0]
427 task_id = self.get_task_id(output)
428 LOGGER.debug('task_id : %s', task_id)
430 LOGGER.error("Failed to retrieve task_id")
431 LOGGER.error("Result:\n%s", output)
432 raise Exception("Failed to retrieve task id")
433 self._save_results(test_name, task_id)
435 def _append_summary(self, json_raw, test_name):
436 """Update statistics summary info."""
439 overall_duration = 0.0
443 rally_report = json.loads(json_raw)
444 for task in rally_report.get('tasks'):
445 for subtask in task.get('subtasks'):
447 for workload in subtask.get('workloads'):
448 if workload.get('full_duration'):
449 overall_duration += workload.get('full_duration')
451 if workload.get('data'):
452 nb_tests += len(workload.get('data'))
454 for result in workload.get('data'):
455 if not result.get('error'):
461 failures.append(subtask['title'])
463 success.append(subtask['title'])
465 scenario_summary = {'test_name': test_name,
466 'overall_duration': overall_duration,
467 'nb_tests': nb_tests,
468 'nb_success': nb_success,
470 'failures': failures,
471 'task_status': self.task_succeed(json_raw)}
472 self.summary.append(scenario_summary)
474 def prepare_run(self, **kwargs):
475 """Prepare resources needed by test scenarios."""
477 LOGGER.debug('Validating run tests...')
478 for test in kwargs.get('tests', self.TESTS):
479 if test in self.TESTS:
480 self.tests.append(test)
482 raise Exception("Test name '%s' is invalid" % test)
484 if not os.path.exists(self.TASK_DIR):
485 os.makedirs(self.TASK_DIR)
487 task = os.path.join(self.RALLY_DIR, 'task.yaml')
488 if not os.path.exists(task):
489 LOGGER.error("Task file '%s' does not exist.", task)
490 raise Exception("Task file '{}' does not exist.".
492 self.task_file = os.path.join(self.TASK_DIR, 'task.yaml')
493 shutil.copyfile(task, self.task_file)
495 task_macro = os.path.join(self.RALLY_DIR, 'macro')
496 if not os.path.exists(task_macro):
497 LOGGER.error("Task macro dir '%s' does not exist.", task_macro)
498 raise Exception("Task macro dir '{}' does not exist.".
500 macro_dir = os.path.join(self.TASK_DIR, 'macro')
501 if os.path.exists(macro_dir):
502 shutil.rmtree(macro_dir)
503 shutil.copytree(task_macro, macro_dir)
505 self.update_keystone_default_role()
506 self.compute_cnt = len(self.cloud.list_hypervisors())
507 self.network_extensions = self.cloud.get_network_extensions()
508 self.flavor_alt = self.create_flavor_alt()
509 self.services = [service.name for service in
510 self.cloud.list_services()]
512 LOGGER.debug("flavor: %s", self.flavor_alt)
514 def prepare_task(self, test_name):
515 """Prepare resources for test run."""
516 file_name = self._prepare_test_list(test_name)
517 if self.file_is_empty(file_name):
518 LOGGER.info('No tests for scenario "%s"', test_name)
520 self.run_cmd = (["rally", "task", "start", "--abort-on-sla-failure",
521 "--task", self.task_file, "--task-args",
522 str(self.build_task_args(test_name))])
525 def run_tests(self, **kwargs):
527 optional = kwargs.get('optional', [])
528 for test in self.tests:
529 if test in self.services or test not in optional:
530 if self.prepare_task(test):
533 def _generate_report(self):
534 """Generate test execution summary report."""
541 res_table = prettytable.PrettyTable(
543 field_names=['Module', 'Duration', 'nb. Test Run', 'Success'])
544 res_table.align['Module'] = "l"
545 res_table.align['Duration'] = "r"
546 res_table.align['Success'] = "r"
548 # for each scenario we draw a row for the table
549 for item in self.summary:
550 if item['task_status'] is True:
552 total_duration += item['overall_duration']
553 total_nb_tests += item['nb_tests']
554 total_nb_success += item['nb_success']
556 success_avg = 100 * item['nb_success'] / item['nb_tests']
557 except ZeroDivisionError:
559 success_str = str("{:0.2f}".format(success_avg)) + '%'
560 duration_str = time.strftime("%H:%M:%S",
561 time.gmtime(item['overall_duration']))
562 res_table.add_row([item['test_name'], duration_str,
563 item['nb_tests'], success_str])
564 payload.append({'module': item['test_name'],
565 'details': {'duration': item['overall_duration'],
566 'nb tests': item['nb_tests'],
567 'success rate': success_str,
568 'success': item['success'],
569 'failures': item['failures']}})
571 total_duration_str = time.strftime("%H:%M:%S",
572 time.gmtime(total_duration))
574 self.result = 100 * total_nb_success / total_nb_tests
575 except ZeroDivisionError:
577 success_rate = "{:0.2f}".format(self.result)
578 success_rate_str = str(success_rate) + '%'
579 res_table.add_row(["", "", "", ""])
580 res_table.add_row(["TOTAL:", total_duration_str, total_nb_tests,
583 LOGGER.info("Rally Summary Report:\n\n%s\n", res_table.get_string())
584 LOGGER.info("Rally '%s' success_rate is %s%% in %s/%s modules",
585 self.case_name, success_rate, nb_modules,
587 payload.append({'summary': {'duration': total_duration,
588 'nb tests': total_nb_tests,
589 'nb success': success_rate}})
590 self.details = payload
593 def export_task(file_name, export_type="html"):
594 """Export all task results (e.g. html or xunit report)
597 subprocess.CalledProcessError: if Rally doesn't return 0
602 cmd = ["rally", "task", "export", "--type", export_type,
604 str(getattr(config.CONF, 'rally_deployment_name')),
606 LOGGER.debug('running command: %s', cmd)
607 output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
608 LOGGER.info("%s\n%s", " ".join(cmd), output)
611 def verify_report(file_name, uuid, export_type="html"):
612 """Generate the verifier report (e.g. html or xunit report)
615 subprocess.CalledProcessError: if Rally doesn't return 0
620 cmd = ["rally", "verify", "report", "--type", export_type,
621 "--uuid", uuid, "--to", file_name]
622 LOGGER.debug('running command: %s', cmd)
623 output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
624 LOGGER.info("%s\n%s", " ".join(cmd), output)
627 """Cleanup of OpenStack resources. Should be called on completion."""
628 self.clean_rally_conf()
630 self.orig_cloud.delete_flavor(self.flavor_alt.id)
631 super(RallyBase, self).clean()
633 def is_successful(self):
634 """The overall result of the test."""
635 for item in self.summary:
636 if item['task_status'] is False:
637 return testcase.TestCase.EX_TESTCASE_FAILED
639 return super(RallyBase, self).is_successful()
641 def run(self, **kwargs):
643 self.start_time = time.time()
645 assert super(RallyBase, self).run(
646 **kwargs) == testcase.TestCase.EX_OK
649 OS_USERNAME=self.project.user.name,
650 OS_PROJECT_NAME=self.project.project.name,
651 OS_PROJECT_ID=self.project.project.id,
652 OS_PASSWORD=self.project.password)
654 del environ['OS_TENANT_NAME']
655 del environ['OS_TENANT_ID']
656 except Exception: # pylint: disable=broad-except
658 self.create_rally_deployment(environ=environ)
659 self.prepare_run(**kwargs)
660 self.run_tests(**kwargs)
661 self._generate_report()
663 "{}/{}.html".format(self.results_dir, self.case_name))
665 "{}/{}.xml".format(self.results_dir, self.case_name),
666 export_type="junit-xml")
667 res = testcase.TestCase.EX_OK
668 except Exception as exc: # pylint: disable=broad-except
669 LOGGER.error('Error with run: %s', exc)
671 res = testcase.TestCase.EX_RUN_ERROR
672 self.stop_time = time.time()
676 class RallySanity(RallyBase):
677 """Rally sanity testcase implementation."""
679 def __init__(self, **kwargs):
680 """Initialize RallySanity object."""
681 if "case_name" not in kwargs:
682 kwargs["case_name"] = "rally_sanity"
683 super(RallySanity, self).__init__(**kwargs)
685 self.scenario_dir = os.path.join(self.RALLY_SCENARIO_DIR, 'sanity')
688 class RallyFull(RallyBase):
689 """Rally full testcase implementation."""
691 def __init__(self, **kwargs):
692 """Initialize RallyFull object."""
693 if "case_name" not in kwargs:
694 kwargs["case_name"] = "rally_full"
695 super(RallyFull, self).__init__(**kwargs)
697 self.scenario_dir = os.path.join(self.RALLY_SCENARIO_DIR, 'full')
700 class RallyJobs(RallyBase):
701 """Rally OpenStack CI testcase implementation."""
705 def __init__(self, **kwargs):
706 """Initialize RallyJobs object."""
707 if "case_name" not in kwargs:
708 kwargs["case_name"] = "rally_jobs"
709 super(RallyJobs, self).__init__(**kwargs)
710 self.task_file = os.path.join(self.RALLY_DIR, 'rally_jobs.yaml')
711 self.task_yaml = None
713 def prepare_run(self, **kwargs):
714 """Create resources needed by test scenarios."""
715 super(RallyJobs, self).prepare_run(**kwargs)
716 with open(os.path.join(self.RALLY_DIR,
717 'rally_jobs.yaml'), 'r') as task_file:
718 self.task_yaml = yaml.safe_load(task_file)
720 for task in self.task_yaml:
721 if task not in self.tests:
722 raise Exception("Test '%s' not in '%s'" %
725 def apply_blacklist(self, case_file_name, result_file_name):
726 # pylint: disable=too-many-branches
727 """Apply blacklist."""
728 LOGGER.debug("Applying blacklist...")
729 black_tests = list(set(self.excl_func() +
730 self.excl_scenario()))
732 LOGGER.debug("Blacklisted tests: %s", str(black_tests))
734 template = YAML(typ='jinja2')
735 with open(case_file_name, 'r') as fname:
736 cases = template.load(fname)
737 if cases.get("version", 1) == 1:
738 # scenarios in dictionary
739 for name in cases.keys():
740 if self.in_iterable_re(name, black_tests):
743 # workloads in subtasks
744 for sind, subtask in enumerate(cases.get('subtasks', [])):
746 for wind, workload in enumerate(subtask.get('workloads', [])):
747 scenario = workload.get('scenario', {})
748 for name in scenario.keys():
749 if self.in_iterable_re(name, black_tests):
752 for wind in reversed(idx):
753 cases['subtasks'][sind]['workloads'].pop(wind)
754 # scenarios in subtasks
756 for sind, subtask in enumerate(cases.get('subtasks', [])):
757 scenario = subtask.get('scenario', {})
758 for name in scenario.keys():
759 if self.in_iterable_re(name, black_tests):
762 for sind in reversed(idx):
763 cases['subtasks'].pop(sind)
765 with open(result_file_name, 'w') as fname:
766 template.dump(cases, fname)
768 def build_task_args(self, test_name):
769 """Build arguments for the Rally task."""
772 task_args['floating_network'] = str(self.ext_net.name)
774 task_args['floating_network'] = ''
778 def _remove_plugins_extra():
779 inst_dir = getattr(config.CONF, 'dir_rally_inst')
781 shutil.rmtree(os.path.join(inst_dir, 'plugins'))
782 shutil.rmtree(os.path.join(inst_dir, 'extra'))
783 except Exception: # pylint: disable=broad-except
786 def prepare_task(self, test_name):
787 """Prepare resources for test run."""
788 self._remove_plugins_extra()
789 jobs_dir = os.path.join(
790 getattr(config.CONF, 'dir_rally_data'), test_name, 'rally-jobs')
791 inst_dir = getattr(config.CONF, 'dir_rally_inst')
792 shutil.copytree(os.path.join(jobs_dir, 'plugins'),
793 os.path.join(inst_dir, 'plugins'))
794 shutil.copytree(os.path.join(jobs_dir, 'extra'),
795 os.path.join(inst_dir, 'extra'))
797 task_name = self.task_yaml.get(test_name).get("task")
798 task = os.path.join(jobs_dir, task_name)
799 if not os.path.exists(task):
800 raise Exception("The scenario '%s' does not exist." % task)
801 LOGGER.debug('Scenario fetched from : %s', task)
803 if not os.path.exists(self.TEMP_DIR):
804 os.makedirs(self.TEMP_DIR)
805 task_file_name = os.path.join(self.TEMP_DIR, task_name)
806 self.apply_blacklist(task, task_file_name)
807 self.run_cmd = (["rally", "task", "start", "--task", task_file_name,
808 "--task-args", str(self.build_task_args(test_name))])
812 self._remove_plugins_extra()
813 super(RallyJobs, self).clean()