def _get_next_action(self, action_node, parent_context, action_params, context_result): # Verify that the referenced action exists # TODO: We do another lookup in cast_param, refactor to reduce number of lookups task_name = action_node.name action_ref = action_node.ref action_db = action_db_util.get_action_by_ref(ref=action_ref) if not action_db: error = 'Task :: %s - Action with ref %s not registered.' % ( task_name, action_ref) raise action_exc.InvalidActionReferencedException(error) resolved_params = ActionChainRunner._resolve_params( action_node=action_node, original_parameters=action_params, results=context_result, chain_vars=self.chain_holder.vars, chain_context={'parent': parent_context}) liveaction = self._build_liveaction_object( action_node=action_node, resolved_params=resolved_params, parent_context=parent_context) return liveaction
def request_action_execution(wf_ex_db, task_ex_db, st2_ctx, ac_ex_req): wf_ac_ex_id = wf_ex_db.action_execution action_ref = ac_ex_req['action'] action_input = ac_ex_req['input'] item_id = ac_ex_req.get('item_id') # If the task is with items and item_id is not provided, raise exception. if task_ex_db.itemized and item_id is None: msg = 'Unable to request action execution. Identifier for the item is not provided.' raise Exception(msg) # Identify the action to execute. action_db = action_utils.get_action_by_ref(ref=action_ref) if not action_db: error = 'Unable to find action "%s".' % action_ref raise ac_exc.InvalidActionReferencedException(error) # Identify the runner for the action. runner_type_db = action_utils.get_runnertype_by_name( action_db.runner_type['name']) # Set context for the action execution. ac_ex_ctx = { 'parent': st2_ctx, 'orquesta': { 'workflow_execution_id': str(wf_ex_db.id), 'task_execution_id': str(task_ex_db.id), 'task_name': task_ex_db.task_name, 'task_id': task_ex_db.task_id } } if item_id is not None: ac_ex_ctx['orquesta']['item_id'] = item_id # Render action execution parameters and setup action execution object. ac_ex_params = param_utils.render_live_params( runner_type_db.runner_parameters or {}, action_db.parameters or {}, action_input or {}, ac_ex_ctx) lv_ac_db = lv_db_models.LiveActionDB(action=action_ref, workflow_execution=str(wf_ex_db.id), task_execution=str(task_ex_db.id), context=ac_ex_ctx, parameters=ac_ex_params) # Set the task execution to running first otherwise a race can occur # where the action execution finishes first and the completion handler # conflicts with this status update. task_ex_db.status = states.RUNNING task_ex_db = wf_db_access.TaskExecution.update(task_ex_db, publish=False) # Request action execution. lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) msg = '[%s] Action execution "%s" requested for task "%s".' LOG.info(msg, wf_ac_ex_id, str(ac_ex_db.id), task_ex_db.task_id) return ac_ex_db
def request(wf_def, ac_ex_db, st2_ctx): wf_ac_ex_id = str(ac_ex_db.id) LOG.info('[%s] Processing action execution request for workflow.', wf_ac_ex_id) # Load workflow definition into workflow spec model. spec_module = specs_loader.get_spec_module('native') wf_spec = spec_module.instantiate(wf_def) # Inspect the workflow spec. inspect(wf_spec, st2_ctx, raise_exception=True) # Identify the action to execute. action_db = action_utils.get_action_by_ref(ref=ac_ex_db.action['ref']) if not action_db: error = 'Unable to find action "%s".' % ac_ex_db.action['ref'] raise ac_exc.InvalidActionReferencedException(error) # Identify the runner for the action. runner_type_db = action_utils.get_runnertype_by_name( action_db.runner_type['name']) # Render action execution parameters. runner_params, action_params = param_utils.render_final_params( runner_type_db.runner_parameters, action_db.parameters, ac_ex_db.parameters, ac_ex_db.context) # Instantiate the workflow conductor. conductor_params = {'inputs': action_params, 'context': st2_ctx} conductor = conducting.WorkflowConductor(wf_spec, **conductor_params) # Set the initial workflow state to requested. conductor.request_workflow_state(states.REQUESTED) # Serialize the conductor which initializes some internal values. data = conductor.serialize() # Create a record for workflow execution. wf_ex_db = wf_db_models.WorkflowExecutionDB(action_execution=str( ac_ex_db.id), spec=data['spec'], graph=data['graph'], flow=data['flow'], context=data['context'], input=data['input'], output=data['output'], errors=data['errors'], status=data['state']) # Insert new record into the database and publish to the message bus. wf_ex_db = wf_db_access.WorkflowExecution.insert(wf_ex_db, publish=True) LOG.info('[%s] Workflow execution "%s" created.', wf_ac_ex_id, str(wf_ex_db.id)) return wf_ex_db
def request_task_execution(wf_ex_db, task_id, task_spec, task_ctx, st2_ctx): wf_ac_ex_id = wf_ex_db.action_execution LOG.info('[%s] Processing task execution request for "%s".', wf_ac_ex_id, task_id) # Create a record for task execution. task_ex_db = wf_db_models.TaskExecutionDB( workflow_execution=str(wf_ex_db.id), task_name=task_spec.name or task_id, task_id=task_id, task_spec=task_spec.serialize(), context=task_ctx, status=states.REQUESTED) # Insert new record into the database. task_ex_db = wf_db_access.TaskExecution.insert(task_ex_db, publish=False) task_ex_id = str(task_ex_db.id) LOG.info('[%s] Task execution "%s" created for task "%s".', wf_ac_ex_id, task_ex_id, task_id) try: # Return here if no action is specified in task spec. if task_spec.action is None: # Set the task execution to running. task_ex_db.status = states.RUNNING task_ex_db = wf_db_access.TaskExecution.update(task_ex_db, publish=False) # Fast forward task execution to completion. update_task_execution(str(task_ex_db.id), states.SUCCEEDED) update_task_flow(str(task_ex_db.id), publish=False) # Refresh and return the task execution return wf_db_access.TaskExecution.get_by_id(str(task_ex_db.id)) # Identify the action to execute. action_db = action_utils.get_action_by_ref(ref=task_spec.action) if not action_db: error = 'Unable to find action "%s".' % task_spec.action raise ac_exc.InvalidActionReferencedException(error) # Identify the runner for the action. runner_type_db = action_utils.get_runnertype_by_name( action_db.runner_type['name']) # Set context for the action execution. ac_ex_ctx = { 'parent': st2_ctx, 'orquesta': { 'workflow_execution_id': str(wf_ex_db.id), 'task_execution_id': str(task_ex_db.id), 'task_name': task_spec.name or task_id, 'task_id': task_id } } # Render action execution parameters and setup action execution object. ac_ex_params = param_utils.render_live_params( runner_type_db.runner_parameters or {}, action_db.parameters or {}, getattr(task_spec, 'input', None) or {}, ac_ex_ctx) lv_ac_db = lv_db_models.LiveActionDB(action=task_spec.action, workflow_execution=str( wf_ex_db.id), task_execution=str(task_ex_db.id), context=ac_ex_ctx, parameters=ac_ex_params) # Set the task execution to running first otherwise a race can occur # where the action execution finishes first and the completion handler # conflicts with this status update. task_ex_db.status = states.RUNNING task_ex_db = wf_db_access.TaskExecution.update(task_ex_db, publish=False) # Request action execution. lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) msg = '[%s] Action execution "%s" requested for task "%s".' LOG.info(msg, wf_ac_ex_id, str(ac_ex_db.id), task_id) except Exception as e: LOG.exception('[%s] Failed task execution for task "%s".', wf_ac_ex_id, task_id) result = { 'errors': [{ 'message': str(e), 'task_id': task_ex_db.task_id }] } update_task_execution(str(task_ex_db.id), states.FAILED, result) raise e return task_ex_db
def request_action_execution(wf_ex_db, task_ex_db, st2_ctx, ac_ex_req, delay=None): wf_ac_ex_id = wf_ex_db.action_execution action_ref = ac_ex_req['action'] action_input = ac_ex_req['input'] item_id = ac_ex_req.get('item_id') # If the task is with items and item_id is not provided, raise exception. if task_ex_db.itemized and item_id is None: msg = 'Unable to request action execution. Identifier for the item is not provided.' raise Exception(msg) # Identify the action to execute. action_db = action_utils.get_action_by_ref(ref=action_ref) if not action_db: error = 'Unable to find action "%s".' % action_ref raise ac_exc.InvalidActionReferencedException(error) # Identify the runner for the action. runner_type_db = action_utils.get_runnertype_by_name( action_db.runner_type['name']) # Identify action pack name pack_name = action_ref.split('.')[0] if action_ref else st2_ctx.get('pack') # Set context for the action execution. ac_ex_ctx = { 'pack': pack_name, 'user': st2_ctx.get('user'), 'parent': st2_ctx, 'orquesta': { 'workflow_execution_id': str(wf_ex_db.id), 'task_execution_id': str(task_ex_db.id), 'task_name': task_ex_db.task_name, 'task_id': task_ex_db.task_id, 'task_route': task_ex_db.task_route } } if st2_ctx.get('api_user'): ac_ex_ctx['api_user'] = st2_ctx.get('api_user') if st2_ctx.get('source_channel'): ac_ex_ctx['source_channel'] = st2_ctx.get('source_channel') if item_id is not None: ac_ex_ctx['orquesta']['item_id'] = item_id # Render action execution parameters and setup action execution object. ac_ex_params = param_utils.render_live_params( runner_type_db.runner_parameters or {}, action_db.parameters or {}, action_input or {}, ac_ex_ctx) # The delay spec is in seconds and scheduler expects milliseconds. if delay is not None and delay > 0: delay = delay * 1000 # Instantiate the live action record. lv_ac_db = lv_db_models.LiveActionDB(action=action_ref, workflow_execution=str(wf_ex_db.id), task_execution=str(task_ex_db.id), delay=delay, context=ac_ex_ctx, parameters=ac_ex_params) # Set notification if instructed. if (wf_ex_db.notify and wf_ex_db.notify.get('config') and wf_ex_db.notify.get('tasks') and task_ex_db.task_name in wf_ex_db.notify['tasks']): lv_ac_db.notify = notify_api_models.NotificationsHelper.to_model( wf_ex_db.notify['config']) # Set the task execution to running first otherwise a race can occur # where the action execution finishes first and the completion handler # conflicts with this status update. task_ex_db.status = statuses.RUNNING task_ex_db = wf_db_access.TaskExecution.update(task_ex_db, publish=False) # Request action execution. lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) msg = '[%s] Action execution "%s" requested for task "%s", route "%s".' LOG.info(msg, wf_ac_ex_id, str(ac_ex_db.id), task_ex_db.task_id, str(task_ex_db.task_route)) return ac_ex_db
def request(wf_def, ac_ex_db, st2_ctx, notify_cfg=None): wf_ac_ex_id = str(ac_ex_db.id) LOG.info('[%s] Processing action execution request for workflow.', wf_ac_ex_id) # Load workflow definition into workflow spec model. spec_module = specs_loader.get_spec_module('native') wf_spec = spec_module.instantiate(wf_def) # Inspect the workflow spec. inspect(wf_spec, st2_ctx, raise_exception=True) # Identify the action to execute. action_db = action_utils.get_action_by_ref(ref=ac_ex_db.action['ref']) if not action_db: error = 'Unable to find action "%s".' % ac_ex_db.action['ref'] raise ac_exc.InvalidActionReferencedException(error) # Identify the runner for the action. runner_type_db = action_utils.get_runnertype_by_name( action_db.runner_type['name']) # Render action execution parameters. runner_params, action_params = param_utils.render_final_params( runner_type_db.runner_parameters, action_db.parameters, ac_ex_db.parameters, ac_ex_db.context) # Instantiate the workflow conductor. conductor_params = {'inputs': action_params, 'context': st2_ctx} conductor = conducting.WorkflowConductor(wf_spec, **conductor_params) # Serialize the conductor which initializes some internal values. data = conductor.serialize() # Create a record for workflow execution. wf_ex_db = wf_db_models.WorkflowExecutionDB(action_execution=str( ac_ex_db.id), spec=data['spec'], graph=data['graph'], input=data['input'], context=data['context'], state=data['state'], status=data['state']['status'], output=data['output'], errors=data['errors']) # Inspect that the list of tasks in the notify parameter exist in the workflow spec. if runner_params.get('notify'): invalid_tasks = list( set(runner_params.get('notify')) - set(wf_spec.tasks.keys())) if invalid_tasks: raise wf_exc.WorkflowExecutionException( 'The following tasks in the notify parameter do not exist ' 'in the workflow definition: %s.' % ', '.join(invalid_tasks)) # Write notify instruction to record. if notify_cfg: # Set up the notify instruction in the workflow execution record. wf_ex_db.notify = { 'config': notify_cfg, 'tasks': runner_params.get('notify') } # Insert new record into the database and do not publish to the message bus yet. wf_ex_db = wf_db_access.WorkflowExecution.insert(wf_ex_db, publish=False) LOG.info('[%s] Workflow execution "%s" is created.', wf_ac_ex_id, str(wf_ex_db.id)) # Update the context with the workflow execution id created on database insert. # Publish the workflow execution requested status to the message bus. if wf_ex_db.status not in statuses.COMPLETED_STATUSES: # Set the initial workflow status to requested. conductor.request_workflow_status(statuses.REQUESTED) data = conductor.serialize() wf_ex_db.state = data['state'] wf_ex_db.status = data['state']['status'] # Put the ID of the workflow execution record in the context. wf_ex_db.context['st2']['workflow_execution_id'] = str(wf_ex_db.id) wf_ex_db.state['contexts'][0]['st2']['workflow_execution_id'] = str( wf_ex_db.id) # Update the workflow execution record. wf_ex_db = wf_db_access.WorkflowExecution.update(wf_ex_db, publish=False) wf_db_access.WorkflowExecution.publish_status(wf_ex_db) msg = '[%s] Workflow execution "%s" is published.' LOG.info(msg, wf_ac_ex_id, str(wf_ex_db.id)) else: msg = '[%s] Unable to request workflow execution. It is already in completed status "%s".' LOG.info(msg, wf_ac_ex_id, wf_ex_db.status) return wf_ex_db