Exemple #1
0
    def test_execute_cancelation(self):
        liveaction_db = self._create_liveaction_db()
        self._process_request(liveaction_db)

        scheduled_liveaction_db = action_utils.get_liveaction_by_id(
            liveaction_db.id)
        scheduled_liveaction_db = self._wait_on_status(
            scheduled_liveaction_db,
            action_constants.LIVEACTION_STATUS_SCHEDULED)

        action_utils.update_liveaction_status(
            status=action_constants.LIVEACTION_STATUS_CANCELED,
            liveaction_id=liveaction_db.id)

        canceled_liveaction_db = action_utils.get_liveaction_by_id(
            liveaction_db.id)
        self.dispatcher._queue_consumer._process_message(
            canceled_liveaction_db)
        dispatched_liveaction_db = action_utils.get_liveaction_by_id(
            liveaction_db.id)

        self.assertEqual(dispatched_liveaction_db.status,
                         action_constants.LIVEACTION_STATUS_CANCELED)

        self.assertDictEqual(dispatched_liveaction_db.result,
                             {'message': 'Action execution canceled by user.'})
Exemple #2
0
    def test_execute_cancelation(self):
        liveaction_db = self._create_liveaction_db()
        self._process_request(liveaction_db)

        scheduled_liveaction_db = action_db.get_liveaction_by_id(liveaction_db.id)
        scheduled_liveaction_db = self._wait_on_status(
            scheduled_liveaction_db,
            action_constants.LIVEACTION_STATUS_SCHEDULED
        )

        action_db.update_liveaction_status(
            status=action_constants.LIVEACTION_STATUS_CANCELED,
            liveaction_id=liveaction_db.id
        )

        canceled_liveaction_db = action_db.get_liveaction_by_id(liveaction_db.id)
        self.dispatcher._queue_consumer._process_message(canceled_liveaction_db)
        dispatched_liveaction_db = action_db.get_liveaction_by_id(liveaction_db.id)

        self.assertEqual(
            dispatched_liveaction_db.status,
            action_constants.LIVEACTION_STATUS_CANCELED
        )

        self.assertDictEqual(
            dispatched_liveaction_db.result,
            {'message': 'Action execution canceled by user.'}
        )
Exemple #3
0
    def test_req_resume(self):
        # Add the runner type to the list of runners that support pause and resume.
        action_constants.WORKFLOW_RUNNER_TYPES.append(ACTION["runner_type"])

        try:
            req, ex = self._submit_request()
            self.assertIsNotNone(ex)
            self.assertEqual(ex.id, req.id)
            self.assertEqual(ex.status, action_constants.LIVEACTION_STATUS_REQUESTED)

            # Update ex status to RUNNING.
            action_service.update_status(
                ex, action_constants.LIVEACTION_STATUS_RUNNING, False
            )
            ex = action_db.get_liveaction_by_id(ex.id)
            self.assertEqual(ex.status, action_constants.LIVEACTION_STATUS_RUNNING)

            # Request pause.
            ex = self._submit_pause(ex)
            self.assertEqual(ex.status, action_constants.LIVEACTION_STATUS_PAUSING)

            # Update ex status to PAUSED.
            action_service.update_status(
                ex, action_constants.LIVEACTION_STATUS_PAUSED, False
            )
            ex = action_db.get_liveaction_by_id(ex.id)
            self.assertEqual(ex.status, action_constants.LIVEACTION_STATUS_PAUSED)

            # Request resume.
            ex = self._submit_resume(ex)
            self.assertEqual(ex.status, action_constants.LIVEACTION_STATUS_RESUMING)
        finally:
            action_constants.WORKFLOW_RUNNER_TYPES.remove(ACTION["runner_type"])
Exemple #4
0
    def query(self, execution_id, query_context, last_query_time=None):
        """
        Queries mistral for workflow results using v2 APIs.
        :param execution_id: st2 execution_id (context to be used for logging/audit)
        :type execution_id: ``str``
        :param query_context: context for the query to be made to mistral. This contains mistral
                              execution id.
        :type query_context: ``object``
        :param last_query_time: Timestamp of last query.
        :type last_query_time: ``float``
        :rtype: (``str``, ``object``)
        """
        # Retrieve liveaction_db to append new result to existing result.
        liveaction_db = action_utils.get_liveaction_by_id(execution_id)

        mistral_exec_id = query_context.get('mistral', {}).get('execution_id', None)
        if not mistral_exec_id:
            raise Exception('[%s] Missing mistral workflow execution ID in query context. %s'
                            % (execution_id, query_context))

        LOG.info('[%s] Querying mistral execution %s...', execution_id, mistral_exec_id)

        try:
            wf_result = self._get_workflow_result(execution_id, mistral_exec_id)

            stream = getattr(liveaction_db, 'result', {})

            wf_tasks_result = self._get_workflow_tasks(
                execution_id,
                mistral_exec_id,
                recorded_tasks=stream.get('tasks', [])
            )

            result = self._format_query_result(
                liveaction_db.result,
                wf_result,
                wf_tasks_result
            )
        except exceptions.ReferenceNotFoundError as exc:
            LOG.exception('[%s] Unable to find reference.', execution_id)
            return (action_constants.LIVEACTION_STATUS_FAILED, str(exc))
        except Exception:
            LOG.exception('[%s] Unable to fetch mistral workflow result and tasks. %s',
                          execution_id, query_context)
            raise

        # Retrieve liveaction_db again in case state has changed
        # while the querier get results from mistral API above.
        liveaction_db = action_utils.get_liveaction_by_id(execution_id)

        status = self._determine_execution_status(
            liveaction_db,
            result['extra']['state'],
            result['tasks']
        )

        LOG.info('[%s] Determined execution status: %s', execution_id, status)
        LOG.debug('[%s] Combined execution result: %s', execution_id, result)

        return (status, result)
Exemple #5
0
    def query(self, execution_id, query_context, last_query_time=None):
        """
        Queries mistral for workflow results using v2 APIs.
        :param execution_id: st2 execution_id (context to be used for logging/audit)
        :type execution_id: ``str``
        :param query_context: context for the query to be made to mistral. This contains mistral
                              execution id.
        :type query_context: ``object``
        :param last_query_time: Timestamp of last query.
        :type last_query_time: ``float``
        :rtype: (``str``, ``object``)
        """
        # Retrieve liveaction_db to append new result to existing result.
        liveaction_db = action_utils.get_liveaction_by_id(execution_id)

        mistral_exec_id = query_context.get('mistral', {}).get('execution_id', None)
        if not mistral_exec_id:
            raise Exception('[%s] Missing mistral workflow execution ID in query context. %s',
                            execution_id, query_context)

        LOG.info('[%s] Querying mistral execution %s...', execution_id, mistral_exec_id)

        try:
            wf_result = self._get_workflow_result(execution_id, mistral_exec_id)

            stream = getattr(liveaction_db, 'result', {})

            wf_tasks_result = self._get_workflow_tasks(
                execution_id,
                mistral_exec_id,
                recorded_tasks=stream.get('tasks', [])
            )

            result = self._format_query_result(
                liveaction_db.result,
                wf_result,
                wf_tasks_result
            )
        except exceptions.ReferenceNotFoundError as exc:
            LOG.exception('[%s] Unable to find reference.', execution_id)
            return (action_constants.LIVEACTION_STATUS_FAILED, exc.message)
        except Exception:
            LOG.exception('[%s] Unable to fetch mistral workflow result and tasks. %s',
                          execution_id, query_context)
            raise

        # Retrieve liveaction_db again in case state has changed
        # while the querier get results from mistral API above.
        liveaction_db = action_utils.get_liveaction_by_id(execution_id)

        status = self._determine_execution_status(
            liveaction_db,
            result['extra']['state'],
            result['tasks']
        )

        LOG.info('[%s] Determined execution status: %s', execution_id, status)
        LOG.debug('[%s] Combined execution result: %s', execution_id, result)

        return (status, result)
Exemple #6
0
    def test_execute_no_result(self):
        liveaction_db = self._create_liveaction_db()
        self._process_request(liveaction_db)

        scheduled_liveaction_db = action_db.get_liveaction_by_id(liveaction_db.id)
        scheduled_liveaction_db = self._wait_on_status(
            scheduled_liveaction_db,
            action_constants.LIVEACTION_STATUS_SCHEDULED
        )

        self.dispatcher._queue_consumer._process_message(scheduled_liveaction_db)
        dispatched_liveaction_db = action_db.get_liveaction_by_id(liveaction_db.id)
        self.assertEqual(dispatched_liveaction_db.status, action_constants.LIVEACTION_STATUS_FAILED)
Exemple #7
0
    def test_execute_no_result(self):
        liveaction_db = self._create_liveaction_db()
        self._process_request(liveaction_db)

        scheduled_liveaction_db = action_db.get_liveaction_by_id(liveaction_db.id)
        scheduled_liveaction_db = self._wait_on_status(
            scheduled_liveaction_db,
            action_constants.LIVEACTION_STATUS_SCHEDULED
        )

        self.dispatcher._queue_consumer._process_message(scheduled_liveaction_db)
        dispatched_liveaction_db = action_db.get_liveaction_by_id(liveaction_db.id)
        self.assertEqual(dispatched_liveaction_db.status, action_constants.LIVEACTION_STATUS_FAILED)
Exemple #8
0
    def test_execute_no_result(self):
        live_action_db = self._get_execution_db_model(
            status=action_constants.LIVEACTION_STATUS_REQUESTED)

        self.scheduler._queue_consumer._process_message(live_action_db)
        scheduled_live_action_db = action_db.get_liveaction_by_id(live_action_db.id)
        self.assertEqual(scheduled_live_action_db.status,
                         action_constants.LIVEACTION_STATUS_SCHEDULED)

        self.dispatcher._queue_consumer._process_message(scheduled_live_action_db)
        dispatched_live_action_db = action_db.get_liveaction_by_id(live_action_db.id)
        self.assertEqual(dispatched_live_action_db.status,
                         action_constants.LIVEACTION_STATUS_FAILED)
Exemple #9
0
    def test_execute(self):
        live_action_db = self._get_execution_db_model(
            status=action_constants.LIVEACTION_STATUS_REQUESTED)

        self.scheduler._queue_consumer._process_message(live_action_db)
        scheduled_live_action_db = action_db.get_liveaction_by_id(live_action_db.id)
        self.assertDictEqual(scheduled_live_action_db.runner_info, {})
        self.assertEqual(scheduled_live_action_db.status,
                         action_constants.LIVEACTION_STATUS_SCHEDULED)

        self.dispatcher._queue_consumer._process_message(scheduled_live_action_db)
        dispatched_live_action_db = action_db.get_liveaction_by_id(live_action_db.id)
        self.assertGreater(len(dispatched_live_action_db.runner_info.keys()), 0)
        self.assertEqual(dispatched_live_action_db.status,
                         action_constants.LIVEACTION_STATUS_RUNNING)
Exemple #10
0
    def run(self, action_parameters):

        liveaction_db = action_utils.get_liveaction_by_id(self.liveaction_id)
        exc = ActionExecution.get(liveaction__id=str(liveaction_db.id))

        # Assemble and dispatch trigger
        trigger_ref = ResourceReference.to_string_reference(
            pack=INQUIRY_TRIGGER['pack'],
            name=INQUIRY_TRIGGER['name']
        )
        trigger_payload = {
            "id": str(exc.id),
            "route": self.route
        }
        self.trigger_dispatcher.dispatch(trigger_ref, trigger_payload)

        # We only want to request a pause if this has a parent
        if liveaction_db.context.get("parent"):

            # Get the root liveaction and request that it pauses
            root_liveaction = action_service.get_root_liveaction(liveaction_db)
            action_service.request_pause(
                root_liveaction,
                self.context.get('user', None)
            )

        result = {
            "schema": self.schema,
            "roles": self.roles_param,
            "users": self.users_param,
            "route": self.route,
            "ttl": self.ttl
        }
        return (LIVEACTION_STATUS_PENDING, result, None)
Exemple #11
0
    def run(self, action_parameters):
        liveaction_db = action_utils.get_liveaction_by_id(self.liveaction_id)
        exc = ex_db_access.ActionExecution.get(liveaction__id=str(liveaction_db.id))

        # Assemble and dispatch trigger
        trigger_ref = sys_db_models.ResourceReference.to_string_reference(
            pack=trigger_constants.INQUIRY_TRIGGER['pack'],
            name=trigger_constants.INQUIRY_TRIGGER['name']
        )

        trigger_payload = {
            "id": str(exc.id),
            "route": self.route
        }

        self.trigger_dispatcher.dispatch(trigger_ref, trigger_payload)

        result = {
            "schema": self.schema,
            "roles": self.roles_param,
            "users": self.users_param,
            "route": self.route,
            "ttl": self.ttl
        }

        return (action_constants.LIVEACTION_STATUS_PENDING, result, None)
Exemple #12
0
    def execute_action(self, liveaction):
        try:
            liveaction_db = get_liveaction_by_id(liveaction.id)
        except StackStormDBObjectNotFoundError:
            LOG.exception('Failed to find liveaction %s in the database.',
                          liveaction.id)
            raise

        # Update liveaction status to "running"
        liveaction_db = update_liveaction_status(status=LIVEACTION_STATUS_RUNNING,
                                                 liveaction_id=liveaction_db.id)
        # Launch action
        LOG.audit('Launching action execution.',
                  extra={'liveaction': liveaction_db.to_serializable_dict()})

        try:
            result = self.container.dispatch(liveaction_db)
            LOG.debug('Runner dispatch produced result: %s', result)
        except Exception:
            liveaction_db = update_liveaction_status(status=LIVEACTION_STATUS_FAILED,
                                                     liveaction_id=liveaction_db.id)
            raise

        if not result:
            raise ActionRunnerException('Failed to execute action.')

        return result
Exemple #13
0
    def _handle_execution(self, execution_queue_item_db):
        liveaction_id = str(execution_queue_item_db.liveaction_id)
        queue_item_id = str(execution_queue_item_db.id)

        extra = {
            'liveaction_id': liveaction_id,
            'queue_item_id': queue_item_id
        }

        LOG.info('Scheduling liveaction: %s (queue_item_id=%s)',
                 liveaction_id,
                 queue_item_id,
                 extra=extra)

        try:
            liveaction_db = action_utils.get_liveaction_by_id(liveaction_id)
        except StackStormDBObjectNotFoundError:
            LOG.exception(
                'Failed to find liveaction %s in the database (queue_item_id=%s).',
                liveaction_id,
                queue_item_id,
                extra=extra)
            ActionExecutionSchedulingQueue.delete(execution_queue_item_db)
            raise

        liveaction_db = self._apply_pre_run(liveaction_db,
                                            execution_queue_item_db)

        if not liveaction_db:
            return

        if self._is_execution_queue_item_runnable(liveaction_db,
                                                  execution_queue_item_db):
            self._update_to_scheduled(liveaction_db, execution_queue_item_db)
    def test_execute_no_result(self):
        live_action_db = self._get_execution_db_model(
            status=action_constants.LIVEACTION_STATUS_REQUESTED)

        self.scheduler._queue_consumer._process_message(live_action_db)
        scheduled_live_action_db = action_db.get_liveaction_by_id(
            live_action_db.id)
        self.assertEqual(scheduled_live_action_db.status,
                         action_constants.LIVEACTION_STATUS_SCHEDULED)

        self.dispatcher._queue_consumer._process_message(
            scheduled_live_action_db)
        dispatched_live_action_db = action_db.get_liveaction_by_id(
            live_action_db.id)
        self.assertEqual(dispatched_live_action_db.status,
                         action_constants.LIVEACTION_STATUS_FAILED)
Exemple #15
0
 def _submit_request(self, action_ref=ACTION_REF):
     context = {'user': USERNAME}
     parameters = {'hosts': '127.0.0.1', 'cmd': 'uname -a'}
     request = LiveActionDB(action=action_ref, context=context, parameters=parameters)
     request, _ = action_service.request(request)
     execution = action_db.get_liveaction_by_id(str(request.id))
     return request, execution
Exemple #16
0
 def _submit_request(self):
     context = {'user': USERNAME}
     parameters = {'hosts': 'localhost', 'cmd': 'uname -a'}
     request = LiveActionDB(action=ACTION_REF, context=context, parameters=parameters)
     request, _ = action_service.request(request)
     execution = action_db.get_liveaction_by_id(str(request.id))
     return request, execution
    def _run_action(self, action_node, parent_execution_id, params, wait_for_completion=True):
        liveaction = LiveActionDB(action=action_node.ref)
        liveaction.parameters = action_param_utils.cast_params(action_ref=action_node.ref,
                                                               params=params)

        # Setup notify for task in chain.
        notify = self._get_notify(action_node)
        if notify:
            liveaction.notify = notify
            LOG.debug('%s: Task notify set to: %s', action_node.name, liveaction.notify)

        liveaction.context = {
            'parent': str(parent_execution_id),
            'chain': vars(action_node)
        }

        liveaction, _ = action_service.request(liveaction)

        while (wait_for_completion and
               liveaction.status != LIVEACTION_STATUS_SUCCEEDED and
               liveaction.status != LIVEACTION_STATUS_FAILED):
            eventlet.sleep(1)
            liveaction = action_db_util.get_liveaction_by_id(liveaction.id)

        return liveaction
Exemple #18
0
    def _update_live_action_db(self, liveaction_id, status, result, context):
        """
        Update LiveActionDB object for the provided liveaction id.
        """
        liveaction_db = get_liveaction_by_id(liveaction_id)

        state_changed = (
            liveaction_db.status != status and
            liveaction_db.status not in action_constants.LIVEACTION_COMPLETED_STATES
        )

        if status in action_constants.LIVEACTION_COMPLETED_STATES:
            end_timestamp = date_utils.get_datetime_utc_now()
        else:
            end_timestamp = None

        liveaction_db = update_liveaction_status(
            status=status if state_changed else liveaction_db.status,
            result=result,
            context=context,
            end_timestamp=end_timestamp,
            liveaction_db=liveaction_db
        )

        return (liveaction_db, state_changed)
Exemple #19
0
def abandon_execution_if_incomplete(liveaction_id, publish=True):
    """
    Marks execution as abandoned if it is still incomplete. Abandoning an
    execution implies that its end state is unknown and cannot anylonger
    be determined. This method should only be called if the owning process
    is certain it can no longer determine status of an execution.
    """
    liveaction_db = action_utils.get_liveaction_by_id(liveaction_id)

    # No need to abandon and already complete action
    if liveaction_db.status in action_constants.LIVEACTION_COMPLETED_STATES:
        raise ValueError('LiveAction %s already in a completed state %s.' %
                         (liveaction_id, liveaction_db.status))

    # Update status to reflect execution being abandoned.
    liveaction_db = action_utils.update_liveaction_status(
        status=action_constants.LIVEACTION_STATUS_ABANDONED,
        liveaction_db=liveaction_db,
        result={})

    execution_db = update_execution(liveaction_db, publish=publish)

    LOG.info('Marked execution %s as %s.', execution_db.id,
             action_constants.LIVEACTION_STATUS_ABANDONED)

    # Invoke post run on the action to execute post run operations such as callback.
    runners_utils.invoke_post_run(liveaction_db)

    return execution_db
Exemple #20
0
    def _update_live_action_db(self, liveaction_id, status, result, context):
        """
        Update LiveActionDB object for the provided liveaction id.
        """
        liveaction_db = get_liveaction_by_id(liveaction_id)

        state_changed = (
            liveaction_db.status != status and
            liveaction_db.status not in action_constants.LIVEACTION_COMPLETED_STATES
        )

        if status in action_constants.LIVEACTION_COMPLETED_STATES:
            end_timestamp = date_utils.get_datetime_utc_now()
        else:
            end_timestamp = None

        liveaction_db = update_liveaction_status(
            status=status if state_changed else liveaction_db.status,
            result=result,
            context=context,
            end_timestamp=end_timestamp,
            liveaction_db=liveaction_db
        )

        return (liveaction_db, state_changed)
Exemple #21
0
    def _run_action(self,
                    action_node,
                    parent_execution_id,
                    params,
                    wait_for_completion=True):
        liveaction = LiveActionDB(action=action_node.ref)
        liveaction.parameters = action_param_utils.cast_params(
            action_ref=action_node.ref, params=params)

        # Setup notify for task in chain.
        notify = self._get_notify(action_node)
        if notify:
            liveaction.notify = notify
            LOG.debug('%s: Task notify set to: %s', action_node.name,
                      liveaction.notify)

        liveaction.context = {
            'parent': str(parent_execution_id),
            'chain': vars(action_node)
        }

        liveaction, _ = action_service.request(liveaction)

        while (wait_for_completion
               and liveaction.status != LIVEACTION_STATUS_SUCCEEDED
               and liveaction.status != LIVEACTION_STATUS_FAILED):
            eventlet.sleep(1)
            liveaction = action_db_util.get_liveaction_by_id(liveaction.id)

        return liveaction
Exemple #22
0
    def run(self, action_parameters):
        liveaction_db = action_utils.get_liveaction_by_id(self.liveaction_id)
        exc = ex_db_access.ActionExecution.get(liveaction__id=str(liveaction_db.id))

        # Assemble and dispatch trigger
        trigger_ref = sys_db_models.ResourceReference.to_string_reference(
            pack=trigger_constants.INQUIRY_TRIGGER['pack'],
            name=trigger_constants.INQUIRY_TRIGGER['name']
        )

        trigger_payload = {
            "id": str(exc.id),
            "route": self.route
        }

        self.trigger_dispatcher.dispatch(trigger_ref, trigger_payload)

        result = {
            "schema": self.schema,
            "roles": self.roles_param,
            "users": self.users_param,
            "route": self.route,
            "ttl": self.ttl
        }

        return (action_constants.LIVEACTION_STATUS_PENDING, result, None)
Exemple #23
0
    def run(self, action_parameters):

        liveaction_db = action_utils.get_liveaction_by_id(self.liveaction_id)
        exc = ActionExecution.get(liveaction__id=str(liveaction_db.id))

        # Assemble and dispatch trigger
        trigger_ref = ResourceReference.to_string_reference(
            pack=INQUIRY_TRIGGER['pack'], name=INQUIRY_TRIGGER['name'])
        trigger_payload = {"id": str(exc.id), "route": self.route}
        self.trigger_dispatcher.dispatch(trigger_ref, trigger_payload)

        # We only want to request a pause if this has a parent
        if liveaction_db.context.get("parent"):

            # Get the root liveaction and request that it pauses
            root_liveaction = action_service.get_root_liveaction(liveaction_db)
            action_service.request_pause(root_liveaction,
                                         self.context.get('user', None))

        result = {
            "schema": self.schema,
            "roles": self.roles_param,
            "users": self.users_param,
            "route": self.route,
            "ttl": self.ttl
        }
        return (LIVEACTION_STATUS_PENDING, result, None)
Exemple #24
0
 def test_succeeded_execution_handling(self):
     testworker = worker.Worker(None)
     live_action_db = self._get_execution_db_model()
     testworker.execute_action(live_action_db)
     updated_live_action_db = get_liveaction_by_id(live_action_db.id)
     self.assertEqual(updated_live_action_db.status,
                      action_constants.LIVEACTION_STATUS_RUNNING)
Exemple #25
0
    def test_req_resume_not_paused(self):
        # Add the runner type to the list of runners that support pause and resume.
        action_constants.WORKFLOW_RUNNER_TYPES.append(ACTION['runner_type'])

        try:
            req, ex = self._submit_request()
            self.assertIsNotNone(ex)
            self.assertEqual(ex.id, req.id)
            self.assertEqual(ex.status,
                             action_constants.LIVEACTION_STATUS_REQUESTED)

            # Update ex status to RUNNING.
            action_service.update_status(
                ex, action_constants.LIVEACTION_STATUS_RUNNING, False)
            ex = action_db.get_liveaction_by_id(ex.id)
            self.assertEqual(ex.status,
                             action_constants.LIVEACTION_STATUS_RUNNING)

            # Request pause.
            ex = self._submit_pause(ex)
            self.assertEqual(ex.status,
                             action_constants.LIVEACTION_STATUS_PAUSING)

            # Request resume.
            self.assertRaises(runner_exc.UnexpectedActionExecutionStatusError,
                              self._submit_resume, ex)
        finally:
            action_constants.WORKFLOW_RUNNER_TYPES.remove(
                ACTION['runner_type'])
Exemple #26
0
 def _submit_request(self, action_ref=ACTION_REF):
     context = {"user": USERNAME}
     parameters = {"hosts": "127.0.0.1", "cmd": "uname -a"}
     req = LiveActionDB(action=action_ref, context=context, parameters=parameters)
     req, _ = action_service.request(req)
     ex = action_db.get_liveaction_by_id(str(req.id))
     return req, ex
Exemple #27
0
    def test_req_resume_already_running(self):
        # Add the runner type to the list of runners that support pause and resume.
        action_constants.WORKFLOW_RUNNER_TYPES.append(ACTION['runner_type'])

        try:
            req, ex = self._submit_request()
            self.assertIsNotNone(ex)
            self.assertEqual(ex.id, req.id)
            self.assertEqual(ex.status,
                             action_constants.LIVEACTION_STATUS_REQUESTED)

            # Update ex status to RUNNING.
            action_service.update_status(
                ex, action_constants.LIVEACTION_STATUS_RUNNING, False)
            ex = action_db.get_liveaction_by_id(ex.id)
            self.assertEqual(ex.status,
                             action_constants.LIVEACTION_STATUS_RUNNING)

            # Request resume.
            with mock.patch.object(action_service,
                                   'update_status',
                                   return_value=None) as mocked:
                ex = self._submit_resume(ex)
                self.assertEqual(ex.status,
                                 action_constants.LIVEACTION_STATUS_RUNNING)
                mocked.assert_not_called()
        finally:
            action_constants.WORKFLOW_RUNNER_TYPES.remove(
                ACTION['runner_type'])
Exemple #28
0
    def _run_action(self,
                    action_node,
                    parent_execution_id,
                    params,
                    wait_for_completion=True):
        liveaction = LiveActionDB(action=action_node.ref)
        liveaction.parameters = action_param_utils.cast_params(
            action_ref=action_node.ref, params=params)
        if action_node.notify:
            liveaction.notify = NotificationsHelper.to_model(
                action_node.notify)

        liveaction.context = {
            'parent': str(parent_execution_id),
            'chain': vars(action_node)
        }

        liveaction, _ = action_service.schedule(liveaction)

        while (wait_for_completion
               and liveaction.status != LIVEACTION_STATUS_SUCCEEDED
               and liveaction.status != LIVEACTION_STATUS_FAILED):
            eventlet.sleep(1)
            liveaction = action_db_util.get_liveaction_by_id(liveaction.id)

        return liveaction
Exemple #29
0
def abandon_execution_if_incomplete(liveaction_id, publish=True):
    """
    Marks execution as abandoned if it is still incomplete. Abandoning an
    execution implies that its end state is unknown and cannot anylonger
    be determined. This method should only be called if the owning process
    is certain it can no longer determine status of an execution.
    """
    liveaction_db = action_utils.get_liveaction_by_id(liveaction_id)

    # No need to abandon and already complete action
    if liveaction_db.status in action_constants.LIVEACTION_COMPLETED_STATES:
        raise ValueError('LiveAction %s already in a completed state %s.' %
                         (liveaction_id, liveaction_db.status))

    # Update status to reflect execution being abandoned.
    liveaction_db = action_utils.update_liveaction_status(
        status=action_constants.LIVEACTION_STATUS_ABANDONED,
        liveaction_db=liveaction_db,
        result={})

    execution_db = update_execution(liveaction_db, publish=publish)

    LOG.info('Marked execution %s as %s.', execution_db.id,
             action_constants.LIVEACTION_STATUS_ABANDONED)

    # Invoke post run on the action to execute post run operations such as callback.
    runners_utils.invoke_post_run(liveaction_db)

    return execution_db
Exemple #30
0
 def test_basic_execution_fail(self):
     testworker = worker.Worker(None)
     live_action_db = self._get_execution_db_model(
         status=action_constants.LIVEACTION_STATUS_FAILED)
     testworker.execute_action(live_action_db)
     updated_live_action_db = get_liveaction_by_id(live_action_db.id)
     self.assertEqual(updated_live_action_db.status,
                      action_constants.LIVEACTION_STATUS_FAILED)
Exemple #31
0
 def test_runner_info(self):
     testworker = worker.Worker(None)
     live_action_db = self._get_execution_db_model()
     testworker.execute_action(live_action_db)
     updated_live_action_db = get_liveaction_by_id(live_action_db.id)
     self.assertEqual(updated_live_action_db.status,
                      action_constants.LIVEACTION_STATUS_RUNNING)
     self.assertTrue(updated_live_action_db.runner_info, 'runner_info should have value.')
Exemple #32
0
def update_execution_records(wf_ex_db,
                             conductor,
                             update_lv_ac_on_states=None,
                             pub_wf_ex=False,
                             pub_lv_ac=True,
                             pub_ac_ex=True):

    wf_ac_ex_id = wf_ex_db.action_execution
    wf_old_status = wf_ex_db.status

    # Update timestamp and output if workflow is completed.
    if conductor.get_workflow_state() in states.COMPLETED_STATES:
        wf_ex_db.end_timestamp = date_utils.get_datetime_utc_now()
        wf_ex_db.output = conductor.get_workflow_output()

    # Update workflow status and task flow and write changes to database.
    wf_ex_db.status = conductor.get_workflow_state()
    wf_ex_db.errors = copy.deepcopy(conductor.errors)
    wf_ex_db.flow = conductor.flow.serialize()
    wf_ex_db = wf_db_access.WorkflowExecution.update(wf_ex_db,
                                                     publish=pub_wf_ex)

    # Add log entry if status changed.
    if wf_old_status != wf_ex_db.status:
        LOG.info('[%s] Updated workflow execution from state "%s" to "%s".',
                 wf_ac_ex_id, wf_old_status, wf_ex_db.status)

    # Return if workflow execution status is not specified in update_lv_ac_on_states.
    if isinstance(update_lv_ac_on_states,
                  list) and wf_ex_db.status not in update_lv_ac_on_states:
        return

    # Update the corresponding liveaction and action execution for the workflow.
    wf_ac_ex_db = ex_db_access.ActionExecution.get_by_id(
        wf_ex_db.action_execution)
    wf_lv_ac_db = ac_db_util.get_liveaction_by_id(wf_ac_ex_db.liveaction['id'])

    # Gather result for liveaction and action execution.
    result = {'output': wf_ex_db.output or None}

    if wf_ex_db.status in states.ABENDED_STATES:
        result['errors'] = wf_ex_db.errors

        for wf_ex_error in wf_ex_db.errors:
            LOG.error('[%s] Workflow execution completed with errors.',
                      wf_ac_ex_id,
                      extra=wf_ex_error)

    # Sync update with corresponding liveaction and action execution.
    wf_lv_ac_db = ac_db_util.update_liveaction_status(
        status=wf_ex_db.status,
        result=result,
        end_timestamp=wf_ex_db.end_timestamp,
        liveaction_db=wf_lv_ac_db,
        publish=pub_lv_ac)

    ex_svc.update_execution(wf_lv_ac_db, publish=pub_ac_ex)
Exemple #33
0
    def test_execute(self):
        liveaction_db = self._create_liveaction_db()
        self._process_request(liveaction_db)

        scheduled_liveaction_db = action_db.get_liveaction_by_id(liveaction_db.id)
        scheduled_liveaction_db = self._wait_on_status(
            scheduled_liveaction_db,
            action_constants.LIVEACTION_STATUS_SCHEDULED
        )
        self.assertDictEqual(scheduled_liveaction_db.runner_info, {})

        self.dispatcher._queue_consumer._process_message(scheduled_liveaction_db)
        dispatched_liveaction_db = action_db.get_liveaction_by_id(liveaction_db.id)
        self.assertGreater(len(list(dispatched_liveaction_db.runner_info.keys())), 0)
        self.assertEqual(
            dispatched_liveaction_db.status,
            action_constants.LIVEACTION_STATUS_RUNNING
        )
Exemple #34
0
    def test_execute(self):
        liveaction_db = self._create_liveaction_db()
        self._process_request(liveaction_db)

        scheduled_liveaction_db = action_db.get_liveaction_by_id(liveaction_db.id)
        scheduled_liveaction_db = self._wait_on_status(
            scheduled_liveaction_db,
            action_constants.LIVEACTION_STATUS_SCHEDULED
        )
        self.assertDictEqual(scheduled_liveaction_db.runner_info, {})

        self.dispatcher._queue_consumer._process_message(scheduled_liveaction_db)
        dispatched_liveaction_db = action_db.get_liveaction_by_id(liveaction_db.id)
        self.assertGreater(len(list(dispatched_liveaction_db.runner_info.keys())), 0)
        self.assertEqual(
            dispatched_liveaction_db.status,
            action_constants.LIVEACTION_STATUS_RUNNING
        )
Exemple #35
0
    def _handle_execution(self, execution_queue_item_db):
        liveaction_id = str(execution_queue_item_db.liveaction_id)
        queue_item_id = str(execution_queue_item_db.id)

        extra = {
            'liveaction_id': liveaction_id,
            'queue_item_id': queue_item_id
        }

        LOG.info('Scheduling liveaction: %s (queue_item_id=%s)',
                 liveaction_id,
                 queue_item_id,
                 extra=extra)

        try:
            liveaction_db = action_utils.get_liveaction_by_id(liveaction_id)
        except StackStormDBObjectNotFoundError:
            LOG.exception(
                'Failed to find liveaction %s in the database (queue_item_id=%s).',
                liveaction_id,
                queue_item_id,
                extra=extra)
            ActionExecutionSchedulingQueue.delete(execution_queue_item_db)
            raise

        # Identify if the action has policies that require locking.
        action_has_policies_require_lock = policy_service.has_policies(
            liveaction_db,
            policy_types=policy_constants.POLICY_TYPES_REQUIRING_LOCK)

        # Acquire a distributed lock if the referenced action has specific policies attached.
        if action_has_policies_require_lock:
            # Warn users that the coordination service is not configured.
            if not coordination_service.configured():
                LOG.warn('Coordination backend is not configured. '
                         'Policy enforcement is best effort.')

            # Acquire a distributed lock before querying the database to make sure that only one
            # scheduler is scheduling execution for this action. Even if the coordination service
            # is not configured, the fake driver using zake or the file driver can still acquire
            # a lock for the local process or server respectively.
            lock_uid = liveaction_db.action
            LOG.debug('%s is attempting to acquire lock "%s".',
                      self.__class__.__name__, lock_uid)
            lock = self._coordinator.get_lock(lock_uid)

            try:
                if lock.acquire(blocking=False):
                    self._regulate_and_schedule(liveaction_db,
                                                execution_queue_item_db)
                else:
                    self._delay(liveaction_db, execution_queue_item_db)
            finally:
                lock.release()
        else:
            # Otherwise if there is no policy, then schedule away.
            self._schedule(liveaction_db, execution_queue_item_db)
    def test_execute(self):
        live_action_db = self._get_execution_db_model(
            status=action_constants.LIVEACTION_STATUS_REQUESTED)

        self.scheduler._queue_consumer._process_message(live_action_db)
        scheduled_live_action_db = action_db.get_liveaction_by_id(
            live_action_db.id)
        self.assertDictEqual(scheduled_live_action_db.runner_info, {})
        self.assertEqual(scheduled_live_action_db.status,
                         action_constants.LIVEACTION_STATUS_SCHEDULED)

        self.dispatcher._queue_consumer._process_message(
            scheduled_live_action_db)
        dispatched_live_action_db = action_db.get_liveaction_by_id(
            live_action_db.id)
        self.assertGreater(len(dispatched_live_action_db.runner_info.keys()),
                           0)
        self.assertEqual(dispatched_live_action_db.status,
                         action_constants.LIVEACTION_STATUS_RUNNING)
Exemple #37
0
    def process(self, liveaction):
        """Dispatches the LiveAction to appropriate action runner.

        LiveAction in statuses other than "scheduled" are ignored. If
        LiveAction is already canceled and result is empty, the LiveAction
        is updated with a generic exception message.

        :param liveaction: Scheduled action execution request.
        :type liveaction: ``st2common.models.db.liveaction.LiveActionDB``

        :rtype: ``dict``
        """

        if liveaction.status == action_constants.LIVEACTION_STATUS_CANCELED:
            LOG.info('%s is not executing %s (id=%s) with "%s" status.',
                     self.__class__.__name__, type(liveaction), liveaction.id, liveaction.status)
            if not liveaction.result:
                updated_liveaction = action_utils.update_liveaction_status(
                    status=liveaction.status,
                    result={'message': 'Action execution canceled by user.'},
                    liveaction_id=liveaction.id)
                executions.update_execution(updated_liveaction)
            return

        if liveaction.status != action_constants.LIVEACTION_STATUS_SCHEDULED:
            LOG.info('%s is not executing %s (id=%s) with "%s" status.',
                     self.__class__.__name__, type(liveaction), liveaction.id, liveaction.status)
            return

        try:
            liveaction_db = action_utils.get_liveaction_by_id(liveaction.id)
        except StackStormDBObjectNotFoundError:
            LOG.exception('Failed to find liveaction %s in the database.', liveaction.id)
            raise

        # stamp liveaction with process_info
        runner_info = system_info.get_process_info()

        # Update liveaction status to "running"
        liveaction_db = action_utils.update_liveaction_status(
            status=action_constants.LIVEACTION_STATUS_RUNNING,
            runner_info=runner_info,
            liveaction_id=liveaction_db.id)

        action_execution_db = executions.update_execution(liveaction_db)

        # Launch action
        extra = {'action_execution_db': action_execution_db, 'liveaction_db': liveaction_db}
        LOG.audit('Launching action execution.', extra=extra)

        # the extra field will not be shown in non-audit logs so temporarily log at info.
        LOG.info('Dispatched {~}action_execution: %s / {~}live_action: %s with "%s" status.',
                 action_execution_db.id, liveaction_db.id, liveaction.status)

        return self._run_action(liveaction_db)
Exemple #38
0
    def process(self, liveaction):
        """Dispatches the LiveAction to appropriate action runner.

        LiveAction in statuses other than "scheduled" and "canceling" are ignored. If
        LiveAction is already canceled and result is empty, the LiveAction
        is updated with a generic exception message.

        :param liveaction: Action execution request.
        :type liveaction: ``st2common.models.db.liveaction.LiveActionDB``

        :rtype: ``dict``
        """

        if liveaction.status == action_constants.LIVEACTION_STATUS_CANCELED:
            LOG.info(
                '%s is not executing %s (id=%s) with "%s" status.',
                self.__class__.__name__,
                type(liveaction),
                liveaction.id,
                liveaction.status,
            )
            if not liveaction.result:
                updated_liveaction = action_utils.update_liveaction_status(
                    status=liveaction.status,
                    result={"message": "Action execution canceled by user."},
                    liveaction_id=liveaction.id,
                )
                executions.update_execution(updated_liveaction)
            return

        if liveaction.status not in [
            action_constants.LIVEACTION_STATUS_SCHEDULED,
            action_constants.LIVEACTION_STATUS_CANCELING,
        ]:
            LOG.info(
                '%s is not dispatching %s (id=%s) with "%s" status.',
                self.__class__.__name__,
                type(liveaction),
                liveaction.id,
                liveaction.status,
            )
            return

        try:
            liveaction_db = action_utils.get_liveaction_by_id(liveaction.id)
        except StackStormDBObjectNotFoundError:
            LOG.exception("Failed to find liveaction %s in the database.", liveaction.id)
            raise

        return (
            self._run_action(liveaction_db)
            if liveaction.status == action_constants.LIVEACTION_STATUS_SCHEDULED
            else self._cancel_action(liveaction_db)
        )
Exemple #39
0
 def test_failed_execution_handling(self):
     testworker = worker.Worker(None)
     live_action_db = self._get_execution_db_model()
     try:
         testworker.execute_action(live_action_db)
         self.assertTrue(False, 'Exception expected.')
     except Exception:
         self.assertTrue(True)
     updated_live_action_db = get_liveaction_by_id(live_action_db.id)
     self.assertEqual(updated_live_action_db.status,
                      action_constants.LIVEACTION_STATUS_FAILED)
Exemple #40
0
    def process(self, request):
        """Schedules the LiveAction and publishes the request
        to the appropriate action runner(s).

        LiveAction in statuses other than "requested" are ignored.

        :param request: Action execution request.
        :type request: ``st2common.models.db.liveaction.LiveActionDB``
        """

        if request.status != action_constants.LIVEACTION_STATUS_REQUESTED:
            LOG.info(
                '%s is ignoring %s (id=%s) with "%s" status.',
                self.__class__.__name__,
                type(request),
                request.id,
                request.status,
            )
            return

        try:
            liveaction_db = action_utils.get_liveaction_by_id(request.id)
        except StackStormDBObjectNotFoundError:
            LOG.exception("Failed to find liveaction %s in the database.", request.id)
            raise

        # Apply policies defined for the action.
        liveaction_db = self._apply_pre_run_policies(liveaction_db=liveaction_db)

        # Exit if the status of the request is no longer runnable.
        # The status could have be changed by one of the policies.
        if liveaction_db.status not in [
            action_constants.LIVEACTION_STATUS_REQUESTED,
            action_constants.LIVEACTION_STATUS_SCHEDULED,
        ]:
            LOG.info(
                '%s is ignoring %s (id=%s) with "%s" status after policies are applied.',
                self.__class__.__name__,
                type(request),
                request.id,
                liveaction_db.status,
            )
            return

        # Update liveaction status to "scheduled".
        if liveaction_db.status == action_constants.LIVEACTION_STATUS_REQUESTED:
            liveaction_db = action_service.update_status(
                liveaction_db, action_constants.LIVEACTION_STATUS_SCHEDULED, publish=False
            )

        # Publish the "scheduled" status here manually. Otherwise, there could be a
        # race condition with the update of the action_execution_db if the execution
        # of the liveaction completes first.
        LiveAction.publish_status(liveaction_db)
Exemple #41
0
    def _handle_execution(self, execution_queue_item_db):
        liveaction_id = str(execution_queue_item_db.liveaction_id)
        queue_item_id = str(execution_queue_item_db.id)

        extra = {
            'liveaction_id': liveaction_id,
            'queue_item_id': queue_item_id
        }

        LOG.info('Scheduling liveaction: %s (queue_item_id=%s)', liveaction_id,
                 queue_item_id, extra=extra)

        try:
            liveaction_db = action_utils.get_liveaction_by_id(liveaction_id)
        except StackStormDBObjectNotFoundError:
            LOG.exception('Failed to find liveaction %s in the database (queue_item_id=%s).',
                          liveaction_id, queue_item_id, extra=extra)
            ActionExecutionSchedulingQueue.delete(execution_queue_item_db)
            raise

        # Identify if the action has policies that require locking.
        action_has_policies_require_lock = policy_service.has_policies(
            liveaction_db,
            policy_types=policy_constants.POLICY_TYPES_REQUIRING_LOCK
        )

        # Acquire a distributed lock if the referenced action has specific policies attached.
        if action_has_policies_require_lock:
            # Warn users that the coordination service is not configured.
            if not coordination_service.configured():
                LOG.warn(
                    'Coordination backend is not configured. '
                    'Policy enforcement is best effort.'
                )

            # Acquire a distributed lock before querying the database to make sure that only one
            # scheduler is scheduling execution for this action. Even if the coordination service
            # is not configured, the fake driver using zake or the file driver can still acquire
            # a lock for the local process or server respectively.
            lock_uid = liveaction_db.action
            LOG.debug('%s is attempting to acquire lock "%s".', self.__class__.__name__, lock_uid)
            lock = self._coordinator.get_lock(lock_uid)

            try:
                if lock.acquire(blocking=False):
                    self._regulate_and_schedule(liveaction_db, execution_queue_item_db)
                else:
                    self._delay(liveaction_db, execution_queue_item_db)
            finally:
                lock.release()
        else:
            # Otherwise if there is no policy, then schedule away.
            self._schedule(liveaction_db, execution_queue_item_db)
Exemple #42
0
 def test_basic_execution_canceled(self):
     testworker = worker.Worker(None)
     live_action_db = self._get_execution_db_model(
         status=action_constants.LIVEACTION_STATUS_CANCELED)
     result = getattr(live_action_db, 'result', None)
     self.assertTrue(result == {}, getattr(live_action_db, 'result', None))
     testworker.execute_action(live_action_db)
     updated_live_action_db = get_liveaction_by_id(live_action_db.id)
     self.assertEqual(updated_live_action_db.status,
                      action_constants.LIVEACTION_STATUS_CANCELED)
     result = getattr(updated_live_action_db, 'result', None)
     self.assertTrue(result['message'] is not None)
Exemple #43
0
    def process(self, liveaction):
        """Dispatches the LiveAction to appropriate action runner.

        LiveAction in statuses other than "scheduled" and "canceling" are ignored. If
        LiveAction is already canceled and result is empty, the LiveAction
        is updated with a generic exception message.

        :param liveaction: Action execution request.
        :type liveaction: ``st2common.models.db.liveaction.LiveActionDB``

        :rtype: ``dict``
        """

        if liveaction.status == action_constants.LIVEACTION_STATUS_CANCELED:
            LOG.info('%s is not executing %s (id=%s) with "%s" status.',
                     self.__class__.__name__, type(liveaction), liveaction.id, liveaction.status)
            if not liveaction.result:
                updated_liveaction = action_utils.update_liveaction_status(
                    status=liveaction.status,
                    result={'message': 'Action execution canceled by user.'},
                    liveaction_id=liveaction.id)
                executions.update_execution(updated_liveaction)
            return

        if liveaction.status not in ACTIONRUNNER_DISPATCHABLE_STATES:
            LOG.info('%s is not dispatching %s (id=%s) with "%s" status.',
                     self.__class__.__name__, type(liveaction), liveaction.id, liveaction.status)
            return

        try:
            liveaction_db = action_utils.get_liveaction_by_id(liveaction.id)
        except StackStormDBObjectNotFoundError:
            LOG.exception('Failed to find liveaction %s in the database.', liveaction.id)
            raise

        if liveaction.status != liveaction_db.status:
            LOG.warning(
                'The status of liveaction %s has changed from %s to %s '
                'while in the queue waiting for processing.',
                liveaction.id,
                liveaction.status,
                liveaction_db.status
            )

        dispatchers = {
            action_constants.LIVEACTION_STATUS_SCHEDULED: self._run_action,
            action_constants.LIVEACTION_STATUS_CANCELING: self._cancel_action,
            action_constants.LIVEACTION_STATUS_PAUSING: self._pause_action,
            action_constants.LIVEACTION_STATUS_RESUMING: self._resume_action
        }

        return dispatchers[liveaction.status](liveaction)
Exemple #44
0
    def process(self, liveaction):
        """Dispatches the LiveAction to appropriate action runner.

        LiveAction in statuses other than "scheduled" and "canceling" are ignored. If
        LiveAction is already canceled and result is empty, the LiveAction
        is updated with a generic exception message.

        :param liveaction: Action execution request.
        :type liveaction: ``st2common.models.db.liveaction.LiveActionDB``

        :rtype: ``dict``
        """

        if liveaction.status == action_constants.LIVEACTION_STATUS_CANCELED:
            LOG.info('%s is not executing %s (id=%s) with "%s" status.',
                     self.__class__.__name__, type(liveaction), liveaction.id, liveaction.status)
            if not liveaction.result:
                updated_liveaction = action_utils.update_liveaction_status(
                    status=liveaction.status,
                    result={'message': 'Action execution canceled by user.'},
                    liveaction_id=liveaction.id)
                executions.update_execution(updated_liveaction)
            return

        if liveaction.status not in ACTIONRUNNER_DISPATCHABLE_STATES:
            LOG.info('%s is not dispatching %s (id=%s) with "%s" status.',
                     self.__class__.__name__, type(liveaction), liveaction.id, liveaction.status)
            return

        try:
            liveaction_db = action_utils.get_liveaction_by_id(liveaction.id)
        except StackStormDBObjectNotFoundError:
            LOG.exception('Failed to find liveaction %s in the database.', liveaction.id)
            raise

        if liveaction.status != liveaction_db.status:
            LOG.warning(
                'The status of liveaction %s has changed from %s to %s '
                'while in the queue waiting for processing.',
                liveaction.id,
                liveaction.status,
                liveaction_db.status
            )

        dispatchers = {
            action_constants.LIVEACTION_STATUS_SCHEDULED: self._run_action,
            action_constants.LIVEACTION_STATUS_CANCELING: self._cancel_action,
            action_constants.LIVEACTION_STATUS_PAUSING: self._pause_action,
            action_constants.LIVEACTION_STATUS_RESUMING: self._resume_action
        }

        return dispatchers[liveaction.status](liveaction)
Exemple #45
0
 def test_basic_execution_canceled(self):
     testworker = worker.Worker(None)
     live_action_db = self._get_execution_db_model(
         status=action_constants.LIVEACTION_STATUS_CANCELED)
     result = getattr(live_action_db, 'result', None)
     self.assertTrue(result == {},
                     getattr(live_action_db, 'result', None))
     testworker.execute_action(live_action_db)
     updated_live_action_db = get_liveaction_by_id(live_action_db.id)
     self.assertEqual(updated_live_action_db.status,
                      action_constants.LIVEACTION_STATUS_CANCELED)
     result = getattr(updated_live_action_db, 'result', None)
     self.assertTrue(result['message'] is not None)
Exemple #46
0
    def _update_live_action_db(self, liveaction_id, status, result, context):
        liveaction_db = get_liveaction_by_id(liveaction_id)
        if status in action_constants.COMPLETED_STATES:
            end_timestamp = isotime.add_utc_tz(datetime.datetime.utcnow())
        else:
            end_timestamp = None

        liveaction_db = update_liveaction_status(status=status,
                                                 result=result,
                                                 context=context,
                                                 end_timestamp=end_timestamp,
                                                 liveaction_db=liveaction_db)
        return liveaction_db
Exemple #47
0
    def _update_live_action_db(self, liveaction_id, status, result, context):
        liveaction_db = get_liveaction_by_id(liveaction_id)
        if status in DONE_STATES:
            end_timestamp = isotime.add_utc_tz(datetime.datetime.utcnow())
        else:
            end_timestamp = None

        liveaction_db = update_liveaction_status(status=status,
                                                 result=result,
                                                 context=context,
                                                 end_timestamp=end_timestamp,
                                                 liveaction_db=liveaction_db)
        return liveaction_db
Exemple #48
0
    def test_request_cancellation_uncancelable_state(self):
        request, execution = self._submit_request()
        self.assertIsNotNone(execution)
        self.assertEqual(execution.id, request.id)
        self.assertEqual(execution.status, action_constants.LIVEACTION_STATUS_REQUESTED)

        # Update execution status to FAILED.
        action_service.update_status(execution, action_constants.LIVEACTION_STATUS_FAILED, False)
        execution = action_db.get_liveaction_by_id(execution.id)
        self.assertEqual(execution.status, action_constants.LIVEACTION_STATUS_FAILED)

        # Request cancellation.
        self.assertRaises(Exception, action_service.request_cancellation, execution)
Exemple #49
0
    def _update_live_action_db(self, liveaction_id, status, result, context):
        liveaction_db = get_liveaction_by_id(liveaction_id)
        if status in action_constants.COMPLETED_STATES:
            end_timestamp = date_utils.get_datetime_utc_now()
        else:
            end_timestamp = None

        liveaction_db = update_liveaction_status(status=status,
                                                 result=result,
                                                 context=context,
                                                 end_timestamp=end_timestamp,
                                                 liveaction_db=liveaction_db)
        return liveaction_db
Exemple #50
0
    def test_request_cancellation_uncancelable_state(self):
        request, execution = self._submit_request()
        self.assertIsNotNone(execution)
        self.assertEqual(execution.id, request.id)
        self.assertEqual(execution.status, action_constants.LIVEACTION_STATUS_REQUESTED)

        # Update execution status to FAILED.
        action_service.update_status(execution, action_constants.LIVEACTION_STATUS_FAILED, False)
        execution = action_db.get_liveaction_by_id(execution.id)
        self.assertEqual(execution.status, action_constants.LIVEACTION_STATUS_FAILED)

        # Request cancellation.
        self.assertRaises(Exception, action_service.request_cancellation, execution)
Exemple #51
0
    def _run_action(self, liveaction, wait_for_completion=True):
        try:
            liveaction, _ = action_service.request(liveaction)
        except:
            liveaction.status = LIVEACTION_STATUS_FAILED
            raise Exception('Failed to schedule liveaction.')

        while (wait_for_completion and
               liveaction.status != LIVEACTION_STATUS_SUCCEEDED and
               liveaction.status != LIVEACTION_STATUS_FAILED):
            eventlet.sleep(1)
            liveaction = action_db_util.get_liveaction_by_id(liveaction.id)

        return liveaction
Exemple #52
0
    def test_request_cancellation(self):
        request, execution = self._submit_request()
        self.assertIsNotNone(execution)
        self.assertEqual(execution.id, request.id)
        self.assertEqual(execution.status, action_constants.LIVEACTION_STATUS_REQUESTED)

        # Update execution status to RUNNING.
        action_service.update_status(execution, action_constants.LIVEACTION_STATUS_RUNNING, False)
        execution = action_db.get_liveaction_by_id(execution.id)
        self.assertEqual(execution.status, action_constants.LIVEACTION_STATUS_RUNNING)

        # Request cancellation.
        execution = self._submit_cancellation(execution)
        self.assertEqual(execution.status, action_constants.LIVEACTION_STATUS_CANCELING)
Exemple #53
0
    def test_request_cancellation(self):
        request, execution = self._submit_request()
        self.assertIsNotNone(execution)
        self.assertEqual(execution.id, request.id)
        self.assertEqual(execution.status, action_constants.LIVEACTION_STATUS_REQUESTED)

        # Update execution status to RUNNING.
        action_service.update_status(execution, action_constants.LIVEACTION_STATUS_RUNNING, False)
        execution = action_db.get_liveaction_by_id(execution.id)
        self.assertEqual(execution.status, action_constants.LIVEACTION_STATUS_RUNNING)

        # Request cancellation.
        execution = self._submit_cancellation(execution)
        self.assertEqual(execution.status, action_constants.LIVEACTION_STATUS_CANCELING)
Exemple #54
0
    def execute_action(self, liveaction):
        # Note: We only want to execute actions which haven't completed yet
        if liveaction.status == LIVEACTION_STATUS_CANCELED:
            LOG.info('Not executing liveaction %s. User canceled execution.', liveaction.id)
            if not liveaction.result:
                update_liveaction_status(status=LIVEACTION_STATUS_CANCELED,
                                         result={'message': 'Action execution canceled by user.'},
                                         liveaction_id=liveaction.id)
            return

        if liveaction.status in [LIVEACTION_STATUS_SUCCEEDED, LIVEACTION_STATUS_FAILED]:
            LOG.info('Ignoring liveaction %s which has already finished', liveaction.id)
            return

        try:
            liveaction_db = get_liveaction_by_id(liveaction.id)
        except StackStormDBObjectNotFoundError:
            LOG.exception('Failed to find liveaction %s in the database.',
                          liveaction.id)
            raise

        # stamp liveaction with process_info
        runner_info = system_info.get_process_info()

        # Update liveaction status to "running"
        liveaction_db = update_liveaction_status(status=LIVEACTION_STATUS_RUNNING,
                                                 runner_info=runner_info,
                                                 liveaction_id=liveaction_db.id)
        action_execution_db = executions.update_execution(liveaction_db)

        # Launch action
        extra = {'action_execution_db': action_execution_db, 'liveaction_db': liveaction_db}
        LOG.audit('Launching action execution.', extra=extra)

        # the extra field will not be shown in non-audit logs so temporarily log at info.
        LOG.info('{~}action_execution: %s / {~}live_action: %s',
                 action_execution_db.id, liveaction_db.id)
        try:
            result = self.container.dispatch(liveaction_db)
            LOG.debug('Runner dispatch produced result: %s', result)
            if not result:
                raise ActionRunnerException('Failed to execute action.')
        except Exception:
            liveaction_db = update_liveaction_status(status=LIVEACTION_STATUS_FAILED,
                                                     liveaction_id=liveaction_db.id)
            raise

        return result
Exemple #55
0
    def _run_action(action_node, parent_execution_id, params, wait_for_completion=True):
        execution = LiveActionDB(action=action_node.ref)
        execution.parameters = action_param_utils.cast_params(action_ref=action_node.ref,
                                                              params=params)
        execution.context = {
            'parent': str(parent_execution_id),
            'chain': vars(action_node)
        }

        liveaction, _ = action_service.schedule(execution)
        while (wait_for_completion and
               liveaction.status != LIVEACTION_STATUS_SUCCEEDED and
               liveaction.status != LIVEACTION_STATUS_FAILED):
            eventlet.sleep(1)
            liveaction = action_db_util.get_liveaction_by_id(liveaction.id)
        return liveaction
    def _run_action(self, liveaction, wait_for_completion=True, sleep_delay=1.0):
        """
        :param sleep_delay: Number of seconds to wait during "is completed" polls.
        :type sleep_delay: ``float``
        """
        try:
            # request return canceled
            liveaction, _ = action_service.request(liveaction)
        except Exception as e:
            liveaction.status = LIVEACTION_STATUS_FAILED
            LOG.exception('Failed to schedule liveaction.')
            raise e

        while (wait_for_completion and liveaction.status not in LIVEACTION_COMPLETED_STATES):
            eventlet.sleep(sleep_delay)
            liveaction = action_db_util.get_liveaction_by_id(liveaction.id)

        return liveaction