def test_display_published_is_true_by_default(self, _): action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack) expected_published_values = { 't1_publish_param_1': 'foo1', 't1_publish_param_2': 'foo2', 't1_publish_param_3': 'foo3', 't2_publish_param_1': 'foo4', 't2_publish_param_2': 'foo5', 't2_publish_param_3': 'foo6', 'publish_last_wins': 'bar_last', } # 1. display_published is True by default chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_WITH_PUBLISH_2 chain_runner.action = ACTION_2 chain_runner.liveaction = LiveActionDB(action=action_ref) chain_runner.container_service = RunnerContainerService() chain_runner.runner_parameters = {} chain_runner.pre_run() action_parameters = {} _, result, _ = chain_runner.run(action_parameters=action_parameters) # Assert that the variables are correctly published self.assertEqual(result['published'], expected_published_values) # 2. display_published is True by default so end result should be the same chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_WITH_PUBLISH_2 chain_runner.action = ACTION_2 chain_runner.liveaction = LiveActionDB(action=action_ref) chain_runner.container_service = RunnerContainerService() chain_runner.runner_parameters = {'display_published': True} chain_runner.pre_run() action_parameters = {} _, result, _ = chain_runner.run(action_parameters=action_parameters) # Assert that the variables are correctly published self.assertEqual(result['published'], expected_published_values) # 3. display_published is disabled chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_WITH_PUBLISH_2 chain_runner.action = ACTION_2 chain_runner.liveaction = LiveActionDB(action=action_ref) chain_runner.container_service = RunnerContainerService() chain_runner.runner_parameters = {'display_published': False} chain_runner.pre_run() action_parameters = {} _, result, _ = chain_runner.run(action_parameters=action_parameters) self.assertTrue('published' not in result) self.assertEqual(result.get('published', {}), {})
def test_chain_runner_chain_second_task_times_out(self, request): # Second task in the chain times out so the action chain status should be timeout chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_2_PATH chain_runner.action = ACTION_1 original_run_action = chain_runner._run_action def mock_run_action(*args, **kwargs): original_live_action = args[0] liveaction = original_run_action(*args, **kwargs) if original_live_action.action == 'wolfpack.a2': # Mock a timeout for second task liveaction.status = LIVEACTION_STATUS_TIMED_OUT return liveaction chain_runner._run_action = mock_run_action action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) chain_runner.liveaction = LiveActionDB(action=action_ref) chain_runner.container_service = RunnerContainerService() chain_runner.pre_run() status, _, _ = chain_runner.run({}) self.assertEqual(status, LIVEACTION_STATUS_TIMED_OUT) self.assertNotEqual(chain_runner.chain_holder.actionchain, None) # based on the chain the callcount is known to be 3. Not great but works. self.assertEqual(request.call_count, 3)
def _get_runner(action_db, entry_point=None, cmd=None, on_behalf_user=None, user=None, kwarg_op=local_runner.DEFAULT_KWARG_OP, timeout=LOCAL_RUNNER_DEFAULT_ACTION_TIMEOUT, sudo=False, env=None): runner = local_runner.LocalShellRunner(uuid.uuid4().hex) runner.container_service = RunnerContainerService() runner.execution = MOCK_EXECUTION runner.action = action_db runner.action_name = action_db.name runner.liveaction_id = uuid.uuid4().hex runner.entry_point = entry_point runner.runner_parameters = { local_runner.RUNNER_COMMAND: cmd, local_runner.RUNNER_SUDO: sudo, local_runner.RUNNER_ENV: env, local_runner.RUNNER_ON_BEHALF_USER: user, local_runner.RUNNER_KWARG_OP: kwarg_op, local_runner.RUNNER_TIMEOUT: timeout } runner.context = dict() runner.callback = dict() runner.libs_dir_path = None runner.auth_token = mock.Mock() runner.auth_token.token = 'mock-token' return runner
def test_chain_runner_failure_during_param_rendering_multiple_tasks( self, request): # Parameter rendering should result in a top level error which aborts # the whole chain chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_SECOND_TASK_RENDER_FAIL_PATH chain_runner.action = ACTION_1 chain_runner.container_service = RunnerContainerService() chain_runner.pre_run() status, result, _ = chain_runner.run({}) # Verify that only first task has ran self.assertEqual(status, LIVEACTION_STATUS_FAILED) self.assertEqual(len(result['tasks']), 1) self.assertEqual(result['tasks'][0]['name'], 'c1') expected_error = ( 'Failed rendering value for action parameter "p1" in ' 'task "c2" (template string={{s1}}):') self.assertTrue('error' in result) self.assertTrue('traceback' in result) self.assertTrue('Failed to run task "c2". Parameter rendering failed' in result['error']) self.assertTrue(expected_error in result['error']) self.assertTrue('Traceback' in result['traceback'])
def invoke_post_run(liveaction_db, action_db=None): LOG.info('Invoking post run for action execution %s.', liveaction_db.id) # Identify action and runner. if not action_db: action_db = action_db_utils.get_action_by_ref(liveaction_db.action) if not action_db: LOG.exception('Unable to invoke post run. Action %s no longer exists.', liveaction_db.action) return LOG.info('Action execution %s runs %s of runner type %s.', liveaction_db.id, action_db.name, action_db.runner_type['name']) # Get an instance of the action runner. runnertype_db = action_db_utils.get_runnertype_by_name( action_db.runner_type['name']) runner = runners.get_runner(runnertype_db.runner_module) # Configure the action runner. runner.container_service = RunnerContainerService() runner.action = action_db runner.action_name = action_db.name runner.action_execution_id = str(liveaction_db.id) runner.entry_point = RunnerContainerService.get_entry_point_abs_path( pack=action_db.pack, entry_point=action_db.entry_point) runner.context = getattr(liveaction_db, 'context', dict()) runner.callback = getattr(liveaction_db, 'callback', dict()) runner.libs_dir_path = RunnerContainerService.get_action_libs_abs_path( pack=action_db.pack, entry_point=action_db.entry_point) # Invoke the post_run method. runner.post_run(liveaction_db.status, liveaction_db.result)
def __init__(self, empty_q_sleep_time=5, no_workers_sleep_time=1, container_service=None): # Let's check to see if deprecated config group ``results_tracker`` is being used. try: query_interval = cfg.CONF.results_tracker.query_interval LOG.warning('You are using deprecated config group ``results_tracker``.' + '\nPlease use ``resultstracker`` group instead.') except: pass try: thread_pool_size = cfg.CONF.results_tracker.thread_pool_size LOG.warning('You are using deprecated config group ``results_tracker``.' + '\nPlease use ``resultstracker`` group instead.') except: pass if not query_interval: query_interval = cfg.CONF.resultstracker.query_interval if not thread_pool_size: thread_pool_size = cfg.CONF.resultstracker.thread_pool_size self._query_thread_pool_size = thread_pool_size self._query_interval = query_interval self._query_contexts = Queue.Queue() self._thread_pool = eventlet.GreenPool(self._query_thread_pool_size) self._empty_q_sleep_time = empty_q_sleep_time self._no_workers_sleep_time = no_workers_sleep_time if not container_service: container_service = RunnerContainerService() self.container_service = container_service self._started = False
def _get_runner(self, runnertype_db, action_db, liveaction_db): runner = get_runner(runnertype_db.runner_module) resolved_entry_point = self._get_entry_point_abs_path(action_db.pack, action_db.entry_point) runner.runner_type_db = runnertype_db runner.container_service = RunnerContainerService() runner.action = action_db runner.action_name = action_db.name runner.liveaction = liveaction_db runner.liveaction_id = str(liveaction_db.id) runner.execution = ActionExecution.get(liveaction__id=runner.liveaction_id) runner.execution_id = str(runner.execution.id) runner.entry_point = resolved_entry_point runner.context = getattr(liveaction_db, 'context', dict()) runner.callback = getattr(liveaction_db, 'callback', dict()) runner.libs_dir_path = self._get_action_libs_abs_path(action_db.pack, action_db.entry_point) # For re-run, get the ActionExecutionDB in which the re-run is based on. rerun_ref_id = runner.context.get('re-run', {}).get('ref') runner.rerun_ex_ref = ActionExecution.get(id=rerun_ref_id) if rerun_ref_id else None return runner
def test_chain_runner_publish(self, request): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_WITH_PUBLISH chain_runner.action = ACTION_2 chain_runner.container_service = RunnerContainerService() chain_runner.runner_parameters = {'display_published': True} chain_runner.pre_run() action_parameters = {'action_param_1': 'test value 1'} _, result, _ = chain_runner.run(action_parameters=action_parameters) # We also assert that the action parameters are available in the # "publish" scope self.assertNotEqual(chain_runner.chain_holder.actionchain, None) expected_value = { 'inttype': 1, 'strtype': 'published', 'booltype': True, 'published_action_param': action_parameters['action_param_1'] } mock_args, _ = request.call_args self.assertEqual(mock_args[0].parameters, expected_value) # Assert that the variables are correctly published self.assertEqual(result['published'], { 'published_action_param': u'test value 1', 'o1': u'published' })
def test_chain_runner_task_is_canceled_while_running(self, request): # Second task in the action is CANCELED, make sure runner doesn't get stuck in an infinite # loop chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_2_PATH chain_runner.action = ACTION_1 original_run_action = chain_runner._run_action def mock_run_action(*args, **kwargs): original_live_action = args[0] if original_live_action.action == 'wolfpack.a2': status = LIVEACTION_STATUS_CANCELED else: status = LIVEACTION_STATUS_SUCCEEDED request.return_value = (DummyActionExecution(status=status), None) liveaction = original_run_action(*args, **kwargs) return liveaction chain_runner._run_action = mock_run_action action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) chain_runner.liveaction = LiveActionDB(action=action_ref) chain_runner.container_service = RunnerContainerService() chain_runner.pre_run() status, _, _ = chain_runner.run({}) self.assertEqual(status, LIVEACTION_STATUS_CANCELED) self.assertNotEqual(chain_runner.chain_holder.actionchain, None) # Chain count should be 2 since the last task doesn't get called since the second one was # canceled self.assertEqual(request.call_count, 2)
def test_chain_runner_bad_default(self, request): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_BAD_DEFAULT chain_runner.action = ACTION_1 chain_runner.container_service = RunnerContainerService() expected_msg = 'Unable to find node with name "bad_default" referenced in "default".' self.assertRaisesRegexp(runnerexceptions.ActionRunnerPreRunError, expected_msg, chain_runner.pre_run)
def test_params_and_parameters_attributes_both_work(self, _): # "params" attribute used chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_ACTION_PARAMS_ATTRIBUTE chain_runner.action = ACTION_2 chain_runner.container_service = RunnerContainerService() chain_runner.pre_run() original_build_liveaction_object = chain_runner._build_liveaction_object def mock_build_liveaction_object(action_node, resolved_params, parent_context): # Verify parameters are correctly passed to the action self.assertEqual(resolved_params, {'pparams': 'v1'}) original_build_liveaction_object(action_node=action_node, resolved_params=resolved_params, parent_context=parent_context) chain_runner._build_liveaction_object = mock_build_liveaction_object action_parameters = {} status, output, _ = chain_runner.run( action_parameters=action_parameters) self.assertEqual(status, LIVEACTION_STATUS_SUCCEEDED) # "parameters" attribute used chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_ACTION_PARAMETERS_ATTRIBUTE chain_runner.action = ACTION_2 chain_runner.container_service = RunnerContainerService() chain_runner.pre_run() def mock_build_liveaction_object(action_node, resolved_params, parent_context): # Verify parameters are correctly passed to the action self.assertEqual(resolved_params, {'pparameters': 'v1'}) original_build_liveaction_object(action_node=action_node, resolved_params=resolved_params, parent_context=parent_context) chain_runner._build_liveaction_object = mock_build_liveaction_object action_parameters = {} status, output, _ = chain_runner.run( action_parameters=action_parameters) self.assertEqual(status, LIVEACTION_STATUS_SUCCEEDED)
def test_chain_runner_missing_param_temp(self, schedule): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_STR_TEMP_PATH chain_runner.action = ACTION_1 chain_runner.container_service = RunnerContainerService() chain_runner.pre_run() chain_runner.run({}) self.assertEqual(schedule.call_count, 0, 'No call expected.')
def test_chain_runner_missing_param_temp(self, request): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_FIRST_TASK_RENDER_FAIL_PATH chain_runner.action = ACTION_1 chain_runner.container_service = RunnerContainerService() chain_runner.pre_run() chain_runner.run({}) self.assertEqual(request.call_count, 0, 'No call expected.')
def test_get_entry_point_absolute_path(self): service = RunnerContainerService() orig_path = cfg.CONF.content.packs_base_path cfg.CONF.content.packs_base_path = '/tests/packs' acutal_path = service.get_entry_point_abs_path( pack='foo', entry_point='/foo/bar.py') self.assertEqual(acutal_path, '/foo/bar.py', 'Entry point path doesn\'t match.') cfg.CONF.content.packs_base_path = orig_path
def test_chain_runner_broken_on_failure_path_static_task_name(self, request): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_BROKEN_ON_FAILURE_PATH_STATIC_TASK_NAME chain_runner.action = ACTION_1 chain_runner.container_service = RunnerContainerService() expected_msg = ('Unable to find node with name "c6" referenced in "on-failure" ' 'in task "c2"') self.assertRaisesRegexp(runnerexceptions.ActionRunnerPreRunError, expected_msg, chain_runner.pre_run)
def test_chain_runner_str_param_temp(self, schedule): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_FIRST_TASK_RENDER_FAIL_PATH chain_runner.action = ACTION_1 chain_runner.container_service = RunnerContainerService() chain_runner.pre_run() chain_runner.run({'s1': 1, 's2': 2, 's3': 3, 's4': 4}) self.assertNotEqual(chain_runner.chain_holder.actionchain, None) mock_args, _ = schedule.call_args self.assertEqual(mock_args[0].parameters, {"p1": "1"})
def test_chain_runner_action_exception(self, schedule): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_1_PATH chain_runner.action = DummyAction() chain_runner.container_service = RunnerContainerService() chain_runner.pre_run() chain_runner.run({}) self.assertNotEqual(chain_runner.action_chain, None) # based on the chain the callcount is known to be 2. Not great but works. self.assertEqual(schedule.call_count, 2)
def test_exception_is_thrown_if_both_params_and_parameters_attributes_are_provided(self): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_ACTION_PARAMS_AND_PARAMETERS_ATTRIBUTE chain_runner.action = ACTION_2 chain_runner.container_service = RunnerContainerService() expected_msg = ('Either "params" or "parameters" attribute needs to be provided, but ' 'not both') self.assertRaisesRegexp(runnerexceptions.ActionRunnerPreRunError, expected_msg, chain_runner.pre_run)
def test_chain_runner_missing_param_temp(self, request): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_FIRST_TASK_RENDER_FAIL_PATH chain_runner.action = ACTION_1 action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) chain_runner.liveaction = LiveActionDB(action=action_ref) chain_runner.container_service = RunnerContainerService() chain_runner.pre_run() chain_runner.run({}) self.assertEqual(request.call_count, 0, 'No call expected.')
def test_chain_runner_str_param_temp(self, schedule): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_STR_TEMP_PATH chain_runner.action = DummyAction() chain_runner.container_service = RunnerContainerService() chain_runner.pre_run() chain_runner.run({'s1': 1, 's2': 2, 's3': 3, 's4': 4}) self.assertNotEqual(chain_runner.action_chain, None) mock_args, _ = schedule.call_args self.assertEqual(mock_args[0].parameters, {"p1": "1"})
def test_chain_runner_list_param_temp(self, request): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_LIST_TEMP_PATH chain_runner.action = ACTION_1 chain_runner.container_service = RunnerContainerService() chain_runner.pre_run() chain_runner.run({'s1': 1, 's2': 2, 's3': 3, 's4': 4}) self.assertNotEqual(chain_runner.chain_holder.actionchain, None) mock_args, _ = request.call_args self.assertEqual(mock_args[0].parameters, {"p1": "[2, 3, 4]"})
def test_chain_runner_success_path_with_wait(self, request): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_1_PATH chain_runner.action = ACTION_1 chain_runner.container_service = RunnerContainerService() chain_runner.pre_run() chain_runner.run({}) self.assertNotEqual(chain_runner.chain_holder.actionchain, None) # based on the chain the callcount is known to be 3. Not great but works. self.assertEqual(request.call_count, 3)
def test_malformed_chain(self): try: chain_runner = acr.get_runner() chain_runner.entry_point = MALFORMED_CHAIN_PATH chain_runner.action = ACTION_1 chain_runner.container_service = RunnerContainerService() chain_runner.pre_run() self.assertTrue(False, 'Expected pre_run to fail.') except runnerexceptions.ActionRunnerPreRunError: self.assertTrue(True)
def test_get_entry_point_absolute_path_empty(self): service = RunnerContainerService() orig_path = cfg.CONF.content.system_packs_base_path cfg.CONF.content.system_packs_base_path = '/tests/packs' acutal_path = service.get_entry_point_abs_path(pack='foo', entry_point=None) self.assertEqual(acutal_path, None, 'Entry point path doesn\'t match.') acutal_path = service.get_entry_point_abs_path(pack='foo', entry_point='') self.assertEqual(acutal_path, None, 'Entry point path doesn\'t match.') cfg.CONF.content.system_packs_base_path = orig_path
def test_chain_runner_vars_action_params(self, request): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_WITH_ACTIONPARAM_VARS chain_runner.action = ACTION_2 chain_runner.container_service = RunnerContainerService() chain_runner.pre_run() chain_runner.run({'input_a': 'two'}) self.assertNotEqual(chain_runner.chain_holder.actionchain, None) expected_value = {'inttype': 1, 'strtype': 'two', 'booltype': True} mock_args, _ = request.call_args self.assertEqual(mock_args[0].parameters, expected_value)
def test_chain_runner_dict_param_temp(self, request): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_DICT_TEMP_PATH chain_runner.action = ACTION_1 chain_runner.container_service = RunnerContainerService() chain_runner.pre_run() chain_runner.run({'s1': 1, 's2': 2, 's3': 3, 's4': 4}) self.assertNotEqual(chain_runner.chain_holder.actionchain, None) expected_value = {"p1": {"p1.3": "[3, 4]", "p1.2": "2", "p1.1": "1"}} mock_args, _ = request.call_args self.assertEqual(mock_args[0].parameters, expected_value)
def test_chain_runner_failure_path(self, request): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_1_PATH chain_runner.action = ACTION_1 chain_runner.container_service = RunnerContainerService() chain_runner.pre_run() status, _, _ = chain_runner.run({}) self.assertEqual(status, LIVEACTION_STATUS_FAILED) self.assertNotEqual(chain_runner.chain_holder.actionchain, None) # based on the chain the callcount is known to be 2. Not great but works. self.assertEqual(request.call_count, 2)
def test_get_entry_point_relative_path(self): service = RunnerContainerService() orig_path = cfg.CONF.content.packs_base_path cfg.CONF.content.packs_base_path = '/tests/packs' acutal_path = service.get_entry_point_abs_path( pack='foo', entry_point='foo/bar.py') expected_path = os.path.join(cfg.CONF.content.packs_base_path, 'foo', 'actions', 'foo/bar.py') self.assertEqual(acutal_path, expected_path, 'Entry point path doesn\'t match.') cfg.CONF.content.packs_base_path = orig_path
def test_chain_runner_list_param_temp(self, request): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_LIST_TEMP_PATH chain_runner.action = ACTION_1 action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) chain_runner.liveaction = LiveActionDB(action=action_ref) chain_runner.container_service = RunnerContainerService() chain_runner.pre_run() chain_runner.run({'s1': 1, 's2': 2, 's3': 3, 's4': 4}) self.assertNotEqual(chain_runner.chain_holder.actionchain, None) mock_args, _ = request.call_args self.assertEqual(mock_args[0].parameters, {"p1": "[2, 3, 4]"})
def test_chain_task_passes_invalid_parameter_type_to_action(self, mock_request): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_ACTION_INVALID_PARAMETER_TYPE chain_runner.action = ACTION_2 chain_runner.container_service = RunnerContainerService() chain_runner.pre_run() action_parameters = {} expected_msg = ('Failed to cast value "stringnotanarray" \(type: str\) for parameter ' '"arrtype" of type "array"') self.assertRaisesRegexp(ValueError, expected_msg, chain_runner.run, action_parameters=action_parameters)