def create_action_execution(values, session=None): a_ex = models.ActionExecution() a_ex.update(values.copy()) try: a_ex.save(session=session) except db_exc.DBDuplicateEntry as e: raise exc.DBDuplicateEntryError( "Duplicate entry for ActionExecution: %s" % e.columns ) return a_ex
def test_continue_workflow(self): self.wf_ex.params = {'task_name': 'task2'} # Assume task1 completed. task1_ex = self._create_task_execution('task1', states.SUCCESS) task1_ex.executions.append( models.ActionExecution( name='std.echo', workflow_name='wf', state=states.SUCCESS, output={'result': 'Hey'}, accepted=True ) ) cmds = self.wf_ctrl.continue_workflow() task1_ex.processed = True self.assertEqual(1, len(cmds)) self.assertEqual('task2', cmds[0].task_spec.get_name()) # Now assume task2 completed. task2_ex = self._create_task_execution('task2', states.SUCCESS) task2_ex.executions.append( models.ActionExecution( name='std.echo', workflow_name='wf', state=states.SUCCESS, output={'result': 'Hi!'}, accepted=True ) ) cmds = self.wf_ctrl.continue_workflow() task1_ex.processed = True self.assertEqual(0, len(cmds))
def test_action_executions(self): # Store one task with two invocations. with db_api.transaction(): wf_ex = db_api.create_workflow_execution(WF_EXECS[0]) values = copy.copy(TASK_EXECS[0]) values.update({'workflow_execution_id': wf_ex.id}) task = db_api.create_task_execution(values) self.assertEqual(0, len(task.executions)) a_ex1 = db_models.ActionExecution() a_ex2 = db_models.ActionExecution() task.executions.append(a_ex1) task.executions.append(a_ex2) self.assertEqual(2, len(task.executions)) # Make sure associated objects were saved. with db_api.transaction(): task = db_api.get_task_execution(task.id) self.assertEqual(2, len(task.executions)) self.assertNotIsInstance(task.executions[0].task_execution, list) # Remove associated objects from collection. with db_api.transaction(): task = db_api.get_task_execution(task.id) del task.executions[:] # Make sure associated objects were deleted. with db_api.transaction(): task = db_api.get_task_execution(task.id) self.assertEqual(0, len(task.executions))
def start_action(self, action_name, action_input, description=None, **params): with db_api.transaction(): action = action_handler.build_action_by_name(action_name) action.validate_input(action_input) sync = params.get('run_sync') save = params.get('save_result') target = params.get('target') is_action_sync = action.is_sync(action_input) if sync and not is_action_sync: raise exceptions.InputException( "Action does not support synchronous execution.") if not sync and (save or not is_action_sync): action.schedule(action_input, target) return action.action_ex.get_clone() output = action.run(action_input, target, save=False) state = states.SUCCESS if output.is_success() else states.ERROR if not save: # Action execution is not created but we need to return similar # object to a client anyway. return db_models.ActionExecution(name=action_name, description=description, input=action_input, output=output.to_dict(), state=state) action_ex_id = u.generate_unicode_uuid() values = { 'id': action_ex_id, 'name': action_name, 'description': description, 'input': action_input, 'output': output.to_dict(), 'state': state, } return db_api.create_action_execution(values)
def test_get_task_execution_result(self): task_ex = models.TaskExecution( name='task1', spec={ "version": '2.0', 'name': 'task1', 'with-items': 'var in [1]', 'type': 'direct', 'action': 'my_action' }, runtime_context={'with_items_context': { 'count': 1 }}) task_ex.action_executions = [ models.ActionExecution(name='my_action', output={'result': 1}, accepted=True, runtime_context={'index': 0}) ] self.assertEqual([1], data_flow.get_task_execution_result(task_ex)) task_ex.action_executions.append( models.ActionExecution(name='my_action', output={'result': 1}, accepted=True, runtime_context={'index': 0})) task_ex.action_executions.append( models.ActionExecution(name='my_action', output={'result': 1}, accepted=False, runtime_context={'index': 0})) self.assertEqual([1, 1], data_flow.get_task_execution_result(task_ex))
def start_action(self, action_name, action_input, description=None, **params): with db_api.transaction(): action_def = action_handler.resolve_definition(action_name) resolved_action_input = action_handler.get_action_input( action_name, action_input ) action = a_m.get_action_class(action_def.name)( **resolved_action_input ) # If we see action is asynchronous, then we enforce 'save_result'. if params.get('save_result') or not action.is_sync(): action_ex = action_handler.create_action_execution( action_def, resolved_action_input, description=description ) action_handler.run_action( action_def, resolved_action_input, action_ex.id, params.get('target') ) return action_ex.get_clone() else: output = action_handler.run_action( action_def, resolved_action_input, target=params.get('target'), async=False ) return db_models.ActionExecution( name=action_name, description=description, input=action_input, output=output )
from mistral.tests.unit.api import base from mistral.utils import rest_utils from mistral.workflow import states from mistral_lib import actions as ml_actions # This line is needed for correct initialization of messaging config. oslo_messaging.get_rpc_transport(cfg.CONF) ACTION_EX_DB = models.ActionExecution( id='123', workflow_name='flow', task_execution=models.TaskExecution(name='task1'), task_execution_id='333', state=states.SUCCESS, state_info=states.SUCCESS, tags=['foo', 'fee'], name='std.echo', description='something', accepted=True, input={}, output={}, created_at=datetime.datetime(1970, 1, 1), updated_at=datetime.datetime(1970, 1, 1)) AD_HOC_ACTION_EX_DB = models.ActionExecution( id='123', state=states.SUCCESS, state_info=states.SUCCESS, tags=['foo', 'fee'], name='std.echo', description='something',
def get_action_ex(accepted, state, index): return models.ActionExecution(accepted=accepted, state=state, runtime_context={'index': index})
def test_continue_workflow(self, get_task_execution): wf_text = """--- version: '2.0' wf: type: direct tasks: task1: action: std.echo output="Hey" publish: res1: <% $.task1 %> on-complete: - task2: <% $.res1 = 'Hey' %> - task3: <% $.res1 = 'Not Hey' %> task2: action: std.echo output="Hi" task3: action: std.echo output="Hoy" """ self._prepare_test(wf_text) # Workflow execution is in initial step. No running tasks. cmds = self.wf_ctrl.continue_workflow() self.assertEqual(1, len(cmds)) cmd = cmds[0] self.assertIs(self.wf_ctrl.wf_ex, cmd.wf_ex) self.assertIsNotNone(cmd.task_spec) self.assertEqual('task1', cmd.task_spec.get_name()) self.assertEqual(states.RUNNING, self.wf_ex.state) # Assume that 'task1' completed successfully. task1_ex = self._create_task_execution('task1', states.SUCCESS) task1_ex.published = {'res1': 'Hey'} get_task_execution.return_value = task1_ex task1_ex.executions.append( models.ActionExecution(name='std.echo', workflow_name='wf', state=states.SUCCESS, output={'result': 'Hey'}, accepted=True, runtime_context={'index': 0})) cmds = self.wf_ctrl.continue_workflow() task1_ex.processed = True self.assertEqual(1, len(cmds)) self.assertEqual('task2', cmds[0].task_spec.get_name()) self.assertEqual(states.RUNNING, self.wf_ex.state) self.assertEqual(states.SUCCESS, task1_ex.state) # Now assume that 'task2' completed successfully. task2_ex = self._create_task_execution('task2', states.SUCCESS) task2_ex.executions.append( models.ActionExecution(name='std.echo', workflow_name='wf', state=states.SUCCESS, output={'result': 'Hi'}, accepted=True)) cmds = self.wf_ctrl.continue_workflow() task2_ex.processed = True self.assertEqual(0, len(cmds))
def start_action(self, action_name, action_input, description=None, namespace='', **params): with db_api.transaction(): engine_action = action_handler.build_action_by_name( action_name, namespace=namespace) action_desc = engine_action.action_desc action_desc.check_parameters(action_input) sync = params.get('run_sync') save = params.get('save_result') target = params.get('target') timeout = params.get('timeout') # In order to know if it's sync or not we have to instantiate # the actual runnable action. action = action_desc.instantiate(action_input, {}) is_action_sync = action.is_sync() if sync and not is_action_sync: raise exceptions.InputException( "Action does not support synchronous execution.") if not sync and (save or not is_action_sync): engine_action.schedule(action_input, target, timeout=timeout) return engine_action.action_ex.get_clone() output = engine_action.run(action_input, target, save=False, timeout=timeout) state = states.SUCCESS if output.is_success() else states.ERROR if not save: # Action execution is not created but we need to return similar # object to the client anyway. return db_models.ActionExecution(name=action_name, description=description, input=action_input, output=output.to_dict(), state=state, workflow_namespace=namespace) action_ex_id = u.generate_unicode_uuid() values = { 'id': action_ex_id, 'name': action_name, 'description': description, 'input': action_input, 'output': output.to_dict(), 'state': state, 'is_sync': is_action_sync, 'workflow_namespace': namespace } return db_api.create_action_execution(values)
from mistral.db.v2 import api as db_api from mistral.db.v2.sqlalchemy import models from mistral.engine import rpc from mistral import exceptions as exc from mistral.tests.unit.api import base from mistral.workflow import states from mistral.workflow import utils as wf_utils action_ex = models.ActionExecution( id='123', workflow_name='flow', task_execution=models.TaskExecution(name='task1'), task_execution_id='333', state=states.SUCCESS, state_info=states.SUCCESS, tags=['foo', 'fee'], name='std.echo', description='something', accepted=True, input={}, output={}, created_at=datetime.datetime(1970, 1, 1), updated_at=datetime.datetime(1970, 1, 1)) ACTION_EXEC = { 'id': '123', 'workflow_name': 'flow', 'task_execution_id': '333', 'task_name': 'task1', 'state': 'SUCCESS', 'state_info': 'SUCCESS',