def process_cron_triggers_v2(self, ctx): for t in triggers.get_next_cron_triggers(): LOG.debug("Processing cron trigger: %s" % t) # Setup admin context before schedule triggers. ctx = security.create_context(t.trust_id, t.project_id) auth_ctx.set_ctx(ctx) LOG.debug("Cron trigger security context: %s" % ctx) try: rpc.get_engine_client().start_workflow( t.workflow.name, t.workflow_input, description="workflow execution by cron trigger.", **t.workflow_params ) finally: if t.remaining_executions > 0: t.remaining_executions -= 1 if t.remaining_executions == 0: db_api_v2.delete_cron_trigger(t.name) else: # if remaining execution = None or > 0 next_time = triggers.get_next_execution_time( t.pattern, t.next_execution_time ) db_api_v2.update_cron_trigger( t.name, {'next_execution_time': next_time, 'remaining_executions': t.remaining_executions} ) auth_ctx.set_ctx(None)
def process_cron_triggers_v2(self, ctx): for t in triggers.get_next_cron_triggers(): LOG.debug("Processing cron trigger: %s" % t) # Setup admin context before schedule triggers. ctx = security.create_context(t.trust_id, t.project_id) auth_ctx.set_ctx(ctx) LOG.debug("Cron trigger security context: %s" % ctx) try: # Try to advance the cron trigger next_execution_time and # remaining_executions if relevant. modified = advance_cron_trigger(t) # If cron trigger was not already modified by another engine. if modified: LOG.debug( "Starting workflow '%s' by cron trigger '%s'", t.workflow.name, t.name ) rpc.get_engine_client().start_workflow( t.workflow.name, t.workflow_input, description="Workflow execution created " "by cron trigger.", **t.workflow_params ) except Exception: # Log and continue to next cron trigger. LOG.exception("Failed to process cron trigger %s" % str(t)) finally: auth_ctx.set_ctx(None)
def run_workflow(wf_name, wf_input, wf_params): rpc.get_engine_client().start_workflow( wf_name, wf_input, "sub-workflow execution", **wf_params )
def process_cron_triggers_v2(self, ctx): for t in triggers.get_next_cron_triggers(): LOG.debug("Processing cron trigger: %s" % t) # Setup admin context before schedule triggers. ctx = security.create_context(t.trust_id, t.project_id) auth_ctx.set_ctx(ctx) LOG.debug("Cron trigger security context: %s" % ctx) try: rpc.get_engine_client().start_workflow( t.workflow.name, t.workflow_input, description="Workflow execution created by cron trigger.", **t.workflow_params ) finally: if t.remaining_executions is not None and t.remaining_executions > 0: t.remaining_executions -= 1 if t.remaining_executions == 0: db_api_v2.delete_cron_trigger(t.name) else: # if remaining execution = None or > 0 next_time = triggers.get_next_execution_time(t.pattern, t.next_execution_time) db_api_v2.update_cron_trigger( t.name, {"next_execution_time": next_time, "remaining_executions": t.remaining_executions} ) auth_ctx.set_ctx(None)
def send_result_to_parent_workflow(wf_ex_id): wf_ex = db_api.get_workflow_execution(wf_ex_id) if wf_ex.state == states.SUCCESS: rpc.get_engine_client().on_action_complete( wf_ex.id, wf_utils.Result(data=wf_ex.output)) elif wf_ex.state == states.ERROR: err_msg = 'Failed subworkflow [execution_id=%s]' % wf_ex.id rpc.get_engine_client().on_action_complete( wf_ex.id, wf_utils.Result(error=err_msg))
def fail_task_if_incomplete(task_ex_id, timeout): task_ex = db_api.get_task_execution(task_ex_id) if not states.is_completed(task_ex.state): msg = "Task timed out [id=%s, timeout(s)=%s]." % (task_ex_id, timeout) wf_trace.info(task_ex, msg) wf_trace.info(task_ex, "Task '%s' [%s -> ERROR]" % (task_ex.name, task_ex.state)) rpc.get_engine_client().on_task_state_change(task_ex_id, states.ERROR)
def fail_task_if_incomplete(task_ex_id, timeout): task_ex = db_api.get_task_execution(task_ex_id) if not states.is_completed(task_ex.state): msg = "Task timed out [id=%s, timeout(s)=%s]." % (task_ex_id, timeout) wf_trace.info(task_ex, msg) wf_trace.info( task_ex, "Task '%s' [%s -> ERROR]" % (task_ex.name, task_ex.state)) rpc.get_engine_client().on_task_state_change(task_ex_id, states.ERROR)
def put(self, id, task): """Update the specified task execution. :param id: Task execution ID. :param task: Task execution object. """ LOG.info("Update task execution [id=%s, task=%s]" % (id, task)) task_ex = db_api.get_task_execution(id) task_spec = spec_parser.get_task_spec(task_ex.spec) task_name = task.name or None reset = task.reset env = task.env or None if task_name and task_name != task_ex.name: raise exc.WorkflowException('Task name does not match.') wf_ex = db_api.get_workflow_execution(task_ex.workflow_execution_id) wf_name = task.workflow_name or None if wf_name and wf_name != wf_ex.name: raise exc.WorkflowException('Workflow name does not match.') if task.state != states.RUNNING: raise exc.WorkflowException( 'Invalid task state. Only updating task to rerun is supported.' ) if task_ex.state != states.ERROR: raise exc.WorkflowException( 'The current task execution must be in ERROR for rerun.' ' Only updating task to rerun is supported.' ) if not task_spec.get_with_items() and not reset: raise exc.WorkflowException( 'Only with-items task has the option to not reset.' ) rpc.get_engine_client().rerun_workflow( wf_ex.id, task_ex.id, reset=reset, env=env ) task_ex = db_api.get_task_execution(id) return _get_task_resource_with_result(task_ex)
def send_result_to_parent_workflow(wf_ex_id): wf_ex = db_api.get_workflow_execution(wf_ex_id) if wf_ex.state == states.SUCCESS: rpc.get_engine_client().on_action_complete( wf_ex.id, wf_utils.Result(data=wf_ex.output) ) elif wf_ex.state == states.ERROR: err_msg = 'Failed subworkflow [execution_id=%s]' % wf_ex.id rpc.get_engine_client().on_action_complete( wf_ex.id, wf_utils.Result(error=err_msg) )
def launch_engine(transport): target = messaging.Target( topic=cfg.CONF.engine.topic, server=cfg.CONF.engine.host ) engine_v2 = def_eng.DefaultEngine(rpc.get_engine_client()) endpoints = [rpc.EngineServer(engine_v2)] # Setup scheduler in engine. db_api.setup_db() scheduler.setup() # Setup expiration policy expiration_policy.setup() server = messaging.get_rpc_server( transport, target, endpoints, executor='eventlet', serializer=ctx.RpcContextSerializer(ctx.JsonPayloadSerializer()) ) engine_v2.register_membership() server.start() server.wait()
def launch_engine(transport): target = messaging.Target(topic=cfg.CONF.engine.topic, server=cfg.CONF.engine.host) engine_v2 = def_eng.DefaultEngine(rpc.get_engine_client()) endpoints = [rpc.EngineServer(engine_v2)] # Setup scheduler in engine. db_api.setup_db() scheduler.setup() # Setup expiration policy expiration_policy.setup() server = messaging.get_rpc_server(transport, target, endpoints, executor='eventlet', serializer=ctx.RpcContextSerializer( ctx.JsonPayloadSerializer())) engine_v2.register_membership() try: server.start() while True: time.sleep(604800) except (KeyboardInterrupt, SystemExit): pass finally: print("Stopping engine service...") server.stop() server.wait()
def launch_executor(transport): target = messaging.Target(topic=cfg.CONF.executor.topic, server=cfg.CONF.executor.host) executor_v2 = def_executor.DefaultExecutor(rpc.get_engine_client()) endpoints = [rpc.ExecutorServer(executor_v2)] server = messaging.get_rpc_server(transport, target, endpoints, executor='eventlet', serializer=ctx.RpcContextSerializer( ctx.JsonPayloadSerializer())) executor_v2.register_membership() try: server.start() while True: time.sleep(604800) except (KeyboardInterrupt, SystemExit): pass finally: print("Stopping executor service...") server.stop() server.wait()
def post(self, wf_ex): """Create a new Execution. :param wf_ex: Execution object with input content. """ LOG.info('Create execution [execution=%s]' % wf_ex) engine = rpc.get_engine_client() exec_dict = wf_ex.to_dict() if not (exec_dict.get('workflow_id') or exec_dict.get('workflow_name')): raise exc.WorkflowException( "Workflow ID or workflow name must be provided. Workflow ID is" " recommended." ) result = engine.start_workflow( exec_dict.get('workflow_id', exec_dict.get('workflow_name')), exec_dict.get('input'), exec_dict.get('description', ''), **exec_dict.get('params') or {} ) return Execution.from_dict(result)
def put(self, id, action_execution): """Update the specified action_execution.""" LOG.info( "Update action_execution [id=%s, action_execution=%s]" % (id, action_execution) ) # Client must provide a valid json. It shouldn't necessarily be an # object but it should be json complaint so strings have to be escaped. output = None if action_execution.output: try: output = json.loads(action_execution.output) except (ValueError, TypeError) as e: raise exc.InvalidResultException(str(e)) if action_execution.state == states.SUCCESS: result = wf_utils.Result(data=output) elif action_execution.state == states.ERROR: result = wf_utils.Result(error=output) else: raise exc.InvalidResultException( "Error. Expected on of %s, actual: %s" % ([states.SUCCESS, states.ERROR], action_execution.state) ) values = rpc.get_engine_client().on_action_complete(id, result) return ActionExecution.from_dict(values)
def put(self, id, action_ex): """Update the specified action_execution.""" acl.enforce('action_executions:update', context.ctx()) LOG.info( "Update action_execution [id=%s, action_execution=%s]" % (id, action_ex) ) output = action_ex.output if action_ex.state == states.SUCCESS: result = wf_utils.Result(data=output) elif action_ex.state == states.ERROR: if not output: output = 'Unknown error' result = wf_utils.Result(error=output) else: raise exc.InvalidResultException( "Error. Expected on of %s, actual: %s" % ([states.SUCCESS, states.ERROR], action_ex.state) ) values = rpc.get_engine_client().on_action_complete(id, result) return ActionExecution.from_dict(values)
def launch_executor(transport): profiler.setup('mistral-executor', cfg.CONF.executor.host) target = messaging.Target( topic=cfg.CONF.executor.topic, server=cfg.CONF.executor.host ) executor_v2 = def_executor.DefaultExecutor(rpc.get_engine_client()) endpoints = [rpc.ExecutorServer(executor_v2)] get_rpc_server = get_rpc_server_function() server = get_rpc_server( transport, target, endpoints, executor='eventlet', serializer=ctx.RpcContextSerializer(ctx.JsonPayloadSerializer()) ) executor_v2.register_membership() try: server.start() while True: time.sleep(604800) except (KeyboardInterrupt, SystemExit): pass finally: print("Stopping executor service...") server.stop() server.wait()
def put(self, id, action_execution): """Update the specified action_execution.""" LOG.info("Update action_execution [id=%s, action_execution=%s]" % (id, action_execution)) # Client must provide a valid json. It shouldn't necessarily be an # object but it should be json complaint so strings have to be escaped. output = None if action_execution.output: try: output = json.loads(action_execution.output) except (ValueError, TypeError) as e: raise exc.InvalidResultException(str(e)) if action_execution.state == states.SUCCESS: result = wf_utils.Result(data=output) elif action_execution.state == states.ERROR: result = wf_utils.Result(error=output) else: raise exc.InvalidResultException( "Error. Expected on of %s, actual: %s" % ([states.SUCCESS, states.ERROR], action_execution.state)) values = rpc.get_engine_client().on_action_complete(id, result) return ActionExecution.from_dict(values)
def post(self, action_execution): """Create new action_execution.""" body = json.loads(pecan.request.body) LOG.info("Create action_execution [action_execution=%s]" % body) action_input = action_execution.input or None description = action_execution.description or None if action_input: try: action_input = json.loads(action_execution.input) if not isinstance(action_input, dict): raise TypeError("Input should be dict type.") except (TypeError, ValueError) as e: raise exc.InputException( "Input should be JSON-serialized dict string. Actual: %s, " "error: %s" % (action_execution.input, e)) name = action_execution.name params = body.get('params', {}) if not name: raise exc.InputException( "Please provide at least action name to run action.") action_ex = rpc.get_engine_client().start_action( name, action_input, description=description, **params) return ActionExecution.from_dict(action_ex).to_dict()
def put(self, id, execution): """Update the specified Execution. :param id: execution ID. :param execution: Execution objects """ LOG.info("Update execution [id=%s, execution=%s]" % (id, execution)) db_api.ensure_workflow_execution_exists(id) new_state = execution.state new_description = execution.description msg = execution.state_info # Currently we can change only state or description. if (not (new_state or new_description) or (new_state and new_description)): raise exc.DataAccessException( "Only state or description of execution can be changed. " "But they can not be changed at the same time." ) if new_description: wf_ex = db_api.update_workflow_execution( id, {"description": new_description} ) elif new_state == states.PAUSED: wf_ex = rpc.get_engine_client().pause_workflow(id) elif new_state == states.RUNNING: wf_ex = rpc.get_engine_client().resume_workflow(id) elif new_state in [states.SUCCESS, states.ERROR]: wf_ex = rpc.get_engine_client().stop_workflow(id, new_state, msg) else: # To prevent changing state in other cases throw a message. raise exc.DataAccessException( "Can not change state to %s. Allowed states are: '%s" % (new_state, ", ".join([states.RUNNING, states.PAUSED, states.SUCCESS, states.ERROR])) ) return Execution.from_dict( wf_ex if isinstance(wf_ex, dict) else wf_ex.to_dict() )
def _run_at_target(action_ex_id, action_class_str, attributes, action_params, target=None): # We'll just call executor directly for testing purposes. executor = default_executor.DefaultExecutor(rpc.get_engine_client()) executor.run_action( action_ex_id, action_class_str, attributes, action_params )
def put(self, id, execution): """Update the specified Execution. :param id: execution ID. :param execution: Execution objects """ LOG.info("Update execution [id=%s, execution=%s]" % (id, execution)) db_api.ensure_workflow_execution_exists(id) new_state = execution.state new_description = execution.description msg = execution.state_info # Currently we can change only state or description. if (not (new_state or new_description) or (new_state and new_description)): raise exc.DataAccessException( "Only state or description of execution can be changed. " "But they can not be changed at the same time.") if new_description: wf_ex = db_api.update_workflow_execution( id, {"description": new_description}) elif new_state == states.PAUSED: wf_ex = rpc.get_engine_client().pause_workflow(id) elif new_state == states.RUNNING: wf_ex = rpc.get_engine_client().resume_workflow(id) elif new_state in [states.SUCCESS, states.ERROR]: wf_ex = rpc.get_engine_client().stop_workflow(id, new_state, msg) else: # To prevent changing state in other cases throw a message. raise exc.DataAccessException( "Can not change state to %s. Allowed states are: '%s" % (new_state, ", ".join([ states.RUNNING, states.PAUSED, states.SUCCESS, states.ERROR ]))) return Execution.from_dict( wf_ex if isinstance(wf_ex, dict) else wf_ex.to_dict())
def put(self, id, execution): """Update the specified Execution. :param id: execution ID. :param execution: Execution objects """ LOG.info("Update execution [id=%s, execution=%s]" % (id, execution)) db_api.ensure_workflow_execution_exists(id) # Currently we can change only state. if not execution.state: raise exc.DataAccessException( "Only state of execution can change. " "Missing 'state' property." ) new_state = execution.state msg = execution.state_info if new_state == states.PAUSED: wf_ex = rpc.get_engine_client().pause_workflow(id) elif new_state == states.RUNNING: wf_ex = rpc.get_engine_client().resume_workflow(id) elif new_state in [states.SUCCESS, states.ERROR]: wf_ex = rpc.get_engine_client().stop_workflow(id, new_state, msg) else: # To prevent changing state in other cases throw a message. raise exc.DataAccessException( "Can not change state to %s. Allowed states are: '%s" % (new_state, ", ".join([states.RUNNING, states.PAUSED, states.SUCCESS, states.ERROR])) ) return Execution.from_dict( wf_ex if isinstance(wf_ex, dict) else wf_ex.to_dict() )
def post(self, execution): """Create a new Execution. :param execution: Execution object with input content. """ LOG.info("Create execution [execution=%s]" % execution) engine = rpc.get_engine_client() exec_dict = execution.to_dict() result = engine.start_workflow(exec_dict['workflow_name'], exec_dict.get('input'), exec_dict.get('description', ''), **exec_dict.get('params') or {}) return Execution.from_dict(result)
def post(self, execution): """Create a new Execution. :param execution: Execution object with input content. """ LOG.info("Create execution [execution=%s]" % execution) engine = rpc.get_engine_client() exec_dict = execution.to_dict() result = engine.start_workflow( exec_dict['workflow_name'], exec_dict.get('input'), **exec_dict.get('params') or {} ) return Execution.from_dict(result)
def launch_executor(transport): target = messaging.Target(topic=cfg.CONF.executor.topic, server=cfg.CONF.executor.host) executor_v2 = def_executor.DefaultExecutor(rpc.get_engine_client()) endpoints = [rpc.ExecutorServer(executor_v2)] server = messaging.get_rpc_server(transport, target, endpoints, executor='eventlet', serializer=ctx.RpcContextSerializer( ctx.JsonPayloadSerializer())) server.start() server.wait()
def post(self, action_ex): """Create new action_execution.""" acl.enforce('action_executions:create', context.ctx()) LOG.info("Create action_execution [action_execution=%s]" % action_ex) name = action_ex.name description = action_ex.description or None action_input = action_ex.input or {} params = action_ex.params or {} if not name: raise exc.InputException( "Please provide at least action name to run action.") action_ex = rpc.get_engine_client().start_action( name, action_input, description=description, **params) return ActionExecution.from_dict(action_ex)
def post(self, wf_ex): """Create a new Execution. :param wf_ex: Execution object with input content. """ LOG.info('Create execution [execution=%s]' % wf_ex) engine = rpc.get_engine_client() exec_dict = wf_ex.to_dict() result = engine.start_workflow( exec_dict['workflow_name'], exec_dict.get('input'), exec_dict.get('description', ''), **exec_dict.get('params') or {} ) return Execution.from_dict(result)
def launch_executor(transport): target = messaging.Target( topic=cfg.CONF.executor.topic, server=cfg.CONF.executor.host ) executor_v2 = def_executor.DefaultExecutor(rpc.get_engine_client()) endpoints = [rpc.ExecutorServer(executor_v2)] server = messaging.get_rpc_server( transport, target, endpoints, executor='eventlet', serializer=ctx.RpcContextSerializer(ctx.JsonPayloadSerializer()) ) server.start() server.wait()
def put(self, id, action_ex): """Update the specified action_execution.""" LOG.info( "Update action_execution [id=%s, action_execution=%s]" % (id, action_ex) ) if action_ex.state == states.SUCCESS: result = wf_utils.Result(data=action_ex.output) elif action_ex.state == states.ERROR: result = wf_utils.Result(error=action_ex.output) else: raise exc.InvalidResultException( "Error. Expected on of %s, actual: %s" % ([states.SUCCESS, states.ERROR], action_ex.state) ) values = rpc.get_engine_client().on_action_complete(id, result) return ActionExecution.from_dict(values)
def launch_engine(transport): profiler.setup('mistral-engine', cfg.CONF.engine.host) target = messaging.Target( topic=cfg.CONF.engine.topic, server=cfg.CONF.engine.host ) engine_v2 = def_eng.DefaultEngine(rpc.get_engine_client()) endpoints = [rpc.EngineServer(engine_v2)] # Setup scheduler in engine. db_api.setup_db() scheduler.setup() # Setup expiration policy expiration_policy.setup() get_rpc_server = get_rpc_server_function() server = get_rpc_server( transport, target, endpoints, executor='eventlet', serializer=ctx.RpcContextSerializer(ctx.JsonPayloadSerializer()) ) engine_v2.register_membership() try: server.start() while True: time.sleep(604800) except (KeyboardInterrupt, SystemExit): pass finally: print("Stopping engine service...") server.stop() server.wait()
def launch_engine(transport): target = messaging.Target(topic=cfg.CONF.engine.topic, server=cfg.CONF.engine.host) engine_v2 = def_eng.DefaultEngine(rpc.get_engine_client()) endpoints = [rpc.EngineServer(engine_v2)] # Setup scheduler in engine. db_api.setup_db() scheduler.setup() server = messaging.get_rpc_server(transport, target, endpoints, executor='eventlet', serializer=ctx.RpcContextSerializer( ctx.JsonPayloadSerializer())) server.start() server.wait()
def put(self, id, action_ex): """Update the specified action_execution.""" acl.enforce('action_executions:update', context.ctx()) LOG.info("Update action_execution [id=%s, action_execution=%s]" % (id, action_ex)) output = action_ex.output if action_ex.state == states.SUCCESS: result = wf_utils.Result(data=output) elif action_ex.state == states.ERROR: if not output: output = 'Unknown error' result = wf_utils.Result(error=output) else: raise exc.InvalidResultException( "Error. Expected on of %s, actual: %s" % ([states.SUCCESS, states.ERROR], action_ex.state)) values = rpc.get_engine_client().on_action_complete(id, result) return ActionExecution.from_dict(values)
def post(self, action_ex): """Create new action_execution.""" LOG.info("Create action_execution [action_execution=%s]" % action_ex) name = action_ex.name description = action_ex.description or None action_input = action_ex.input or {} params = action_ex.params or {} if not name: raise exc.InputException( "Please provide at least action name to run action." ) action_ex = rpc.get_engine_client().start_action( name, action_input, description=description, **params ) return ActionExecution.from_dict(action_ex)
def post(self, wf_ex): """Create a new Execution. :param wf_ex: Execution object with input content. """ LOG.info('Create execution [execution=%s]' % wf_ex) engine = rpc.get_engine_client() exec_dict = wf_ex.to_dict() if not (exec_dict.get('workflow_id') or exec_dict.get('workflow_name')): raise exc.WorkflowException( "Workflow ID or workflow name must be provided. Workflow ID is" " recommended.") result = engine.start_workflow( exec_dict.get('workflow_id', exec_dict.get('workflow_name')), exec_dict.get('input'), exec_dict.get('description', ''), **exec_dict.get('params') or {}) return Execution.from_dict(result)
def post(self, action_execution): """Create new action_execution.""" body = json.loads(pecan.request.body) LOG.info("Create action_execution [action_execution=%s]" % body) action_input = action_execution.input or None description = action_execution.description or None if action_input: try: action_input = json.loads(action_execution.input) if not isinstance(action_input, dict): raise TypeError("Input should be dict type.") except (TypeError, ValueError) as e: raise exc.InputException( "Input should be JSON-serialized dict string. Actual: %s, " "error: %s" % (action_execution.input, e) ) name = action_execution.name params = body.get('params', {}) if not name: raise exc.InputException( "Please provide at least action name to run action." ) action_ex = rpc.get_engine_client().start_action( name, action_input, description=description, **params ) return ActionExecution.from_dict(action_ex).to_dict()
def run_workflow(wf_name, wf_input, wf_params): rpc.get_engine_client().start_workflow( wf_name, wf_input, **wf_params )
task1: workflow: wf1 input: param1: <% env().var2 %> param2: <% env().var3 %> task_name: task2 publish: slogan: > <% task(task1).result.final_result %> is a cool <% env().var4 %>! """ def _run_at_target(action_ex_id, action_class_str, attributes, action_params, target=None, async=True): # We'll just call executor directly for testing purposes. executor = default_executor.DefaultExecutor(rpc.get_engine_client()) executor.run_action( action_ex_id, action_class_str, attributes, action_params ) MOCK_RUN_AT_TARGET = mock.MagicMock(side_effect=_run_at_target) class EnvironmentTest(base.EngineTestCase): def setUp(self): super(EnvironmentTest, self).setUp()
def put(self, id, wf_ex): """Update the specified workflow execution. :param id: execution ID. :param wf_ex: Execution object. """ LOG.info('Update execution [id=%s, execution=%s]' % (id, wf_ex)) db_api.ensure_workflow_execution_exists(id) delta = {} if wf_ex.state: delta['state'] = wf_ex.state if wf_ex.description: delta['description'] = wf_ex.description if wf_ex.params and wf_ex.params.get('env'): delta['env'] = wf_ex.params.get('env') # Currently we can change only state, description, or env. if len(delta.values()) <= 0: raise exc.InputException( 'The property state, description, or env ' 'is not provided for update.' ) # Description cannot be updated together with state. if delta.get('description') and delta.get('state'): raise exc.InputException( 'The property description must be updated ' 'separately from state.' ) # If state change, environment cannot be updated if not RUNNING. if (delta.get('env') and delta.get('state') and delta['state'] != states.RUNNING): raise exc.InputException( 'The property env can only be updated when workflow ' 'execution is not running or on resume from pause.' ) if delta.get('description'): wf_ex = db_api.update_workflow_execution( id, {'description': delta['description']} ) if not delta.get('state') and delta.get('env'): with db_api.transaction(): wf_ex = db_api.get_workflow_execution(id) wf_ex = wf_service.update_workflow_execution_env( wf_ex, delta.get('env') ) if delta.get('state'): if delta.get('state') == states.PAUSED: wf_ex = rpc.get_engine_client().pause_workflow(id) elif delta.get('state') == states.RUNNING: wf_ex = rpc.get_engine_client().resume_workflow( id, env=delta.get('env') ) elif delta.get('state') in [states.SUCCESS, states.ERROR]: msg = wf_ex.state_info if wf_ex.state_info else None wf_ex = rpc.get_engine_client().stop_workflow( id, delta.get('state'), msg ) else: # To prevent changing state in other cases throw a message. raise exc.InputException( "Cannot change state to %s. Allowed states are: '%s" % ( wf_ex.state, ', '.join([ states.RUNNING, states.PAUSED, states.SUCCESS, states.ERROR ]) ) ) return Execution.from_dict( wf_ex if isinstance(wf_ex, dict) else wf_ex.to_dict() )
def resume_workflow(wf_ex_id, env): rpc.get_engine_client().resume_workflow(wf_ex_id, env=env)
param2: <% env().var3 %> task_name: task2 publish: slogan: > <% task(task1).result.final_result %> is a cool <% env().var4 %>! """ def _run_at_target(action_ex_id, action_class_str, attributes, action_params, target=None, async=True): # We'll just call executor directly for testing purposes. executor = default_executor.DefaultExecutor(rpc.get_engine_client()) executor.run_action(action_ex_id, action_class_str, attributes, action_params) MOCK_RUN_AT_TARGET = mock.MagicMock(side_effect=_run_at_target) class EnvironmentTest(base.EngineTestCase): def setUp(self): super(EnvironmentTest, self).setUp() wb_service.create_workbook_v2(WORKBOOK) @mock.patch.object(rpc.ExecutorClient, 'run_action', MOCK_RUN_AT_TARGET)
def put(self, id, wf_ex): """Update the specified workflow execution. :param id: execution ID. :param wf_ex: Execution object. """ LOG.info('Update execution [id=%s, execution=%s]' % (id, wf_ex)) db_api.ensure_workflow_execution_exists(id) delta = {} if wf_ex.state: delta['state'] = wf_ex.state if wf_ex.description: delta['description'] = wf_ex.description if wf_ex.params and wf_ex.params.get('env'): delta['env'] = wf_ex.params.get('env') # Currently we can change only state, description, or env. if len(delta.values()) <= 0: raise exc.InputException('The property state, description, or env ' 'is not provided for update.') # Description cannot be updated together with state. if delta.get('description') and delta.get('state'): raise exc.InputException( 'The property description must be updated ' 'separately from state.') # If state change, environment cannot be updated if not RUNNING. if (delta.get('env') and delta.get('state') and delta['state'] != states.RUNNING): raise exc.InputException( 'The property env can only be updated when workflow ' 'execution is not running or on resume from pause.') if delta.get('description'): wf_ex = db_api.update_workflow_execution( id, {'description': delta['description']}) if not delta.get('state') and delta.get('env'): with db_api.transaction(): wf_ex = db_api.get_workflow_execution(id) wf_ex = wf_service.update_workflow_execution_env( wf_ex, delta.get('env')) if delta.get('state'): if delta.get('state') == states.PAUSED: wf_ex = rpc.get_engine_client().pause_workflow(id) elif delta.get('state') == states.RUNNING: wf_ex = rpc.get_engine_client().resume_workflow( id, env=delta.get('env')) elif delta.get('state') in [states.SUCCESS, states.ERROR]: msg = wf_ex.state_info if wf_ex.state_info else None wf_ex = rpc.get_engine_client().stop_workflow( id, delta.get('state'), msg) else: # To prevent changing state in other cases throw a message. raise exc.InputException( "Cannot change state to %s. Allowed states are: '%s" % (wf_ex.state, ', '.join([ states.RUNNING, states.PAUSED, states.SUCCESS, states.ERROR ]))) return Execution.from_dict( wf_ex if isinstance(wf_ex, dict) else wf_ex.to_dict())
def run_workflow(wf_name, wf_input, wf_params): rpc.get_engine_client().start_workflow(wf_name, wf_input, "sub-workflow execution", **wf_params)