Beispiel #1
0
 def test_do_not_retry_on_exceptions(self):
     instance = wf_db_models.WorkflowExecutionDB()
     exc = db_exc.StackStormDBObjectConflictError('foobar', '1234',
                                                  instance)
     self.assertFalse(wf_exc.retry_on_exceptions(exc))
     self.assertFalse(wf_exc.retry_on_exceptions(NotImplementedError()))
     self.assertFalse(wf_exc.retry_on_exceptions(Exception()))
Beispiel #2
0
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
Beispiel #3
0
    def test_workflow_execution_crud(self):
        initial = wf_db_models.WorkflowExecutionDB()
        initial.action_execution = uuid.uuid4().hex
        initial.graph = {"var1": "foobar"}
        initial.status = "requested"

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

        # Test read
        retrieved = wf_db_access.WorkflowExecution.get_by_id(doc_id)
        self.assertEqual(created.action_execution, retrieved.action_execution)
        self.assertDictEqual(created.graph, retrieved.graph)
        self.assertEqual(created.status, retrieved.status)

        # Test update
        graph = {"var1": "fubar"}
        status = "running"
        retrieved = wf_db_access.WorkflowExecution.update(
            retrieved, graph=graph, status=status
        )
        updated = wf_db_access.WorkflowExecution.get_by_id(doc_id)
        self.assertNotEqual(created.rev, updated.rev)
        self.assertEqual(retrieved.rev, updated.rev)
        self.assertEqual(retrieved.action_execution, updated.action_execution)
        self.assertDictEqual(retrieved.graph, updated.graph)
        self.assertEqual(retrieved.status, updated.status)

        # Test add or update
        retrieved.graph = {"var2": "fubar"}
        retrieved = wf_db_access.WorkflowExecution.add_or_update(retrieved)
        updated = wf_db_access.WorkflowExecution.get_by_id(doc_id)
        self.assertNotEqual(created.rev, updated.rev)
        self.assertEqual(retrieved.rev, updated.rev)
        self.assertEqual(retrieved.action_execution, updated.action_execution)
        self.assertDictEqual(retrieved.graph, updated.graph)
        self.assertEqual(retrieved.status, updated.status)

        # Test delete
        created.delete()

        self.assertRaises(
            db_exc.StackStormDBObjectNotFoundError,
            wf_db_access.WorkflowExecution.get_by_id,
            doc_id,
        )
Beispiel #4
0
    def test_workflow_execution_write_conflict(self):
        initial = wf_db_models.WorkflowExecutionDB()
        initial.action_execution = uuid.uuid4().hex
        initial.graph = {"var1": "foobar"}
        initial.status = "requested"

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

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

        # Test update on instance 1, expect success
        graph = {"var1": "fubar"}
        status = "running"
        retrieved1 = wf_db_access.WorkflowExecution.update(
            retrieved1, graph=graph, status=status
        )
        updated = wf_db_access.WorkflowExecution.get_by_id(doc_id)
        self.assertNotEqual(created.rev, updated.rev)
        self.assertEqual(retrieved1.rev, updated.rev)
        self.assertEqual(retrieved1.action_execution, updated.action_execution)
        self.assertDictEqual(retrieved1.graph, updated.graph)
        self.assertEqual(retrieved1.status, updated.status)

        # Test update on instance 2, expect race error
        self.assertRaises(
            db_exc.StackStormDBObjectWriteConflictError,
            wf_db_access.WorkflowExecution.update,
            retrieved2,
            graph={"var2": "fubar"},
        )

        # Test delete
        created.delete()

        self.assertRaises(
            db_exc.StackStormDBObjectNotFoundError,
            wf_db_access.WorkflowExecution.get_by_id,
            doc_id,
        )
Beispiel #5
0
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
 def test_retry_on_transient_db_errors(self):
     instance = wf_db_models.WorkflowExecutionDB()
     exc = db_exc.StackStormDBObjectWriteConflictError(instance)
     self.assertTrue(wf_exc.retry_on_transient_db_errors(exc))
    def mock_workflow_records(self, completed=False, expired=True, log=True):
        status = (ac_const.LIVEACTION_STATUS_SUCCEEDED
                  if completed else ac_const.LIVEACTION_STATUS_RUNNING)

        # Identify start and 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 + 30)
        start_timestamp = expiry_dt if expired else utc_now_dt
        end_timestamp = utc_now_dt if completed else None

        # Assign metadata.
        action_ref = "orquesta_tests.sequential"
        runner = "orquesta"
        user = "******"

        # Create the WorkflowExecutionDB record first since the ID needs to be
        # included in the LiveActionDB and ActionExecutionDB records.
        st2_ctx = {
            "st2": {
                "action_execution_id": "123",
                "action": "foobar",
                "runner": "orquesta",
            }
        }
        wf_ex_db = wf_db_models.WorkflowExecutionDB(
            context=st2_ctx,
            status=status,
            start_timestamp=start_timestamp,
            end_timestamp=end_timestamp,
        )

        wf_ex_db = wf_db_access.WorkflowExecution.insert(wf_ex_db,
                                                         publish=False)

        # Create the LiveActionDB record.
        lv_ac_db = lv_db_models.LiveActionDB(
            workflow_execution=str(wf_ex_db.id),
            action=action_ref,
            action_is_workflow=True,
            context={
                "user": user,
                "workflow_execution": str(wf_ex_db.id)
            },
            status=status,
            start_timestamp=start_timestamp,
            end_timestamp=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(wf_ex_db.id),
            action={
                "runner_type": runner,
                "ref": action_ref
            },
            runner={"name": runner},
            liveaction={"id": str(lv_ac_db.id)},
            context={
                "user": user,
                "workflow_execution": str(wf_ex_db.id)
            },
            status=status,
            start_timestamp=start_timestamp,
            end_timestamp=end_timestamp,
        )

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

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

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

        # Update the WorkflowExecutionDB record with cross reference to the ActionExecutionDB.
        wf_ex_db.action_execution = str(ac_ex_db.id)
        wf_ex_db = wf_db_access.WorkflowExecution.update(wf_ex_db,
                                                         publish=False)

        return wf_ex_db, lv_ac_db, ac_ex_db
Beispiel #8
0
    def mock_workflow_records(self, completed=False, expired=True, log=True):
        status = (ac_const.LIVEACTION_STATUS_SUCCEEDED
                  if completed else ac_const.LIVEACTION_STATUS_RUNNING)

        # Identify start and 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 + 30)
        start_timestamp = expiry_dt if expired else utc_now_dt
        end_timestamp = utc_now_dt if completed else None

        # Assign metadata.
        action_ref = 'orquesta_tests.sequential'
        runner = 'orquesta'
        user = '******'

        # Create the WorkflowExecutionDB record first since the ID needs to be
        # included in the LiveActionDB and ActionExecutionDB records.
        st2_ctx = {
            'st2': {
                'action_execution_id': '123',
                'action': 'foobar',
                'runner': 'orquesta'
            }
        }
        wf_ex_db = wf_db_models.WorkflowExecutionDB(
            context=st2_ctx,
            status=status,
            start_timestamp=start_timestamp,
            end_timestamp=end_timestamp)

        wf_ex_db = wf_db_access.WorkflowExecution.insert(wf_ex_db,
                                                         publish=False)

        # Create the LiveActionDB record.
        lv_ac_db = lv_db_models.LiveActionDB(workflow_execution=str(
            wf_ex_db.id),
                                             action=action_ref,
                                             action_is_workflow=True,
                                             context={
                                                 'user':
                                                 user,
                                                 'workflow_execution':
                                                 str(wf_ex_db.id)
                                             },
                                             status=status,
                                             start_timestamp=start_timestamp,
                                             end_timestamp=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(wf_ex_db.id),
            action={
                'runner_type': runner,
                'ref': action_ref
            },
            runner={'name': runner},
            liveaction={'id': str(lv_ac_db.id)},
            context={
                'user': user,
                'workflow_execution': str(wf_ex_db.id)
            },
            status=status,
            start_timestamp=start_timestamp,
            end_timestamp=end_timestamp)

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

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

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

        # Update the WorkflowExecutionDB record with cross reference to the ActionExecutionDB.
        wf_ex_db.action_execution = str(ac_ex_db.id)
        wf_ex_db = wf_db_access.WorkflowExecution.update(wf_ex_db,
                                                         publish=False)

        return wf_ex_db, lv_ac_db, ac_ex_db