def test_update_same_liveaction_status(self): liveaction_db = LiveActionDB() liveaction_db.status = 'requested' liveaction_db.start_timestamp = get_datetime_utc_now() liveaction_db.action = ResourceReference( name=ActionDBUtilsTestCase.action_db.name, pack=ActionDBUtilsTestCase.action_db.pack).ref params = { 'actionstr': 'foo', 'some_key_that_aint_exist_in_action_or_runner': 'bar', 'runnerint': 555 } liveaction_db.parameters = params liveaction_db = LiveAction.add_or_update(liveaction_db) origliveaction_db = copy.copy(liveaction_db) # Update by id. newliveaction_db = action_db_utils.update_liveaction_status( status='requested', liveaction_id=liveaction_db.id) # Verify id didn't change. self.assertEqual(origliveaction_db.id, newliveaction_db.id) self.assertEqual(newliveaction_db.status, 'requested') # Verify that state is not published. self.assertFalse(LiveActionPublisher.publish_state.called)
def setup_action_models(cls): pack = 'wolfpack' name = 'action-1' parameters = { 'actionint': {'type': 'number', 'default': 10, 'position': 0}, 'actionfloat': {'type': 'float', 'required': False, 'position': 1}, 'actionstr': {'type': 'string', 'required': True, 'position': 2}, 'actionbool': {'type': 'boolean', 'required': False, 'position': 3}, 'actionlist': {'type': 'list', 'required': False, 'position': 4}, 'actionobject': {'type': 'object', 'required': False, 'position': 5}, 'actionnull': {'type': 'null', 'required': False, 'position': 6}, 'runnerdummy': {'type': 'string', 'default': 'actiondummy'} } action_db = ActionDB(pack=pack, name=name, description='awesomeness', enabled=True, ref=ResourceReference(name=name, pack=pack).ref, entry_point='', runner_type={'name': 'test-runner'}, parameters=parameters) ActionDBUtilsTestCase.action_db = Action.add_or_update(action_db) liveaction_db = LiveActionDB() liveaction_db.status = 'initializing' liveaction_db.start_timestamp = get_datetime_utc_now() liveaction_db.action = ActionDBUtilsTestCase.action_db.ref params = { 'actionstr': 'foo', 'some_key_that_aint_exist_in_action_or_runner': 'bar', 'runnerint': 555 } liveaction_db.parameters = params ActionDBUtilsTestCase.liveaction_db = LiveAction.add_or_update(liveaction_db)
def post(self, execution_parameters, execution_id): """ Re-run the provided action execution optionally specifying override parameters. Handles requests: POST /executions/<id>/re_run """ parameters = execution_parameters.parameters # Note: We only really need parameters here existing_execution = self._get_one(id=execution_id, exclude_fields=self.exclude_fields) # Merge in any parameters provided by the user new_parameters = copy.deepcopy(existing_execution.parameters) new_parameters.update(parameters) # Create object for the new execution action_ref = existing_execution.action['ref'] new_execution = LiveActionDB() new_execution.action = action_ref new_execution.parameters = new_parameters result = self._handle_schedule_execution(execution=new_execution) return result
def test_process_post_generic_notify_trigger_on_custom_emit_when_states(self, mock_LiveAction, mock_dispatch): # Verify that generic action trigger is posted on all completed states when action sensor # is enabled for status in LIVEACTION_STATUSES: notifier = Notifier(connection=None, queues=[]) liveaction_db = LiveActionDB(id=bson.ObjectId(), action='core.local') liveaction_db.status = status execution = MOCK_EXECUTION execution.liveaction = vars(LiveActionAPI.from_model(liveaction_db)) execution.status = liveaction_db.status mock_LiveAction.get_by_id.return_value = liveaction_db notifier = Notifier(connection=None, queues=[]) notifier.process(execution) if status in ['scheduled', 'pending', 'abandoned']: exp = {'status': status, 'start_timestamp': str(liveaction_db.start_timestamp), 'result': {}, 'parameters': {}, 'action_ref': u'core.local', 'runner_ref': 'local-shell-cmd', 'execution_id': str(MOCK_EXECUTION.id), 'action_name': u'core.local'} mock_dispatch.assert_called_with('core.st2.generic.actiontrigger', payload=exp, trace_context={}) self.assertEqual(mock_dispatch.call_count, 3)
def setup_action_models(cls): action_db = ActionDB() action_db.name = 'action-1' action_db.description = 'awesomeness' action_db.enabled = True action_db.pack = 'wolfpack' action_db.ref = ResourceReference(name=action_db.name, pack=action_db.pack).ref action_db.entry_point = '' action_db.runner_type = {'name': 'test-runner'} action_db.parameters = { 'actionstr': {'type': 'string', 'position': 1, 'required': True}, 'actionint': {'type': 'number', 'default': 10, 'position': 0}, 'runnerdummy': {'type': 'string', 'default': 'actiondummy'} } ActionDBUtilsTestCase.action_db = Action.add_or_update(action_db) liveaction_db = LiveActionDB() liveaction_db.status = 'initializing' liveaction_db.start_timestamp = get_datetime_utc_now() liveaction_db.action = ActionDBUtilsTestCase.action_db.ref params = { 'actionstr': 'foo', 'some_key_that_aint_exist_in_action_or_runner': 'bar', 'runnerint': 555 } liveaction_db.parameters = params ActionDBUtilsTestCase.liveaction_db = LiveAction.add_or_update(liveaction_db)
def _run_action(self, action_node, parent_execution_id, params, wait_for_completion=True): liveaction = LiveActionDB(action=action_node.ref) liveaction.parameters = action_param_utils.cast_params(action_ref=action_node.ref, params=params) # Setup notify for task in chain. notify = self._get_notify(action_node) if notify: liveaction.notify = notify LOG.debug('%s: Task notify set to: %s', action_node.name, liveaction.notify) liveaction.context = { 'parent': str(parent_execution_id), 'chain': vars(action_node) } liveaction, _ = action_service.request(liveaction) while (wait_for_completion and liveaction.status != LIVEACTION_STATUS_SUCCEEDED and liveaction.status != LIVEACTION_STATUS_FAILED): eventlet.sleep(1) liveaction = action_db_util.get_liveaction_by_id(liveaction.id) return liveaction
def _create_inquiry(self, ttl, timestamp): action_db = self.models['actions']['ask.yaml'] liveaction_db = LiveActionDB() liveaction_db.status = action_constants.LIVEACTION_STATUS_PENDING liveaction_db.start_timestamp = timestamp liveaction_db.action = ResourceReference(name=action_db.name, pack=action_db.pack).ref liveaction_db.result = {'ttl': ttl} liveaction_db = LiveAction.add_or_update(liveaction_db) executions.create_execution_object(liveaction_db)
def _get_action_exec_db_model(self, params): liveaction_db = LiveActionDB() liveaction_db.status = 'initializing' liveaction_db.start_timestamp = datetime.datetime.utcnow() liveaction_db.action = ResourceReference(name=ParamsUtilsTest.action_db.name, pack=ParamsUtilsTest.action_db.pack).ref liveaction_db.parameters = params return liveaction_db
def _get_execution_db_model(self, status=action_constants.LIVEACTION_STATUS_REQUESTED): live_action_db = LiveActionDB() live_action_db.status = status live_action_db.start_timestamp = date_utils.get_datetime_utc_now() live_action_db.action = ResourceReference( name='test_action', pack='test_pack').ref live_action_db.parameters = None return action.LiveAction.add_or_update(live_action_db, publish=False)
def _get_liveaction_model(self, params): status = 'initializing' start_timestamp = date_utils.get_datetime_utc_now() action_ref = ResourceReference(name=ParamsUtilsTest.action_db.name, pack=ParamsUtilsTest.action_db.pack).ref liveaction_db = LiveActionDB(status=status, start_timestamp=start_timestamp, action=action_ref, parameters=params) liveaction_db.context = {'source_channel': 'awesome', 'api_user': '******'} return liveaction_db
def test_notify_triggers_jinja_patterns(self, dispatch): liveaction_db = LiveActionDB(action='core.local') liveaction_db.id = bson.ObjectId() liveaction_db.description = '' liveaction_db.status = 'succeeded' liveaction_db.parameters = {'cmd': 'mamma mia', 'runner_foo': 'foo'} on_success = NotificationSubSchema(message='Command {{action_parameters.cmd}} succeeded.', data={'stdout': '{{action_results.stdout}}'}) liveaction_db.notify = NotificationSchema(on_success=on_success) liveaction_db.start_timestamp = date_utils.get_datetime_utc_now() liveaction_db.end_timestamp = \ (liveaction_db.start_timestamp + datetime.timedelta(seconds=50)) LiveAction.add_or_update(liveaction_db) execution = MOCK_EXECUTION execution.liveaction = vars(LiveActionAPI.from_model(liveaction_db)) execution.status = liveaction_db.status notifier = Notifier(connection=None, queues=[]) notifier.process(execution) exp = {'status': 'succeeded', 'start_timestamp': isotime.format(liveaction_db.start_timestamp), 'route': 'notify.default', 'runner_ref': 'local-shell-cmd', 'channel': 'notify.default', 'message': u'Command mamma mia succeeded.', 'data': {'result': '{}', 'stdout': 'stuff happens'}, 'action_ref': u'core.local', 'execution_id': str(MOCK_EXECUTION.id), 'end_timestamp': isotime.format(liveaction_db.end_timestamp)} dispatch.assert_called_once_with('core.st2.generic.notifytrigger', payload=exp, trace_context={}) notifier.process(execution)
def test_notify_triggers_end_timestamp_none(self): liveaction_db = LiveActionDB(action='core.local') liveaction_db.id = bson.ObjectId() liveaction_db.description = '' liveaction_db.status = 'succeeded' liveaction_db.parameters = {} on_success = NotificationSubSchema(message='Action succeeded.') on_failure = NotificationSubSchema(message='Action failed.') liveaction_db.notify = NotificationSchema(on_success=on_success, on_failure=on_failure) liveaction_db.start_timestamp = date_utils.get_datetime_utc_now() # This tests for end_timestamp being set to None, which can happen when a policy cancels # a request. # The assertions within "MockDispatcher.dispatch" will validate that the underlying code # handles this properly, so all we need to do is keep the call to "notifier.process" below liveaction_db.end_timestamp = None LiveAction.add_or_update(liveaction_db) execution = MOCK_EXECUTION execution.liveaction = vars(LiveActionAPI.from_model(liveaction_db)) execution.status = liveaction_db.status dispatcher = NotifierTestCase.MockDispatcher(self) notifier = Notifier(connection=None, queues=[], trigger_dispatcher=dispatcher) notifier.process(execution)
def _build_liveaction_object(self, action_node, resolved_params, parent_context): liveaction = LiveActionDB(action=action_node.ref) # Setup notify for task in chain. notify = self._get_notify(action_node) if notify: liveaction.notify = notify LOG.debug('%s: Task notify set to: %s', action_node.name, liveaction.notify) liveaction.context = { 'parent': parent_context, 'chain': vars(action_node) } liveaction.parameters = action_param_utils.cast_params(action_ref=action_node.ref, params=resolved_params) return liveaction
def _invoke_action(self, action_db, runnertype_db, params, context=None, additional_contexts=None): """ Schedule an action execution. :type action_exec_spec: :class:`ActionExecutionSpecDB` :param params: Partially rendered parameters to execute the action with. :type params: ``dict`` :rtype: :class:`LiveActionDB` on successful scheduling, None otherwise. """ action_ref = action_db.ref runnertype_db = action_utils.get_runnertype_by_name(action_db.runner_type['name']) liveaction_db = LiveActionDB(action=action_ref, context=context, parameters=params) try: liveaction_db.parameters = self.get_resolved_parameters( runnertype_db=runnertype_db, action_db=action_db, params=liveaction_db.parameters, context=liveaction_db.context, additional_contexts=additional_contexts) except param_exc.ParamException as e: # We still need to create a request, so liveaction_db is assigned an ID liveaction_db, execution_db = action_service.create_request(liveaction_db) # By this point the execution is already in the DB therefore need to mark it failed. _, e, tb = sys.exc_info() action_service.update_status( liveaction=liveaction_db, new_status=action_constants.LIVEACTION_STATUS_FAILED, result={'error': six.text_type(e), 'traceback': ''.join(traceback.format_tb(tb, 20))}) # Might be a good idea to return the actual ActionExecution rather than bubble up # the exception. raise validation_exc.ValueValidationException(six.text_type(e)) liveaction_db, execution_db = action_service.request(liveaction_db) return execution_db
def test_update_liveaction_result_with_dotted_key(self): liveaction_db = LiveActionDB() liveaction_db.status = 'initializing' liveaction_db.start_timestamp = get_datetime_utc_now() liveaction_db.action = ResourceReference( name=ActionDBUtilsTestCase.action_db.name, pack=ActionDBUtilsTestCase.action_db.pack).ref params = { 'actionstr': 'foo', 'some_key_that_aint_exist_in_action_or_runner': 'bar', 'runnerint': 555 } liveaction_db.parameters = params liveaction_db = LiveAction.add_or_update(liveaction_db) origliveaction_db = copy.copy(liveaction_db) # Update by id. newliveaction_db = action_db_utils.update_liveaction_status( status='running', liveaction_id=liveaction_db.id) # Verify id didn't change. self.assertEqual(origliveaction_db.id, newliveaction_db.id) self.assertEqual(newliveaction_db.status, 'running') # Verify that state is published. self.assertTrue(LiveActionPublisher.publish_state.called) LiveActionPublisher.publish_state.assert_called_once_with(newliveaction_db, 'running') now = get_datetime_utc_now() status = 'succeeded' result = {'a': 1, 'b': True, 'a.b.c': 'abc'} context = {'third_party_id': uuid.uuid4().hex} newliveaction_db = action_db_utils.update_liveaction_status( status=status, result=result, context=context, end_timestamp=now, liveaction_id=liveaction_db.id) self.assertEqual(origliveaction_db.id, newliveaction_db.id) self.assertEqual(newliveaction_db.status, status) self.assertIn('a.b.c', list(result.keys())) self.assertDictEqual(newliveaction_db.result, result) self.assertDictEqual(newliveaction_db.context, context) self.assertEqual(newliveaction_db.end_timestamp, now)
def get_liveaction_instance(self, status=None, result=None): callback = { 'source': MISTRAL_RUNNER_NAME, 'url': 'http://127.0.0.1:8989/v2/action_executions/12345' } liveaction = LiveActionDB( action='core.local', parameters={'cmd': 'uname -a'}, callback=callback, context=dict() ) if status: liveaction.status = status if result: liveaction.result = result return liveaction
def test_update_LiveAction_status_invalid(self): liveaction_db = LiveActionDB() liveaction_db.status = 'initializing' liveaction_db.start_timestamp = get_datetime_utc_now() liveaction_db.action = ResourceReference( name=ActionDBUtilsTestCase.action_db.name, pack=ActionDBUtilsTestCase.action_db.pack).ref params = { 'actionstr': 'foo', 'some_key_that_aint_exist_in_action_or_runner': 'bar', 'runnerint': 555 } liveaction_db.parameters = params liveaction_db = LiveAction.add_or_update(liveaction_db) # Update by id. self.assertRaises(ValueError, action_db_utils.update_liveaction_status, status='mea culpa', liveaction_id=liveaction_db.id) # Verify that state is not published. self.assertFalse(LiveActionPublisher.publish_state.called)
def _get_liveaction_model(self, params, with_config_context=False): status = 'initializing' start_timestamp = date_utils.get_datetime_utc_now() action_ref = ResourceReference(name=ParamsUtilsTest.action_db.name, pack=ParamsUtilsTest.action_db.pack).ref liveaction_db = LiveActionDB(status=status, start_timestamp=start_timestamp, action=action_ref, parameters=params) liveaction_db.context = { 'api_user': '******', 'source_channel': 'reddit', } if with_config_context: liveaction_db.context.update( { 'pack': 'generic', 'user': '******' } ) return liveaction_db
def test_liveaction_create_with_notify_on_success_only(self): created = LiveActionDB() created.action = 'core.local' created.description = '' created.status = 'running' created.parameters = {} notify_db = NotificationSchema() notify_sub_schema = NotificationSubSchema() notify_sub_schema.message = 'Action succeeded.' notify_sub_schema.data = { 'foo': 'bar', 'bar': 1, 'baz': {'k1': 'v1'} } notify_db.on_success = notify_sub_schema created.notify = notify_db saved = LiveActionModelTest._save_liveaction(created) retrieved = LiveAction.get_by_id(saved.id) self.assertEqual(saved.action, retrieved.action, 'Same triggertype was not returned.') # Assert notify settings saved are right. self.assertEqual(notify_sub_schema.message, retrieved.notify.on_success.message) self.assertDictEqual(notify_sub_schema.data, retrieved.notify.on_success.data) self.assertListEqual(notify_sub_schema.routes, retrieved.notify.on_success.routes) self.assertEqual(retrieved.notify.on_failure, None) self.assertEqual(retrieved.notify.on_complete, None)
def test_post_generic_trigger_with_emit_condition(self, dispatch): for status in LIVEACTION_STATUSES: liveaction_db = LiveActionDB(action='core.local') liveaction_db.status = status execution = MOCK_EXECUTION execution.liveaction = vars(LiveActionAPI.from_model(liveaction_db)) execution.status = liveaction_db.status notifier = Notifier(connection=None, queues=[]) notifier._post_generic_trigger(liveaction_db, execution) if status in ['scheduled', 'pending', 'abandoned']: exp = {'status': status, 'start_timestamp': str(liveaction_db.start_timestamp), 'result': {}, 'parameters': {}, 'action_ref': u'core.local', 'runner_ref': 'local-shell-cmd', 'execution_id': str(MOCK_EXECUTION.id), 'action_name': u'core.local'} dispatch.assert_called_with('core.st2.generic.actiontrigger', payload=exp, trace_context={}) self.assertEqual(dispatch.call_count, 3)
def test_liveaction_crud_no_notify(self): created = LiveActionDB() created.action = 'core.local' created.description = '' created.status = 'running' created.parameters = {} saved = LiveActionModelTest._save_liveaction(created) retrieved = LiveAction.get_by_id(saved.id) self.assertEqual(saved.action, retrieved.action, 'Same triggertype was not returned.') self.assertEqual(retrieved.notify, None) # Test update self.assertTrue(retrieved.end_timestamp is None) retrieved.end_timestamp = date_utils.get_datetime_utc_now() updated = LiveAction.add_or_update(retrieved) self.assertTrue(updated.end_timestamp == retrieved.end_timestamp) # Test delete LiveActionModelTest._delete([retrieved]) try: retrieved = LiveAction.get_by_id(saved.id) except StackStormDBObjectNotFoundError: retrieved = None self.assertIsNone(retrieved, 'managed to retrieve after failure.')
def _get_action_exec_db_model(self, action_db, params): liveaction_db = LiveActionDB() liveaction_db.status = action_constants.LIVEACTION_STATUS_REQUESTED liveaction_db.start_timestamp = date_utils.get_datetime_utc_now() liveaction_db.action = ResourceReference( name=action_db.name, pack=action_db.pack).ref liveaction_db.parameters = params liveaction_db.context = {'user': cfg.CONF.system_user.user} return liveaction_db
def _get_failingaction_exec_db_model(self, params): liveaction_db = LiveActionDB() liveaction_db.status = action_constants.LIVEACTION_STATUS_REQUESTED liveaction_db.start_timestamp = datetime.datetime.now() liveaction_db.action = ResourceReference( name=RunnerContainerTest.failingaction_db.name, pack=RunnerContainerTest.failingaction_db.pack).ref liveaction_db.parameters = params liveaction_db.context = {'user': cfg.CONF.system_user.user} return liveaction_db
def test_chain_runner_success_task_action_call_with_no_params( self, request): # Make sure that the runner doesn't explode if task definition contains # no "params" section chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_ACTION_CALL_NO_PARAMS_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.liveaction.notify = CHAIN_NOTIFY_DB 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_chain_runner_no_default(self, request): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_NO_DEFAULT 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.pre_run() chain_runner.run({}) self.assertNotEqual(chain_runner.chain_holder.actionchain, None) # In case of this chain default_node is the first_node. default_node = chain_runner.chain_holder.actionchain.default first_node = chain_runner.chain_holder.actionchain.chain[0] self.assertEqual(default_node, first_node.name) # based on the chain the callcount is known to be 3. Not great but works. self.assertEqual(request.call_count, 3)
def test_cancel_retry(self): liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS) liveaction, execution = action_service.request(liveaction) liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING) mistral_context = liveaction.context.get('mistral', None) self.assertIsNotNone(mistral_context) self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id')) self.assertEqual(mistral_context['workflow_name'], WF1_EXEC.get('workflow_name')) requester = cfg.CONF.system_user.user liveaction, execution = action_service.request_cancellation(liveaction, requester) executions.ExecutionManager.update.assert_called_with(WF1_EXEC.get('id'), 'CANCELLED') liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_CANCELING)
def test_launch_workflow_reverse(self): # no differences for liveaction (direct == reverse) liveaction = LiveActionDB(action=WF3_NAME, parameters=ACTION_PARAMS) liveaction, execution = action_service.request(liveaction) liveaction = self._wait_on_status( liveaction, action_constants.LIVEACTION_STATUS_RUNNING) # no differences for mistral_context (direct == reverse) mistral_context = liveaction.context.get('mistral', None) self.assertIsNotNone(mistral_context) self.assertEqual(mistral_context['execution_id'], WF3_EXEC.get('id')) self.assertEqual(mistral_context['workflow_name'], WF3_EXEC.get('workflow_name')) # no differences for workflow_input (direct == reverse) workflow_input = copy.deepcopy(ACTION_PARAMS) workflow_input.update({'count': '3'}) env = { 'st2_execution_id': str(execution.id), 'st2_liveaction_id': str(liveaction.id), 'st2_action_api_url': 'http://0.0.0.0:9101/v1', '__actions': { 'st2.action': { 'st2_context': { 'api_url': 'http://0.0.0.0:9101/v1', 'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions', 'parent': { 'pack': 'mistral_tests', 'execution_id': str(execution.id) }, 'notify': {}, 'skip_notify_tasks': [] } } } } # task_name must be passed to mistral.executions.create for reverse workflows task_name = WF3_REVERSE_TARGET_TASK_NAME executions.ExecutionManager.create.assert_called_with( WF3_NAME, workflow_input=workflow_input, env=env, notify=NOTIFY, task_name=task_name)
def test_launch_workflow_with_mistral_auth(self): cfg.CONF.set_default('keystone_username', 'foo', group='mistral') cfg.CONF.set_default('keystone_password', 'bar', group='mistral') cfg.CONF.set_default('keystone_project_name', 'admin', group='mistral') cfg.CONF.set_default('keystone_auth_url', 'http://localhost:5000/v3', group='mistral') MistralRunner.entry_point = mock.PropertyMock(return_value=WF1_YAML_FILE_PATH) liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS) liveaction, execution = action_service.request(liveaction) liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING) mistral_context = liveaction.context.get('mistral', None) self.assertIsNotNone(mistral_context) self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id')) self.assertEqual(mistral_context['workflow_name'], WF1_EXEC.get('workflow_name')) workflow_input = copy.deepcopy(ACTION_PARAMS) workflow_input.update({'count': '3'}) env = { 'st2_execution_id': str(execution.id), 'st2_liveaction_id': str(liveaction.id), '__actions': { 'st2.action': { 'st2_context': { 'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions', 'parent': { 'execution_id': str(execution.id) }, 'notify': {}, 'skip_notify_tasks': [] } } } } client.Client.authenticate.assert_called_with( cfg.CONF.mistral.v2_base_url, cfg.CONF.mistral.keystone_username, cfg.CONF.mistral.keystone_password, cfg.CONF.mistral.keystone_project_name, cfg.CONF.mistral.keystone_auth_url, None, 'publicURL', 'workflow', None, None, None) executions.ExecutionManager.create.assert_called_with( WF1_NAME, workflow_input=workflow_input, env=env)
def _schedule_execution(self, action_alias_db, params, notify, context, requester_user, show_secrets): action_ref = action_alias_db.action_ref action_db = action_utils.get_action_by_ref(action_ref) if not action_db: raise StackStormDBObjectNotFoundError( 'Action with ref "%s" not found ' % (action_ref)) assert_user_has_resource_db_permission( user_db=requester_user, resource_db=action_db, permission_type=PermissionType.ACTION_EXECUTE) try: # prior to shipping off the params cast them to the right type. params = action_param_utils.cast_params( action_ref=action_alias_db.action_ref, params=params, cast_overrides=CAST_OVERRIDES) if not context: context = { 'action_alias_ref': reference.get_ref_from_model(action_alias_db), 'user': get_system_username() } liveaction = LiveActionDB(action=action_alias_db.action_ref, context=context, parameters=params, notify=notify) _, action_execution_db = action_service.request(liveaction) mask_secrets = self._get_mask_secrets(requester_user, show_secrets=show_secrets) return ActionExecutionAPI.from_model(action_execution_db, mask_secrets=mask_secrets) except ValueError as e: LOG.exception('Unable to execute action.') abort(http_client.BAD_REQUEST, str(e)) except jsonschema.ValidationError as e: LOG.exception( 'Unable to execute action. Parameter validation failed.') abort(http_client.BAD_REQUEST, str(e)) except Exception as e: LOG.exception( 'Unable to execute action. Unexpected error encountered.') abort(http_client.INTERNAL_SERVER_ERROR, str(e))
def test_notify_triggers(self): liveaction_db = LiveActionDB(action='core.local') liveaction_db.id = bson.ObjectId() liveaction_db.description = '' liveaction_db.status = 'succeeded' liveaction_db.parameters = {} on_success = NotificationSubSchema(message='Action succeeded.') on_failure = NotificationSubSchema(message='Action failed.') liveaction_db.notify = NotificationSchema(on_success=on_success, on_failure=on_failure) liveaction_db.start_timestamp = date_utils.get_datetime_utc_now() liveaction_db.end_timestamp = \ (liveaction_db.start_timestamp + datetime.timedelta(seconds=50)) LiveAction.add_or_update(liveaction_db) execution = MOCK_EXECUTION execution.liveaction = vars(LiveActionAPI.from_model(liveaction_db)) execution.status = liveaction_db.status dispatcher = NotifierTestCase.MockDispatcher(self) notifier = Notifier(connection=None, queues=[], trigger_dispatcher=dispatcher) notifier.process(execution)
def test_chain_runner_success_path(self, request): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_1_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.pre_run() chain_runner.run({}) self.assertNotEqual(chain_runner.chain_holder.actionchain, None) self.assertEqual(request.call_count, 2) first_call_args = request.call_args_list[0][0] liveaction_db = first_call_args[0] self.assertTrue(liveaction_db.notify, 'Notify property expected.') second_call_args = request.call_args_list[1][0] liveaction_db = second_call_args[0] self.assertFalse(liveaction_db.notify, 'Notify property not expected.')
def _get_output_schema_exec_db_model(self, params): status = action_constants.LIVEACTION_STATUS_REQUESTED start_timestamp = date_utils.get_datetime_utc_now() action_ref = ResourceReference( name=RunnerContainerTest.schema_output_action_db.name, pack=RunnerContainerTest.schema_output_action_db.pack, ).ref parameters = params context = {"user": cfg.CONF.system_user.user} liveaction_db = LiveActionDB( status=status, start_timestamp=start_timestamp, action=action_ref, parameters=parameters, context=context, ) return liveaction_db
def test_failed_cancel(self): liveaction = LiveActionDB(action='executions.local', parameters={'cmd': 'uname -a'}) liveaction, _ = action_service.request(liveaction) liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING) # Cancel execution. action_service.request_cancellation(liveaction, cfg.CONF.system_user.user) # Cancellation failed and execution state remains "canceling". ActionRunner.cancel.assert_called_once_with() liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_CANCELING)
def test_launch_workflow_under_parent_chain_with_nonetype_in_params_context( self): ac_ctx = {'chain': {'params': None}} liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS, context=ac_ctx) liveaction, execution = action_service.request(liveaction) liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING) mistral_context = liveaction.context.get('mistral', None) self.assertIsNotNone(mistral_context) self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id')) self.assertEqual(mistral_context['workflow_name'], WF1_EXEC.get('workflow_name')) workflow_input = copy.deepcopy(ACTION_PARAMS) workflow_input.update({'count': '3'}) env = { 'st2_execution_id': str(execution.id), 'st2_liveaction_id': str(liveaction.id), 'st2_action_api_url': 'http://0.0.0.0:9101/v1', '__actions': { 'st2.action': { 'st2_context': { 'api_url': 'http://0.0.0.0:9101/v1', 'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions', 'parent': { 'pack': 'mistral_tests', 'execution_id': str(execution.id), 'chain': { 'params': None } }, 'notify': {}, 'skip_notify_tasks': [] } } } } executions.ExecutionManager.create.assert_called_with( WF1_NAME, workflow_input=workflow_input, env=env, notify=NOTIFY)
def test_chain_pause_resume_status_change(self): # Tests context_result is updated when last task's status changes between pause and resume action = TEST_PACK + '.' + 'test_pause_resume_context_result' liveaction = LiveActionDB(action=action) liveaction, execution = action_service.request(liveaction) liveaction = LiveAction.get_by_id(str(liveaction.id)) # Wait until the liveaction is paused. liveaction = self._wait_for_status( liveaction, action_constants.LIVEACTION_STATUS_PAUSED) extra_info = str(liveaction) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_PAUSED, extra_info) # Wait for non-blocking threads to complete. Ensure runner is not running. MockLiveActionPublisherNonBlocking.wait_all() last_task_liveaction_id = liveaction.result['tasks'][-1][ 'liveaction_id'] action_utils.update_liveaction_status( status=action_constants.LIVEACTION_STATUS_SUCCEEDED, end_timestamp=date_utils.get_datetime_utc_now(), result={'foo': 'bar'}, liveaction_id=last_task_liveaction_id) # Request action chain to resume. liveaction, execution = action_service.request_resume( liveaction, USERNAME) # Wait until the liveaction is completed. liveaction = self._wait_for_status( liveaction, action_constants.LIVEACTION_STATUS_SUCCEEDED) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_SUCCEEDED, str(liveaction)) # Wait for non-blocking threads to complete. MockLiveActionPublisherNonBlocking.wait_all() # Check liveaction result. self.assertIn('tasks', liveaction.result) self.assertEqual(len(liveaction.result['tasks']), 2) self.assertEqual(liveaction.result['tasks'][0]['result']['foo'], 'bar')
def test_chain_runner_dependent_param_temp(self, request): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_DEP_INPUT 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.pre_run() chain_runner.run({'s1': 1, 's2': 2, 's3': 3, 's4': 4}) self.assertNotEqual(chain_runner.chain_holder.actionchain, None) expected_values = [{u'p1': u'1'}, {u'p1': u'1'}, {u'p2': u'1', u'p3': u'1', u'p1': u'1'}] # Each of the call_args must be one of for call_args in request.call_args_list: self.assertIn(call_args[0][0].parameters, expected_values) expected_values.remove(call_args[0][0].parameters) self.assertEqual(len(expected_values), 0, 'Not all expected values received.')
def test_chain_runner_dependent_param_temp(self, request): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_DEP_INPUT 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.pre_run() chain_runner.run({"s1": 1, "s2": 2, "s3": 3, "s4": 4}) self.assertNotEqual(chain_runner.chain_holder.actionchain, None) expected_values = [{"p1": "1"}, {"p1": "1"}, {"p2": "1", "p3": "1", "p1": "1"}] # Each of the call_args must be one of for call_args in request.call_args_list: self.assertIn(call_args[0][0].parameters, expected_values) expected_values.remove(call_args[0][0].parameters) self.assertEqual(len(expected_values), 0, "Not all expected values received.")
def test_cancel(self): MistralRunner.entry_point = mock.PropertyMock(return_value=WF1_YAML_FILE_PATH) liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS) liveaction, execution = action_service.request(liveaction) liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING) mistral_context = liveaction.context.get('mistral', None) self.assertIsNotNone(mistral_context) self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id')) self.assertEqual(mistral_context['workflow_name'], WF1_EXEC.get('workflow_name')) requester = cfg.CONF.system_user.user liveaction, execution = action_service.request_cancellation(liveaction, requester) executions.ExecutionManager.update.assert_called_with(WF1_EXEC.get('id'), 'PAUSED') liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_CANCELED)
def test_callback(self): liveaction = LiveActionDB( action='core.local', parameters={'cmd': 'uname -a'}, callback={ 'source': 'mistral', 'url': 'http://127.0.0.1:8989/v2/action_executions/12345' } ) for status in action_constants.LIVEACTION_COMPLETED_STATES: expected_mistral_status = mistral_status_map[status] LocalShellRunner.run = mock.Mock(return_value=(status, NON_EMPTY_RESULT, None)) liveaction, execution = action_service.request(liveaction) liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, status) action_executions.ActionExecutionManager.update.assert_called_with( '12345', state=expected_mistral_status, output=NON_EMPTY_RESULT)
def test_action_chain_runner_referenced_action_doesnt_exist(self, mock_request): # Action referenced by a task doesn't exist, should result in a top level error chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_WITH_INVALID_ACTION chain_runner.action = ACTION_2 action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack) chain_runner.liveaction = LiveActionDB(action=action_ref) chain_runner.pre_run() action_parameters = {} status, output, _ = chain_runner.run(action_parameters=action_parameters) expected_error = ('Failed to run task "c1". Action with reference "wolfpack.a2" ' 'doesn\'t exist.') self.assertEqual(status, LIVEACTION_STATUS_FAILED) self.assertIn(expected_error, output['error']) self.assertIn('Traceback', output['traceback'])
def test_callback_incomplete_state(self): local_runner_cls = self.get_runner_class('local_runner') local_run_result = (action_constants.LIVEACTION_STATUS_RUNNING, NON_EMPTY_RESULT, None) local_runner_cls.run = mock.Mock(return_value=local_run_result) liveaction = LiveActionDB( action='core.local', parameters={'cmd': 'uname -a'}, callback={ 'source': MISTRAL_RUNNER_NAME, 'url': 'http://127.0.0.1:8989/v2/action_executions/12345' } ) liveaction, execution = action_service.request(liveaction) liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING) self.assertFalse(action_executions.ActionExecutionManager.update.called)
def test_notify_triggers(self): liveaction = LiveActionDB(action='core.local') liveaction.description = '' liveaction.status = 'succeeded' liveaction.parameters = {} on_success = NotificationSubSchema(message='Action succeeded.') on_failure = NotificationSubSchema(message='Action failed.') liveaction.notify = NotificationSchema(on_success=on_success, on_failure=on_failure) liveaction.start_timestamp = date_utils.get_datetime_utc_now() liveaction.end_timestamp = liveaction.start_timestamp + datetime.timedelta(seconds=50) dispatcher = NotifierTestCase.MockDispatcher(self) notifier = Notifier(connection=None, queues=[], trigger_dispatcher=dispatcher) notifier.process(liveaction)
def test_chain_cancel(self): # A temp file is created during test setup. Ensure the temp file exists. # The test action chain will stall until this file is deleted. This gives # the unit test a moment to run any test related logic. path = self.temp_file_path self.assertTrue(os.path.exists(path)) action = TEST_PACK + '.' + 'test_cancel' params = {'tempfile': path, 'message': 'foobar'} liveaction = LiveActionDB(action=action, parameters=params) liveaction, execution = action_service.request(liveaction) liveaction = LiveAction.get_by_id(str(liveaction.id)) # Wait until the liveaction is running. liveaction = self._wait_for_status( liveaction, action_constants.LIVEACTION_STATUS_RUNNING) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING) # Request action chain to cancel. liveaction, execution = action_service.request_cancellation( liveaction, USERNAME) # Wait until the liveaction is canceling. liveaction = self._wait_for_status( liveaction, action_constants.LIVEACTION_STATUS_CANCELING) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_CANCELING) # Delete the temporary file that the action chain is waiting on. os.remove(path) self.assertFalse(os.path.exists(path)) # Wait until the liveaction is canceled. liveaction = self._wait_for_status( liveaction, action_constants.LIVEACTION_STATUS_CANCELED) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_CANCELED) # Wait for non-blocking threads to complete. Ensure runner is not running. MockLiveActionPublisherNonBlocking.wait_all() # Check liveaction result. self.assertIn('tasks', liveaction.result) self.assertEqual(len(liveaction.result['tasks']), 1)
def test_notify_triggers(self): liveaction = LiveActionDB(action='core.local') liveaction.description = '' liveaction.status = 'succeeded' liveaction.parameters = {} on_success = NotificationSubSchema(message='Action succeeded.') on_failure = NotificationSubSchema(message='Action failed.') liveaction.notify = NotificationSchema(on_success=on_success, on_failure=on_failure) liveaction.start_timestamp = date_utils.get_datetime_utc_now() dispatcher = NotifierTestCase.MockDispatcher(self) notifier = Notifier(connection=None, queues=[], trigger_dispatcher=dispatcher) notifier.process(liveaction)
def _re_run_live_action(self, live_action_db): retry_count = self._get_live_action_retry_count(live_action_db=live_action_db) # Add additional policy specific info to the context context = getattr(live_action_db, 'context', {}) new_context = copy.deepcopy(context) new_context['policies'] = {} new_context['policies']['retry'] = { 'applied_policy': self._policy_ref, 'retry_count': (retry_count + 1), 'retried_liveaction_id': str(live_action_db.id) } action_ref = live_action_db.action parameters = live_action_db.parameters new_live_action_db = LiveActionDB(action=action_ref, parameters=parameters, context=new_context) _, action_execution_db = action_services.request(new_live_action_db) return action_execution_db
def test_update_canceled_liveaction(self): liveaction_db = LiveActionDB() liveaction_db.status = 'initializing' liveaction_db.start_timestamp = get_datetime_utc_now() liveaction_db.action = ResourceReference( name=ActionDBUtilsTestCase.action_db.name, pack=ActionDBUtilsTestCase.action_db.pack).ref params = { 'actionstr': 'foo', 'some_key_that_aint_exist_in_action_or_runner': 'bar', 'runnerint': 555 } liveaction_db.parameters = params liveaction_db = LiveAction.add_or_update(liveaction_db) origliveaction_db = copy.copy(liveaction_db) # Update by id. newliveaction_db = action_db_utils.update_liveaction_status( status='running', liveaction_id=liveaction_db.id) # Verify id didn't change. self.assertEqual(origliveaction_db.id, newliveaction_db.id) self.assertEqual(newliveaction_db.status, 'running') # Verify that state is published. self.assertTrue(LiveActionPublisher.publish_state.called) LiveActionPublisher.publish_state.assert_called_once_with(newliveaction_db, 'running') # Cancel liveaction. now = get_datetime_utc_now() status = 'canceled' newliveaction_db = action_db_utils.update_liveaction_status( status=status, end_timestamp=now, liveaction_id=liveaction_db.id) self.assertEqual(origliveaction_db.id, newliveaction_db.id) self.assertEqual(newliveaction_db.status, status) self.assertEqual(newliveaction_db.end_timestamp, now) # Since liveaction has already been canceled, check that anymore update of # status, result, context, and end timestamp are not processed. now = get_datetime_utc_now() status = 'succeeded' result = 'Work is done.' context = {'third_party_id': uuid.uuid4().hex} newliveaction_db = action_db_utils.update_liveaction_status( status=status, result=result, context=context, end_timestamp=now, liveaction_id=liveaction_db.id) self.assertEqual(origliveaction_db.id, newliveaction_db.id) self.assertEqual(newliveaction_db.status, 'canceled') self.assertNotEqual(newliveaction_db.result, result) self.assertNotEqual(newliveaction_db.context, context) self.assertNotEqual(newliveaction_db.end_timestamp, now)
def test_callback_retry_exhausted(self): liveaction = LiveActionDB( action='core.local', parameters={'cmd': 'uname -a'}, callback={ 'source': 'mistral', 'url': 'http://127.0.0.1:8989/v2/action_executions/12345' } ) liveaction, execution = action_service.request(liveaction) liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_SUCCEEDED) # This test initially setup mock for action_executions.ActionExecutionManager.update # to fail the first 4 times and return success on the 5th times. The max attempts # is set to 3. We expect only 3 calls to pass thru the update method. calls = [call('12345', state='SUCCESS', output=NON_EMPTY_RESULT) for i in range(0, 2)] action_executions.ActionExecutionManager.update.assert_has_calls(calls)
def test_chain_runner_failure_during_param_rendering_single_task(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_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.pre_run() status, result, _ = chain_runner.run({}) # No tasks ran because rendering of parameters for the first task failed self.assertEqual(status, LIVEACTION_STATUS_FAILED) self.assertEqual(result['tasks'], []) self.assertIn('error', result) self.assertIn('traceback', result) self.assertIn('Failed to run task "c1". Parameter rendering failed', result['error']) self.assertIn('Traceback', result['traceback'])
def test_chain_runner_no_default_multiple_options(self, request): # subtle difference is that when there are multiple possible default nodes # the order per chain definition may not be preseved. This is really a # poorly formatted chain but we still the best attempt to work. chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_NO_DEFAULT_2 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.pre_run() chain_runner.run({}) self.assertNotEqual(chain_runner.chain_holder.actionchain, None) # In case of this chain default_node is the first_node. default_node = chain_runner.chain_holder.actionchain.default first_node = chain_runner.chain_holder.actionchain.chain[0] self.assertEqual(default_node, first_node.name) # based on the chain the callcount is known to be 2. self.assertEqual(request.call_count, 2)
def test_get_all(self): resp = stream.StreamController().get_all() self.assertEqual(resp._status, '200 OK') self.assertIn(('Content-Type', 'text/event-stream; charset=UTF-8'), resp._headerlist) listener = st2common.stream.listener.get_listener(name='stream') process = listener.processor(LiveActionAPI) message = None for message in resp._app_iter: if message != '\n': break process(LiveActionDB(**LIVE_ACTION_1), META()) self.assertIn('event: some__thing', message) self.assertIn('data: {"', message) self.assertNotIn(SUPER_SECRET_PARAMETER, message)
def test_noop_cancel(self): liveaction = LiveActionDB(action='executions.local', parameters={'cmd': 'uname -a'}) liveaction, _ = action_service.request(liveaction) liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_REQUESTED) # Cancel execution. action_service.request_cancellation(liveaction, cfg.CONF.system_user.user) # Cancel is only called when liveaction is still in running state. # Otherwise, the cancellation is only a state change. self.assertFalse(ActionRunner.cancel.called) liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_CANCELED)
def test_chain_runner_typed_params(self, request): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_TYPED_PARAMS chain_runner.action = ACTION_2 action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack) chain_runner.liveaction = LiveActionDB(action=action_ref) chain_runner.pre_run() chain_runner.run({'s1': 1, 's2': 'two', 's3': 3.14}) self.assertNotEqual(chain_runner.chain_holder.actionchain, None) expected_value = {'booltype': True, 'inttype': 1, 'numbertype': 3.14, 'strtype': 'two', 'arrtype': ['1', 'two'], 'objtype': {'s2': 'two', 'k1': '1'}} mock_args, _ = request.call_args self.assertEqual(mock_args[0].parameters, expected_value)
def _create_nested_executions(self, depth=2): """Utility function for easily creating nested LiveAction and ActionExecutions for testing returns (childmost_liveaction_db, parentmost_liveaction_db) """ if depth <= 0: raise Exception("Please provide a depth > 0") root_liveaction_db = LiveActionDB() root_liveaction_db.status = action_constants.LIVEACTION_STATUS_PAUSED root_liveaction_db.action = ACTION_WORKFLOW_REF root_liveaction_db = LiveAction.add_or_update(root_liveaction_db) root_ex = executions.create_execution_object(root_liveaction_db) last_id = root_ex['id'] # Create children to the specified depth for i in range(depth): # Childmost liveaction should use ACTION_REF, everything else # should use ACTION_WORKFLOW_REF if i == depth: action = ACTION_REF else: action = ACTION_WORKFLOW_REF child_liveaction_db = LiveActionDB() child_liveaction_db.status = action_constants.LIVEACTION_STATUS_PAUSED child_liveaction_db.action = action child_liveaction_db.context = {"parent": {"execution_id": last_id}} child_liveaction_db = LiveAction.add_or_update(child_liveaction_db) parent_ex = executions.create_execution_object(child_liveaction_db) last_id = parent_ex.id # Return the last-created child as well as the root return (child_liveaction_db, root_liveaction_db)
def test_chain_runner_dependent_results_param(self, request): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_DEP_RESULTS_INPUT 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.pre_run() chain_runner.run({'s1': 1}) self.assertNotEqual(chain_runner.chain_holder.actionchain, None) expected_values = [{u'p1': u'1'}, {u'p1': u'1'}, {u'out': u"{'c2': {'o1': '1'}, 'c1': {'o1': '1'}}"}] # Each of the call_args must be one of self.assertEqual(request.call_count, 3) for call_args in request.call_args_list: self.assertTrue(call_args[0][0].parameters in expected_values) expected_values.remove(call_args[0][0].parameters) self.assertEqual(len(expected_values), 0, 'Not all expected values received.')
def test_liveaction_create_with_notify_both_on_success_and_on_error(self): created = LiveActionDB() created.action = 'core.local' created.description = '' created.status = 'running' created.parameters = {} on_success = NotificationSubSchema(message='Action succeeded.') on_failure = NotificationSubSchema(message='Action failed.') created.notify = NotificationSchema(on_success=on_success, on_failure=on_failure) saved = LiveActionModelTest._save_liveaction(created) retrieved = LiveAction.get_by_id(saved.id) self.assertEqual(saved.action, retrieved.action, 'Same triggertype was not returned.') # Assert notify settings saved are right. self.assertEqual(on_success.message, retrieved.notify.on_success.message) self.assertEqual(on_failure.message, retrieved.notify.on_failure.message) self.assertEqual(retrieved.notify.on_complete, None)
def test_update_liveaction_with_incorrect_output_schema(self): liveaction_db = LiveActionDB() liveaction_db.status = 'initializing' liveaction_db.start_timestamp = get_datetime_utc_now() liveaction_db.action = ResourceReference( name=ActionDBUtilsTestCase.action_db.name, pack=ActionDBUtilsTestCase.action_db.pack).ref params = { 'actionstr': 'foo', 'some_key_that_aint_exist_in_action_or_runner': 'bar', 'runnerint': 555 } liveaction_db.parameters = params runner = mock.MagicMock() runner.output_schema = { "notaparam": { "type": "boolean" } } liveaction_db.runner = runner liveaction_db = LiveAction.add_or_update(liveaction_db) origliveaction_db = copy.copy(liveaction_db) now = get_datetime_utc_now() status = 'succeeded' result = 'Work is done.' context = {'third_party_id': uuid.uuid4().hex} newliveaction_db = action_db_utils.update_liveaction_status( status=status, result=result, context=context, end_timestamp=now, liveaction_id=liveaction_db.id) self.assertEqual(origliveaction_db.id, newliveaction_db.id) self.assertEqual(newliveaction_db.status, status) self.assertEqual(newliveaction_db.result, result) self.assertDictEqual(newliveaction_db.context, context) self.assertEqual(newliveaction_db.end_timestamp, now)
MOCK_TRIGGER_INSTANCE = TriggerInstanceDB() MOCK_TRIGGER_INSTANCE.id = 'triggerinstance-test' MOCK_TRIGGER_INSTANCE.payload = {'t1_p': 't1_p_v'} MOCK_TRIGGER_INSTANCE.occurrence_time = date_utils.get_datetime_utc_now() MOCK_TRIGGER_INSTANCE_2 = TriggerInstanceDB() MOCK_TRIGGER_INSTANCE_2.id = 'triggerinstance-test2' MOCK_TRIGGER_INSTANCE_2.payload = {'t1_p': None} MOCK_TRIGGER_INSTANCE_2.occurrence_time = date_utils.get_datetime_utc_now() MOCK_TRIGGER_INSTANCE_3 = TriggerInstanceDB() MOCK_TRIGGER_INSTANCE_3.id = 'triggerinstance-test3' MOCK_TRIGGER_INSTANCE_3.payload = {'t1_p': None, 't2_p': 'value2'} MOCK_TRIGGER_INSTANCE_3.occurrence_time = date_utils.get_datetime_utc_now() MOCK_LIVEACTION = LiveActionDB() MOCK_LIVEACTION.id = 'liveaction-test-1.id' MOCK_LIVEACTION.status = 'requested' MOCK_EXECUTION = ActionExecutionDB() MOCK_EXECUTION.id = 'exec-test-1.id' MOCK_EXECUTION.status = 'requested' FAILURE_REASON = "fail!" class EnforceTest(DbTestCase): models = None @classmethod