Ejemplo n.º 1
0
    def test_task_execution_write_conflict(self):
        initial = wf_db_models.TaskExecutionDB()
        initial.workflow_execution = uuid.uuid4().hex
        initial.task_name = "t1"
        initial.task_id = "t1"
        initial.task_route = 0
        initial.task_spec = {"tasks": {"t1": "some task"}}
        initial.delay = 180
        initial.status = "requested"
        initial.context = {"var1": "foobar"}

        # Prep record
        created = wf_db_access.TaskExecution.add_or_update(initial)
        self.assertEqual(initial.rev, 1)
        doc_id = created.id

        # Get two separate instances of the document.
        retrieved1 = wf_db_access.TaskExecution.get_by_id(doc_id)
        retrieved2 = wf_db_access.TaskExecution.get_by_id(doc_id)

        # Test update on instance 1, expect success
        status = "running"
        retrieved1 = wf_db_access.TaskExecution.update(retrieved1,
                                                       status=status)
        updated = wf_db_access.TaskExecution.get_by_id(doc_id)
        self.assertNotEqual(created.rev, updated.rev)
        self.assertEqual(retrieved1.rev, updated.rev)
        self.assertEqual(updated.workflow_execution,
                         retrieved1.workflow_execution)
        self.assertEqual(updated.task_name, retrieved1.task_name)
        self.assertEqual(updated.task_id, retrieved1.task_id)
        self.assertEqual(updated.task_route, retrieved1.task_route)
        self.assertDictEqual(updated.task_spec, retrieved1.task_spec)
        self.assertEqual(updated.delay, retrieved1.delay)
        self.assertEqual(updated.itemized, retrieved1.itemized)
        self.assertEqual(updated.status, retrieved1.status)
        self.assertIsNotNone(updated.start_timestamp)
        self.assertIsNone(updated.end_timestamp)
        self.assertDictEqual(updated.context, retrieved1.context)

        # Test update on instance 2, expect race error
        self.assertRaises(
            db_exc.StackStormDBObjectWriteConflictError,
            wf_db_access.TaskExecution.update,
            retrieved2,
            status="pausing",
        )

        # Test delete
        created.delete()

        self.assertRaises(
            db_exc.StackStormDBObjectNotFoundError,
            wf_db_access.TaskExecution.get_by_id,
            doc_id,
        )
Ejemplo n.º 2
0
    def test_task_execution_write_conflict(self):
        initial = wf_db_models.TaskExecutionDB()
        initial.workflow_execution = uuid.uuid4().hex
        initial.task_name = 't1'
        initial.task_id = 't1'
        initial.task_spec = {'tasks': {'t1': 'some task'}}
        initial.status = 'requested'
        initial.initial_context = {'var1': 'foobar'}

        # Prep record
        created = wf_db_access.TaskExecution.add_or_update(initial)
        self.assertEqual(initial.rev, 1)
        doc_id = created.id

        # Get two separate instances of the document.
        retrieved1 = wf_db_access.TaskExecution.get_by_id(doc_id)
        retrieved2 = wf_db_access.TaskExecution.get_by_id(doc_id)

        # Test update on instance 1, expect success
        status = 'running'
        retrieved1 = wf_db_access.TaskExecution.update(retrieved1,
                                                       status=status)
        updated = wf_db_access.TaskExecution.get_by_id(doc_id)
        self.assertNotEqual(created.rev, updated.rev)
        self.assertEqual(retrieved1.rev, updated.rev)
        self.assertEqual(updated.workflow_execution,
                         retrieved1.workflow_execution)
        self.assertEqual(updated.task_name, retrieved1.task_name)
        self.assertEqual(updated.task_id, retrieved1.task_id)
        self.assertDictEqual(updated.task_spec, retrieved1.task_spec)
        self.assertEqual(updated.status, retrieved1.status)
        self.assertIsNotNone(updated.start_timestamp)
        self.assertIsNone(updated.end_timestamp)
        self.assertDictEqual(updated.initial_context,
                             retrieved1.initial_context)

        # Test update on instance 2, expect race error
        self.assertRaises(db_exc.StackStormDBObjectWriteConflictError,
                          wf_db_access.TaskExecution.update,
                          retrieved2,
                          status='pausing')

        # Test delete
        created.delete()

        self.assertRaises(db_exc.StackStormDBObjectNotFoundError,
                          wf_db_access.TaskExecution.get_by_id, doc_id)
Ejemplo n.º 3
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
Ejemplo n.º 4
0
def request_task_execution(wf_ex_db, st2_ctx, task_ex_req):
    wf_ac_ex_id = wf_ex_db.action_execution
    task_id = task_ex_req['id']
    task_route = task_ex_req['route']
    task_spec = task_ex_req['spec']
    task_ctx = task_ex_req['ctx']
    task_actions = task_ex_req['actions']
    task_delay = task_ex_req.get('delay')

    msg = '[%s] Processing task execution request for task "%s", route "%s".'
    LOG.info(msg, wf_ac_ex_id, task_id, str(task_route))

    # Use existing task execution when task is with items and still running.
    task_ex_dbs = wf_db_access.TaskExecution.query(
        workflow_execution=str(wf_ex_db.id),
        task_id=task_id,
        task_route=task_route,
        order_by=['-start_timestamp'])

    if (len(task_ex_dbs) > 0 and task_ex_dbs[0].itemized
            and task_ex_dbs[0].status == ac_const.LIVEACTION_STATUS_RUNNING):
        task_ex_db = task_ex_dbs[0]
        task_ex_id = str(task_ex_db.id)
        msg = '[%s] Task execution "%s" retrieved for task "%s", route "%s".'
        LOG.info(msg, wf_ac_ex_id, task_ex_id, task_id, str(task_route))
    else:
        # 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_route=task_route,
            task_spec=task_spec.serialize(),
            delay=task_delay,
            itemized=task_spec.has_items(),
            items_count=task_ex_req.get('items_count'),
            items_concurrency=task_ex_req.get('concurrency'),
            context=task_ctx,
            status=statuses.REQUESTED)

        # Prepare the result format for itemized task execution.
        if task_ex_db.itemized:
            task_ex_db.result = {'items': [None] * task_ex_db.items_count}

        # 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)
        msg = '[%s] Task execution "%s" created for task "%s", route "%s".'
        LOG.info(msg, wf_ac_ex_id, task_ex_id, task_id, str(task_route))

    try:
        # Return here if no action is specified in task spec.
        if task_spec.action is None:
            msg = '[%s] Task "%s", route "%s", is action less and succeed by default.'
            LOG.info(msg, wf_ac_ex_id, task_id, str(task_route))

            # Set the task execution to running.
            task_ex_db.status = statuses.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), statuses.SUCCEEDED)
            update_task_state(str(task_ex_db.id),
                              statuses.SUCCEEDED,
                              publish=False)

            # Refresh and return the task execution
            return wf_db_access.TaskExecution.get_by_id(str(task_ex_db.id))

        # Return here for task with items but the items list is empty.
        if task_ex_db.itemized and task_ex_db.items_count == 0:
            msg = '[%s] Task "%s", route "%s", has no items and succeed by default.'
            LOG.info(msg, wf_ac_ex_id, task_id, str(task_route))

            # Set the task execution to running.
            task_ex_db.status = statuses.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), statuses.SUCCEEDED)
            update_task_state(str(task_ex_db.id),
                              statuses.SUCCEEDED,
                              publish=False)

            # Refresh and return the task execution
            return wf_db_access.TaskExecution.get_by_id(str(task_ex_db.id))

        # Request action execution for each actions in the task request.
        for ac_ex_req in task_actions:
            ac_ex_delay = eval_action_execution_delay(task_ex_req, ac_ex_req,
                                                      task_ex_db.itemized)
            request_action_execution(wf_ex_db,
                                     task_ex_db,
                                     st2_ctx,
                                     ac_ex_req,
                                     delay=ac_ex_delay)
            task_ex_db = wf_db_access.TaskExecution.get_by_id(
                str(task_ex_db.id))
    except Exception as e:
        msg = '[%s] Failed action execution(s) for task "%s", route "%s". %s'
        LOG.exception(msg, wf_ac_ex_id, task_id, str(task_route),
                      six.text_type(e))
        message = '%s: %s' % (type(e).__name__, six.text_type(e))
        error = {
            'type': 'error',
            'message': message,
            'task_id': task_id,
            'route': task_route
        }
        update_task_execution(str(task_ex_db.id), statuses.FAILED,
                              {'errors': [error]})
        raise e

    return task_ex_db
    def mock_task_records(self,
                          parent,
                          task_id,
                          task_route=0,
                          completed=True,
                          expired=False,
                          log=True):
        if not completed and expired:
            raise ValueError(
                "Task must be set completed=True if expired=True.")

        status = (ac_const.LIVEACTION_STATUS_SUCCEEDED
                  if completed else ac_const.LIVEACTION_STATUS_RUNNING)

        parent_wf_ex_db, parent_ac_ex_db = parent[0], parent[2]

        # Identify end timestamp
        gc_max_idle = cfg.CONF.workflow_engine.gc_max_idle_sec
        utc_now_dt = date_utils.get_datetime_utc_now()
        expiry_dt = utc_now_dt - datetime.timedelta(seconds=gc_max_idle + 10)
        end_timestamp = expiry_dt if expired else utc_now_dt

        # Assign metadata.
        action_ref = "core.local"
        runner = "local-shell-cmd"
        user = "******"

        # Create the TaskExecutionDB record first since the ID needs to be
        # included in the LiveActionDB and ActionExecutionDB records.
        tk_ex_db = wf_db_models.TaskExecutionDB(
            workflow_execution=str(parent_wf_ex_db.id),
            task_id=task_id,
            task_route=0,
            status=status,
            start_timestamp=parent_wf_ex_db.start_timestamp,
        )

        if status in ac_const.LIVEACTION_COMPLETED_STATES:
            tk_ex_db.end_timestamp = end_timestamp if expired else utc_now_dt

        tk_ex_db = wf_db_access.TaskExecution.insert(tk_ex_db, publish=False)

        # Build context for LiveActionDB and ActionExecutionDB.
        context = {
            "user": user,
            "orquesta": {
                "task_id": tk_ex_db.task_id,
                "task_name": tk_ex_db.task_id,
                "workflow_execution_id": str(parent_wf_ex_db.id),
                "task_execution_id": str(tk_ex_db.id),
                "task_route": tk_ex_db.task_route,
            },
            "parent": {
                "user": user,
                "execution_id": str(parent_ac_ex_db.id)
            },
        }

        # Create the LiveActionDB record.
        lv_ac_db = lv_db_models.LiveActionDB(
            workflow_execution=str(parent_wf_ex_db.id),
            task_execution=str(tk_ex_db.id),
            action=action_ref,
            action_is_workflow=False,
            context=context,
            status=status,
            start_timestamp=tk_ex_db.start_timestamp,
            end_timestamp=tk_ex_db.end_timestamp,
        )

        lv_ac_db = lv_db_access.LiveAction.insert(lv_ac_db, publish=False)

        # Create the ActionExecutionDB record.
        ac_ex_db = ex_db_models.ActionExecutionDB(
            workflow_execution=str(parent_wf_ex_db.id),
            task_execution=str(tk_ex_db.id),
            action={
                "runner_type": runner,
                "ref": action_ref
            },
            runner={"name": runner},
            liveaction={"id": str(lv_ac_db.id)},
            context=context,
            status=status,
            start_timestamp=tk_ex_db.start_timestamp,
            end_timestamp=tk_ex_db.end_timestamp,
        )

        if log:
            ac_ex_db.log = [{
                "status": "running",
                "timestamp": tk_ex_db.start_timestamp
            }]

        if log and status in ac_const.LIVEACTION_COMPLETED_STATES:
            ac_ex_db.log.append({
                "status": status,
                "timestamp": tk_ex_db.end_timestamp
            })

        ac_ex_db = ex_db_access.ActionExecution.insert(ac_ex_db, publish=False)

        return tk_ex_db, lv_ac_db, ac_ex_db
Ejemplo n.º 6
0
    def test_task_execution_crud(self):
        initial = wf_db_models.TaskExecutionDB()
        initial.workflow_execution = uuid.uuid4().hex
        initial.task_name = 't1'
        initial.task_id = 't1'
        initial.task_spec = {'tasks': {'t1': 'some task'}}
        initial.status = 'requested'
        initial.initial_context = {'var1': 'foobar'}

        # Test create
        created = wf_db_access.TaskExecution.add_or_update(initial)
        self.assertEqual(initial.rev, 1)
        doc_id = created.id

        # Test read
        retrieved = wf_db_access.TaskExecution.get_by_id(doc_id)
        self.assertEqual(created.workflow_execution,
                         retrieved.workflow_execution)
        self.assertEqual(created.task_name, retrieved.task_name)
        self.assertEqual(created.task_id, retrieved.task_id)
        self.assertDictEqual(created.task_spec, retrieved.task_spec)
        self.assertEqual(created.status, retrieved.status)
        self.assertIsNotNone(created.start_timestamp)
        self.assertIsNone(created.end_timestamp)
        self.assertDictEqual(created.initial_context,
                             retrieved.initial_context)

        # Test update
        status = 'running'
        retrieved = wf_db_access.TaskExecution.update(retrieved, status=status)
        updated = wf_db_access.TaskExecution.get_by_id(doc_id)
        self.assertNotEqual(created.rev, updated.rev)
        self.assertEqual(retrieved.rev, updated.rev)
        self.assertEqual(updated.workflow_execution,
                         retrieved.workflow_execution)
        self.assertEqual(updated.task_name, retrieved.task_name)
        self.assertEqual(updated.task_id, retrieved.task_id)
        self.assertDictEqual(updated.task_spec, retrieved.task_spec)
        self.assertEqual(updated.status, retrieved.status)
        self.assertIsNotNone(updated.start_timestamp)
        self.assertIsNone(updated.end_timestamp)
        self.assertDictEqual(updated.initial_context,
                             retrieved.initial_context)

        # Test add or update
        retrieved.result = {'output': 'fubar'}
        retrieved.status = 'succeeded'
        retrieved.end_timestamp = date_utils.get_datetime_utc_now()
        retrieved = wf_db_access.TaskExecution.add_or_update(retrieved)
        updated = wf_db_access.TaskExecution.get_by_id(doc_id)
        self.assertNotEqual(created.rev, updated.rev)
        self.assertEqual(retrieved.rev, updated.rev)
        self.assertEqual(updated.workflow_execution,
                         retrieved.workflow_execution)
        self.assertEqual(updated.task_name, retrieved.task_name)
        self.assertEqual(updated.task_id, retrieved.task_id)
        self.assertDictEqual(updated.task_spec, retrieved.task_spec)
        self.assertEqual(updated.status, retrieved.status)
        self.assertIsNotNone(updated.start_timestamp)
        self.assertIsNotNone(updated.end_timestamp)
        self.assertDictEqual(updated.initial_context,
                             retrieved.initial_context)
        self.assertDictEqual(updated.result, retrieved.result)

        # Test delete
        created.delete()

        self.assertRaises(db_exc.StackStormDBObjectNotFoundError,
                          wf_db_access.TaskExecution.get_by_id, doc_id)
Ejemplo n.º 7
0
    def mock_task_records(self,
                          parent,
                          task_id,
                          task_route=0,
                          completed=True,
                          expired=False,
                          log=True):
        if not completed and expired:
            raise ValueError(
                'Task must be set completed=True if expired=True.')

        status = (ac_const.LIVEACTION_STATUS_SUCCEEDED
                  if completed else ac_const.LIVEACTION_STATUS_RUNNING)

        parent_wf_ex_db, parent_ac_ex_db = parent[0], parent[2]

        # Identify end timestamp
        gc_max_idle = cfg.CONF.workflow_engine.gc_max_idle_sec
        utc_now_dt = date_utils.get_datetime_utc_now()
        expiry_dt = utc_now_dt - datetime.timedelta(seconds=gc_max_idle + 10)
        end_timestamp = expiry_dt if expired else utc_now_dt

        # Assign metadata.
        action_ref = 'core.local'
        runner = 'local-shell-cmd'
        user = '******'

        # Create the TaskExecutionDB record first since the ID needs to be
        # included in the LiveActionDB and ActionExecutionDB records.
        tk_ex_db = wf_db_models.TaskExecutionDB(
            workflow_execution=str(parent_wf_ex_db.id),
            task_id=task_id,
            task_route=0,
            status=status,
            start_timestamp=parent_wf_ex_db.start_timestamp)

        if status in ac_const.LIVEACTION_COMPLETED_STATES:
            tk_ex_db.end_timestamp = end_timestamp if expired else utc_now_dt

        tk_ex_db = wf_db_access.TaskExecution.insert(tk_ex_db, publish=False)

        # Build context for LiveActionDB and ActionExecutionDB.
        context = {
            'user': user,
            'orquesta': {
                'task_id': tk_ex_db.task_id,
                'task_name': tk_ex_db.task_id,
                'workflow_execution_id': str(parent_wf_ex_db.id),
                'task_execution_id': str(tk_ex_db.id),
                'task_route': tk_ex_db.task_route
            },
            'parent': {
                'user': user,
                'execution_id': str(parent_ac_ex_db.id)
            }
        }

        # Create the LiveActionDB record.
        lv_ac_db = lv_db_models.LiveActionDB(
            workflow_execution=str(parent_wf_ex_db.id),
            task_execution=str(tk_ex_db.id),
            action=action_ref,
            action_is_workflow=False,
            context=context,
            status=status,
            start_timestamp=tk_ex_db.start_timestamp,
            end_timestamp=tk_ex_db.end_timestamp)

        lv_ac_db = lv_db_access.LiveAction.insert(lv_ac_db, publish=False)

        # Create the ActionExecutionDB record.
        ac_ex_db = ex_db_models.ActionExecutionDB(
            workflow_execution=str(parent_wf_ex_db.id),
            task_execution=str(tk_ex_db.id),
            action={
                'runner_type': runner,
                'ref': action_ref
            },
            runner={'name': runner},
            liveaction={'id': str(lv_ac_db.id)},
            context=context,
            status=status,
            start_timestamp=tk_ex_db.start_timestamp,
            end_timestamp=tk_ex_db.end_timestamp)

        if log:
            ac_ex_db.log = [{
                'status': 'running',
                'timestamp': tk_ex_db.start_timestamp
            }]

        if log and status in ac_const.LIVEACTION_COMPLETED_STATES:
            ac_ex_db.log.append({
                'status': status,
                'timestamp': tk_ex_db.end_timestamp
            })

        ac_ex_db = ex_db_access.ActionExecution.insert(ac_ex_db, publish=False)

        return tk_ex_db, lv_ac_db, ac_ex_db
Ejemplo n.º 8
0
    def test_task_execution_crud(self):
        initial = wf_db_models.TaskExecutionDB()
        initial.workflow_execution = uuid.uuid4().hex
        initial.task_name = "t1"
        initial.task_id = "t1"
        initial.task_route = 0
        initial.task_spec = {"tasks": {"t1": "some task"}}
        initial.delay = 180
        initial.status = "requested"
        initial.context = {"var1": "foobar"}

        # Test create
        created = wf_db_access.TaskExecution.add_or_update(initial)
        self.assertEqual(initial.rev, 1)
        doc_id = created.id

        # Test read
        retrieved = wf_db_access.TaskExecution.get_by_id(doc_id)
        self.assertEqual(created.workflow_execution,
                         retrieved.workflow_execution)
        self.assertEqual(created.task_name, retrieved.task_name)
        self.assertEqual(created.task_id, retrieved.task_id)
        self.assertEqual(created.task_route, retrieved.task_route)
        self.assertDictEqual(created.task_spec, retrieved.task_spec)
        self.assertEqual(created.delay, retrieved.delay)
        self.assertFalse(created.itemized)
        self.assertEqual(created.status, retrieved.status)
        self.assertIsNotNone(created.start_timestamp)
        self.assertIsNone(created.end_timestamp)
        self.assertDictEqual(created.context, retrieved.context)

        # Test update
        status = "running"
        retrieved = wf_db_access.TaskExecution.update(retrieved, status=status)
        updated = wf_db_access.TaskExecution.get_by_id(doc_id)
        self.assertNotEqual(created.rev, updated.rev)
        self.assertEqual(retrieved.rev, updated.rev)
        self.assertEqual(updated.workflow_execution,
                         retrieved.workflow_execution)
        self.assertEqual(updated.task_name, retrieved.task_name)
        self.assertEqual(updated.task_id, retrieved.task_id)
        self.assertEqual(updated.task_route, retrieved.task_route)
        self.assertDictEqual(updated.task_spec, retrieved.task_spec)
        self.assertEqual(updated.delay, retrieved.delay)
        self.assertEqual(updated.itemized, retrieved.itemized)
        self.assertEqual(updated.status, retrieved.status)
        self.assertIsNotNone(updated.start_timestamp)
        self.assertIsNone(updated.end_timestamp)
        self.assertDictEqual(updated.context, retrieved.context)

        # Test add or update
        retrieved.result = {"output": "fubar"}
        retrieved.status = "succeeded"
        retrieved.end_timestamp = date_utils.get_datetime_utc_now()
        retrieved = wf_db_access.TaskExecution.add_or_update(retrieved)
        updated = wf_db_access.TaskExecution.get_by_id(doc_id)
        self.assertNotEqual(created.rev, updated.rev)
        self.assertEqual(retrieved.rev, updated.rev)
        self.assertEqual(updated.workflow_execution,
                         retrieved.workflow_execution)
        self.assertEqual(updated.task_name, retrieved.task_name)
        self.assertEqual(updated.task_id, retrieved.task_id)
        self.assertEqual(updated.task_route, retrieved.task_route)
        self.assertDictEqual(updated.task_spec, retrieved.task_spec)
        self.assertEqual(updated.delay, retrieved.delay)
        self.assertEqual(updated.itemized, retrieved.itemized)
        self.assertEqual(updated.status, retrieved.status)
        self.assertIsNotNone(updated.start_timestamp)
        self.assertIsNotNone(updated.end_timestamp)
        self.assertDictEqual(updated.context, retrieved.context)
        self.assertDictEqual(updated.result, retrieved.result)

        # Test delete
        created.delete()

        self.assertRaises(
            db_exc.StackStormDBObjectNotFoundError,
            wf_db_access.TaskExecution.get_by_id,
            doc_id,
        )
Ejemplo n.º 9
0
def request_task_execution(wf_ex_db, st2_ctx, task_req):
    wf_ac_ex_id = wf_ex_db.action_execution
    task_id = task_req['id']
    task_spec = task_req['spec']
    task_ctx = task_req['ctx']
    task_actions = task_req['actions']

    LOG.info('[%s] Processing task execution request for "%s".', wf_ac_ex_id,
             task_id)

    # Use existing task execution when task is with items and still running.
    task_ex_dbs = wf_db_access.TaskExecution.query(
        workflow_execution=str(wf_ex_db.id),
        task_id=task_id,
        order_by=['-start_timestamp'])

    if (len(task_ex_dbs) > 0 and task_ex_dbs[0].itemized
            and task_ex_dbs[0].status == ac_const.LIVEACTION_STATUS_RUNNING):
        task_ex_db = task_ex_dbs[0]
        task_ex_id = str(task_ex_db.id)
        msg = '[%s] Task execution "%s" retrieved for task "%s".'
        LOG.info(msg, wf_ac_ex_id, task_ex_id, task_id)
    else:
        # 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(),
            itemized=task_spec.has_items(),
            context=task_ctx,
            status=states.REQUESTED)

        # Prepare the result format for itemized task execution.
        if task_ex_db.itemized:
            task_ex_db.result = {'items': [None] * task_req['items_count']}

        # 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)
        msg = '[%s] Task execution "%s" created for task "%s".'
        LOG.info(msg, 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:
            LOG.info('[%s] Task "%s" is action less and succeed by default.',
                     wf_ac_ex_id, task_id)

            # 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),
                             states.SUCCEEDED,
                             publish=False)

            # Refresh and return the task execution
            return wf_db_access.TaskExecution.get_by_id(str(task_ex_db.id))

        # Request action execution for each actions in the task request.
        for action in task_actions:
            request_action_execution(wf_ex_db, task_ex_db, st2_ctx, action)
            task_ex_db = wf_db_access.TaskExecution.get_by_id(
                str(task_ex_db.id))
    except Exception as e:
        msg = '[%s] Failed action execution(s) for task "%s". %s'
        LOG.exception(msg, wf_ac_ex_id, task_id, str(e))
        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