예제 #1
0
    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
예제 #2
0
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
예제 #3
0
파일: workflows.py 프로젝트: shusugmt/st2
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
예제 #4
0
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
예제 #5
0
파일: workflows.py 프로젝트: jayd2446/st2
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
예제 #6
0
파일: workflows.py 프로젝트: jayd2446/st2
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