Example #1
0
    def _insert_mock_stdout_and_stderr_objects_for_execution(
        self, execution_id, count=5
    ):
        execution_id = str(execution_id)

        stdout_dbs, stderr_dbs = [], []
        for i in range(0, count):
            stdout_db = ActionExecutionOutputDB(
                execution_id=execution_id,
                action_ref="dummy.pack",
                runner_ref="dummy",
                output_type="stdout",
                data="stdout %s" % (i),
            )
            ActionExecutionOutput.add_or_update(stdout_db)

            stderr_db = ActionExecutionOutputDB(
                execution_id=execution_id,
                action_ref="dummy.pack",
                runner_ref="dummy",
                output_type="stderr",
                data="stderr%s" % (i),
            )
            ActionExecutionOutput.add_or_update(stderr_db)

        return stdout_dbs, stderr_dbs
    def test_get_output_finished_execution(self):
        # Test the execution output API endpoint for execution which has finished
        for status in action_constants.LIVEACTION_COMPLETED_STATES:
            # Insert mock execution and output objects
            status = action_constants.LIVEACTION_STATUS_SUCCEEDED
            timestamp = date_utils.get_datetime_utc_now()
            action_execution_db = ActionExecutionDB(
                start_timestamp=timestamp,
                end_timestamp=timestamp,
                status=status,
                action={"ref": "core.local"},
                runner={"name": "local-shell-cmd"},
                liveaction={"ref": "foo"},
            )
            action_execution_db = ActionExecution.add_or_update(
                action_execution_db)

            for i in range(1, 6):
                stdout_db = ActionExecutionOutputDB(
                    execution_id=str(action_execution_db.id),
                    action_ref="core.local",
                    runner_ref="dummy",
                    timestamp=timestamp,
                    output_type="stdout",
                    data="stdout %s\n" % (i),
                )
                ActionExecutionOutput.add_or_update(stdout_db)

            for i in range(10, 15):
                stderr_db = ActionExecutionOutputDB(
                    execution_id=str(action_execution_db.id),
                    action_ref="core.local",
                    runner_ref="dummy",
                    timestamp=timestamp,
                    output_type="stderr",
                    data="stderr %s\n" % (i),
                )
                ActionExecutionOutput.add_or_update(stderr_db)

            resp = self.app.get(
                "/v1/executions/%s/output" % (str(action_execution_db.id)),
                expect_errors=False,
            )
            self.assertEqual(resp.status_int, 200)

            events = self._parse_response(resp.text)
            self.assertEqual(len(events), 11)
            self.assertEqual(events[0][1]["data"], "stdout 1\n")
            self.assertEqual(events[9][1]["data"], "stderr 14\n")
            self.assertEqual(events[10][0], "EOF")

            # Verify "last" short-hand id works
            resp = self.app.get("/v1/executions/last/output",
                                expect_errors=False)
            self.assertEqual(resp.status_int, 200)

            events = self._parse_response(resp.text)
            self.assertEqual(len(events), 11)
            self.assertEqual(events[10][0], "EOF")
    def test_get_output_finished_execution(self):
        # Test the execution output API endpoint for execution which has finished
        for status in action_constants.LIVEACTION_COMPLETED_STATES:
            # Insert mock execution and output objects
            status = action_constants.LIVEACTION_STATUS_SUCCEEDED
            timestamp = date_utils.get_datetime_utc_now()
            action_execution_db = ActionExecutionDB(
                start_timestamp=timestamp,
                end_timestamp=timestamp,
                status=status,
                action={'ref': 'core.local'},
                runner={'name': 'local-shell-cmd'},
                liveaction={'ref': 'foo'})
            action_execution_db = ActionExecution.add_or_update(
                action_execution_db)

            for i in range(1, 6):
                stdout_db = ActionExecutionOutputDB(execution_id=str(
                    action_execution_db.id),
                                                    action_ref='core.local',
                                                    runner_ref='dummy',
                                                    timestamp=timestamp,
                                                    output_type='stdout',
                                                    data='stdout %s\n' % (i))
                ActionExecutionOutput.add_or_update(stdout_db)

            for i in range(10, 15):
                stderr_db = ActionExecutionOutputDB(execution_id=str(
                    action_execution_db.id),
                                                    action_ref='core.local',
                                                    runner_ref='dummy',
                                                    timestamp=timestamp,
                                                    output_type='stderr',
                                                    data='stderr %s\n' % (i))
                ActionExecutionOutput.add_or_update(stderr_db)

            resp = self.app.get('/v1/executions/%s/output' %
                                (str(action_execution_db.id)),
                                expect_errors=False)
            self.assertEqual(resp.status_int, 200)

            events = self._parse_response(resp.text)
            self.assertEqual(len(events), 11)
            self.assertEqual(events[0][1]['data'], 'stdout 1\n')
            self.assertEqual(events[9][1]['data'], 'stderr 14\n')
            self.assertEqual(events[10][0], 'EOF')

            # Verify "last" short-hand id works
            resp = self.app.get('/v1/executions/last/output',
                                expect_errors=False)
            self.assertEqual(resp.status_int, 200)

            events = self._parse_response(resp.text)
            self.assertEqual(len(events), 11)
            self.assertEqual(events[10][0], 'EOF')
Example #4
0
        def publish_action_finished(action_execution_db):
            # Insert mock output object
            output_params['data'] = 'stdout pre finish 1\n'
            output_db = ActionExecutionOutputDB(**output_params)
            ActionExecutionOutput.add_or_update(output_db)

            # Transition execution to completed state so the connection closes
            action_execution_db.status = action_constants.LIVEACTION_STATUS_SUCCEEDED
            action_execution_db = ActionExecution.add_or_update(action_execution_db)
Example #5
0
def store_execution_output_data_ex(
    execution_id, action_ref, runner_ref, data, output_type="output", timestamp=None
):
    timestamp = timestamp or date_utils.get_datetime_utc_now()

    output_db = ActionExecutionOutputDB(
        execution_id=execution_id,
        action_ref=action_ref,
        runner_ref=runner_ref,
        timestamp=timestamp,
        output_type=output_type,
        data=data,
    )

    output_db = ActionExecutionOutput.add_or_update(
        output_db, publish=True, dispatch_trigger=False
    )

    return output_db
Example #6
0
def store_execution_output_data(execution_db, action_db, data, output_type='output',
                                timestamp=None):
    """
    Store output from an execution as a new document in the collection.
    """
    execution_id = str(execution_db.id)
    action_ref = action_db.ref
    runner_ref = getattr(action_db, 'runner_type', {}).get('name', 'unknown')
    timestamp = timestamp or date_utils.get_datetime_utc_now()

    output_db = ActionExecutionOutputDB(execution_id=execution_id,
                                        action_ref=action_ref,
                                        runner_ref=runner_ref,
                                        timestamp=timestamp,
                                        output_type=output_type,
                                        data=data)
    output_db = ActionExecutionOutput.add_or_update(output_db, publish=True,
                                                    dispatch_trigger=False)

    return output_db
 def insert_mock_data():
     output_params['data'] = 'stdout mid 1\n'
     output_db = ActionExecutionOutputDB(**output_params)
     ActionExecutionOutput.add_or_update(output_db)
    def test_get_output_running_execution(self):
        # Retrieve lister instance to avoid race with listener connection not being established
        # early enough for tests to pass.
        # NOTE: This only affects tests where listeners are not pre-initialized.
        listener = get_listener(name='execution_output')
        eventlet.sleep(1.0)

        # Test the execution output API endpoint for execution which is running (blocking)
        status = action_constants.LIVEACTION_STATUS_RUNNING
        timestamp = date_utils.get_datetime_utc_now()
        action_execution_db = ActionExecutionDB(
            start_timestamp=timestamp,
            end_timestamp=timestamp,
            status=status,
            action={'ref': 'core.local'},
            runner={'name': 'local-shell-cmd'},
            liveaction={'ref': 'foo'})
        action_execution_db = ActionExecution.add_or_update(
            action_execution_db)

        output_params = dict(execution_id=str(action_execution_db.id),
                             action_ref='core.local',
                             runner_ref='dummy',
                             timestamp=timestamp,
                             output_type='stdout',
                             data='stdout before start\n')

        # Insert mock output object
        output_db = ActionExecutionOutputDB(**output_params)
        ActionExecutionOutput.add_or_update(output_db, publish=False)

        def insert_mock_data():
            output_params['data'] = 'stdout mid 1\n'
            output_db = ActionExecutionOutputDB(**output_params)
            ActionExecutionOutput.add_or_update(output_db)

        # Since the API endpoint is blocking (connection is kept open until action finishes), we
        # spawn an eventlet which eventually finishes the action.
        def publish_action_finished(action_execution_db):
            # Insert mock output object
            output_params['data'] = 'stdout pre finish 1\n'
            output_db = ActionExecutionOutputDB(**output_params)
            ActionExecutionOutput.add_or_update(output_db)

            eventlet.sleep(1.0)

            # Transition execution to completed state so the connection closes
            action_execution_db.status = action_constants.LIVEACTION_STATUS_SUCCEEDED
            action_execution_db = ActionExecution.add_or_update(
                action_execution_db)

        eventlet.spawn_after(0.2, insert_mock_data)
        eventlet.spawn_after(1.5, publish_action_finished, action_execution_db)

        # Retrieve data while execution is running - endpoint return new data once it's available
        # and block until the execution finishes
        resp = self.app.get('/v1/executions/%s/output' %
                            (str(action_execution_db.id)),
                            expect_errors=False)
        self.assertEqual(resp.status_int, 200)

        events = self._parse_response(resp.text)
        self.assertEqual(len(events), 4)
        self.assertEqual(events[0][1]['data'], 'stdout before start\n')
        self.assertEqual(events[1][1]['data'], 'stdout mid 1\n')
        self.assertEqual(events[2][1]['data'], 'stdout pre finish 1\n')
        self.assertEqual(events[3][0], 'EOF')

        # Once the execution is in completed state, existing output should be returned immediately
        resp = self.app.get('/v1/executions/%s/output' %
                            (str(action_execution_db.id)),
                            expect_errors=False)
        self.assertEqual(resp.status_int, 200)

        events = self._parse_response(resp.text)
        self.assertEqual(len(events), 4)
        self.assertEqual(events[0][1]['data'], 'stdout before start\n')
        self.assertEqual(events[1][1]['data'], 'stdout mid 1\n')
        self.assertEqual(events[2][1]['data'], 'stdout pre finish 1\n')
        self.assertEqual(events[3][0], 'EOF')

        listener.shutdown()
Example #9
0
    def test_garbage_collection(self):
        now = date_utils.get_datetime_utc_now()
        status = action_constants.LIVEACTION_STATUS_SUCCEEDED

        # Insert come mock ActionExecutionDB objects with start_timestamp < TTL defined in the
        # config
        old_executions_count = 15
        ttl_days = 30  # > 20
        timestamp = (now - datetime.timedelta(days=ttl_days))
        for index in range(0, old_executions_count):
            action_execution_db = ActionExecutionDB(
                start_timestamp=timestamp,
                end_timestamp=timestamp,
                status=status,
                action={'ref': 'core.local'},
                runner={'name': 'local-shell-cmd'},
                liveaction={'ref': 'foo'})
            ActionExecution.add_or_update(action_execution_db)

            stdout_db = ActionExecutionOutputDB(execution_id=str(
                action_execution_db.id),
                                                action_ref='core.local',
                                                runner_ref='dummy',
                                                timestamp=timestamp,
                                                output_type='stdout',
                                                data='stdout')
            ActionExecutionOutput.add_or_update(stdout_db)

            stderr_db = ActionExecutionOutputDB(execution_id=str(
                action_execution_db.id),
                                                action_ref='core.local',
                                                runner_ref='dummy',
                                                timestamp=timestamp,
                                                output_type='stderr',
                                                data='stderr')
            ActionExecutionOutput.add_or_update(stderr_db)

        # Insert come mock ActionExecutionDB objects with start_timestamp > TTL defined in the
        # config
        new_executions_count = 5
        ttl_days = 2  # < 20
        timestamp = (now - datetime.timedelta(days=ttl_days))
        for index in range(0, new_executions_count):
            action_execution_db = ActionExecutionDB(
                start_timestamp=timestamp,
                end_timestamp=timestamp,
                status=status,
                action={'ref': 'core.local'},
                runner={'name': 'local-shell-cmd'},
                liveaction={'ref': 'foo'})
            ActionExecution.add_or_update(action_execution_db)

            stdout_db = ActionExecutionOutputDB(execution_id=str(
                action_execution_db.id),
                                                action_ref='core.local',
                                                runner_ref='dummy',
                                                timestamp=timestamp,
                                                output_type='stdout',
                                                data='stdout')
            ActionExecutionOutput.add_or_update(stdout_db)

            stderr_db = ActionExecutionOutputDB(execution_id=str(
                action_execution_db.id),
                                                action_ref='core.local',
                                                runner_ref='dummy',
                                                timestamp=timestamp,
                                                output_type='stderr',
                                                data='stderr')
            ActionExecutionOutput.add_or_update(stderr_db)

        # Insert some mock output objects where start_timestamp > action_executions_output_ttl
        new_output_count = 5
        ttl_days = 15  # > 10 and < 20
        timestamp = (now - datetime.timedelta(days=ttl_days))
        for index in range(0, new_output_count):
            action_execution_db = ActionExecutionDB(
                start_timestamp=timestamp,
                end_timestamp=timestamp,
                status=status,
                action={'ref': 'core.local'},
                runner={'name': 'local-shell-cmd'},
                liveaction={'ref': 'foo'})
            ActionExecution.add_or_update(action_execution_db)

            stdout_db = ActionExecutionOutputDB(execution_id=str(
                action_execution_db.id),
                                                action_ref='core.local',
                                                runner_ref='dummy',
                                                timestamp=timestamp,
                                                output_type='stdout',
                                                data='stdout')
            ActionExecutionOutput.add_or_update(stdout_db)

            stderr_db = ActionExecutionOutputDB(execution_id=str(
                action_execution_db.id),
                                                action_ref='core.local',
                                                runner_ref='dummy',
                                                timestamp=timestamp,
                                                output_type='stderr',
                                                data='stderr')
            ActionExecutionOutput.add_or_update(stderr_db)

        execs = ActionExecution.get_all()
        self.assertEqual(
            len(execs),
            (old_executions_count + new_executions_count + new_output_count))

        stdout_dbs = ActionExecutionOutput.query(output_type='stdout')
        self.assertEqual(
            len(stdout_dbs),
            (old_executions_count + new_executions_count + new_output_count))

        stderr_dbs = ActionExecutionOutput.query(output_type='stderr')
        self.assertEqual(
            len(stderr_dbs),
            (old_executions_count + new_executions_count + new_output_count))

        # Start garbage collector
        process = self._start_garbage_collector()

        # Give it some time to perform garbage collection and kill it
        eventlet.sleep(15)
        process.send_signal(signal.SIGKILL)
        self.remove_process(process=process)

        # Old executions and corresponding objects should have been garbage collected
        execs = ActionExecution.get_all()
        self.assertEqual(len(execs), (new_executions_count + new_output_count))

        # Collection for output objects older than 10 days is also enabled, so those objects
        # should be deleted as well
        stdout_dbs = ActionExecutionOutput.query(output_type='stdout')
        self.assertEqual(len(stdout_dbs), (new_executions_count))

        stderr_dbs = ActionExecutionOutput.query(output_type='stderr')
        self.assertEqual(len(stderr_dbs), (new_executions_count))
Example #10
0
    def test_get_all_with_filters(self):
        cfg.CONF.set_override(name='heartbeat', group='stream', override=0.1)

        listener = st2common.stream.listener.get_listener(name='stream')
        process_execution = listener.processor(ActionExecutionAPI)
        process_liveaction = listener.processor(LiveActionAPI)
        process_output = listener.processor(ActionExecutionOutputAPI)
        process_no_api_model = listener.processor()

        execution_api = ActionExecutionDB(**EXECUTION_1)
        liveaction_api = LiveActionDB(**LIVE_ACTION_1)
        output_api_stdout = ActionExecutionOutputDB(**STDOUT_1)
        output_api_stderr = ActionExecutionOutputDB(**STDERR_1)

        def dispatch_and_handle_mock_data(resp):
            received_messages_data = ''
            for index, message in enumerate(resp._app_iter):
                if message.strip():
                    received_messages_data += message

                # Dispatch some mock events
                if index == 0:
                    meta = META('st2.execution', 'create')
                    process_execution(execution_api, meta)
                elif index == 1:
                    meta = META('st2.execution', 'update')
                    process_execution(execution_api, meta)
                elif index == 2:
                    meta = META('st2.execution', 'delete')
                    process_execution(execution_api, meta)
                elif index == 3:
                    meta = META('st2.liveaction', 'create')
                    process_liveaction(liveaction_api, meta)
                elif index == 4:
                    meta = META('st2.liveaction', 'create')
                    process_liveaction(liveaction_api, meta)
                elif index == 5:
                    meta = META('st2.liveaction', 'delete')
                    process_liveaction(liveaction_api, meta)
                elif index == 6:
                    meta = META('st2.liveaction', 'delete')
                    process_liveaction(liveaction_api, meta)
                elif index == 7:
                    meta = META('st2.announcement', 'chatops')
                    process_no_api_model({}, meta)
                elif index == 8:
                    meta = META('st2.execution.output', 'create')
                    process_output(output_api_stdout, meta)
                elif index == 9:
                    meta = META('st2.execution.output', 'create')
                    process_output(output_api_stderr, meta)
                elif index == 10:
                    meta = META('st2.announcement', 'errbot')
                    process_no_api_model({}, meta)

                else:
                    break

            received_messages = received_messages_data.split('\n\n')
            received_messages = [message for message in received_messages if message]
            return received_messages

        # 1. Default filter - stdout and stderr messages should be excluded for backward
        # compatibility reasons
        resp = stream.StreamController().get_all()

        received_messages = dispatch_and_handle_mock_data(resp)
        self.assertEqual(len(received_messages), 9)
        self.assertTrue('st2.execution__create' in received_messages[0])
        self.assertTrue('st2.liveaction__delete' in received_messages[5])
        self.assertTrue('st2.announcement__chatops' in received_messages[7])
        self.assertTrue('st2.announcement__errbot' in received_messages[8])

        # 1. ?events= filter
        # No filter provided - all messages should be received
        stream.DEFAULT_EVENTS_WHITELIST = None
        resp = stream.StreamController().get_all()

        received_messages = dispatch_and_handle_mock_data(resp)
        self.assertEqual(len(received_messages), 11)
        self.assertTrue('st2.execution__create' in received_messages[0])
        self.assertTrue('st2.announcement__chatops' in received_messages[7])
        self.assertTrue('st2.execution.output__create' in received_messages[8])
        self.assertTrue('st2.execution.output__create' in received_messages[9])
        self.assertTrue('st2.announcement__errbot' in received_messages[10])

        # Filter provided, only three messages should be received
        events = ['st2.execution__create', 'st2.liveaction__delete']
        resp = stream.StreamController().get_all(events=events)

        received_messages = dispatch_and_handle_mock_data(resp)
        self.assertEqual(len(received_messages), 3)
        self.assertTrue('st2.execution__create' in received_messages[0])
        self.assertTrue('st2.liveaction__delete' in received_messages[1])
        self.assertTrue('st2.liveaction__delete' in received_messages[2])

        # Filter provided, only three messages should be received
        events = ['st2.liveaction__create', 'st2.liveaction__delete']
        resp = stream.StreamController().get_all(events=events)

        received_messages = dispatch_and_handle_mock_data(resp)
        self.assertEqual(len(received_messages), 4)
        self.assertTrue('st2.liveaction__create' in received_messages[0])
        self.assertTrue('st2.liveaction__create' in received_messages[1])
        self.assertTrue('st2.liveaction__delete' in received_messages[2])
        self.assertTrue('st2.liveaction__delete' in received_messages[3])

        # Glob filter
        events = ['st2.announcement__*']
        resp = stream.StreamController().get_all(events=events)

        received_messages = dispatch_and_handle_mock_data(resp)
        self.assertEqual(len(received_messages), 2)
        self.assertTrue('st2.announcement__chatops' in received_messages[0])
        self.assertTrue('st2.announcement__errbot' in received_messages[1])

        # Filter provided
        events = ['st2.execution.output__create']
        resp = stream.StreamController().get_all(events=events)

        received_messages = dispatch_and_handle_mock_data(resp)
        self.assertEqual(len(received_messages), 2)
        self.assertTrue('st2.execution.output__create' in received_messages[0])
        self.assertTrue('st2.execution.output__create' in received_messages[1])

        # Filter provided, invalid , no message should be received
        events = ['invalid1', 'invalid2']
        resp = stream.StreamController().get_all(events=events)

        received_messages = dispatch_and_handle_mock_data(resp)
        self.assertEqual(len(received_messages), 0)

        # 2. ?action_refs= filter
        action_refs = ['invalid1', 'invalid2']
        resp = stream.StreamController().get_all(action_refs=action_refs)

        received_messages = dispatch_and_handle_mock_data(resp)
        self.assertEqual(len(received_messages), 0)

        action_refs = ['dummy.action1']
        resp = stream.StreamController().get_all(action_refs=action_refs)

        received_messages = dispatch_and_handle_mock_data(resp)
        self.assertEqual(len(received_messages), 2)

        # 3. ?execution_ids= filter
        execution_ids = ['invalid1', 'invalid2']
        resp = stream.StreamController().get_all(execution_ids=execution_ids)

        received_messages = dispatch_and_handle_mock_data(resp)
        self.assertEqual(len(received_messages), 0)

        execution_ids = [EXECUTION_1['id']]
        resp = stream.StreamController().get_all(execution_ids=execution_ids)

        received_messages = dispatch_and_handle_mock_data(resp)
        self.assertEqual(len(received_messages), 5)
 def insert_mock_data():
     output_params["data"] = "stdout mid 1\n"
     output_db = ActionExecutionOutputDB(**output_params)
     ActionExecutionOutput.add_or_update(output_db)
Example #12
0
    def test_get_output_running_execution(self):
        # Test the execution output API endpoint for execution which is running (blocking)
        status = action_constants.LIVEACTION_STATUS_RUNNING
        timestamp = date_utils.get_datetime_utc_now()
        action_execution_db = ActionExecutionDB(start_timestamp=timestamp,
                                                end_timestamp=timestamp,
                                                status=status,
                                                action={'ref': 'core.local'},
                                                runner={'name': 'run-local'},
                                                liveaction={'ref': 'foo'})
        action_execution_db = ActionExecution.add_or_update(action_execution_db)

        output_params = dict(execution_id=str(action_execution_db.id),
                             action_ref='core.local',
                             runner_ref='dummy',
                             timestamp=timestamp,
                             output_type='stdout',
                             data='stdout before start\n')

        # Insert mock output object
        output_db = ActionExecutionOutputDB(**output_params)
        ActionExecutionOutput.add_or_update(output_db)

        def insert_mock_data():
            output_params['data'] = 'stdout mid 1\n'
            output_db = ActionExecutionOutputDB(**output_params)
            ActionExecutionOutput.add_or_update(output_db)
            pass

        # Since the API endpoint is blocking (connection is kept open until action finishes), we
        # spawn an eventlet which eventually finishes the action.
        def publish_action_finished(action_execution_db):
            # Insert mock output object
            output_params['data'] = 'stdout pre finish 1\n'
            output_db = ActionExecutionOutputDB(**output_params)
            ActionExecutionOutput.add_or_update(output_db)

            # Transition execution to completed state so the connection closes
            action_execution_db.status = action_constants.LIVEACTION_STATUS_SUCCEEDED
            action_execution_db = ActionExecution.add_or_update(action_execution_db)

        eventlet.spawn_after(0.2, insert_mock_data)
        eventlet.spawn_after(1.5, publish_action_finished, action_execution_db)
        resp = self.app.get('/v1/executions/%s/output' % (str(action_execution_db.id)),
                            expect_errors=False)

        self.assertEqual(resp.status_int, 200)
        lines = resp.text.strip().split('\n')
        self.assertEqual(len(lines), 3)
        self.assertEqual(lines[0], 'stdout before start')
        self.assertEqual(lines[1], 'stdout mid 1')
        self.assertEqual(lines[2], 'stdout pre finish 1')

        # Once the execution is in completed state, existing output should be returned immediately
        resp = self.app.get('/v1/executions/%s/output' % (str(action_execution_db.id)),
                            expect_errors=False)

        self.assertEqual(resp.status_int, 200)
        lines = resp.text.strip().split('\n')
        self.assertEqual(len(lines), 3)
        self.assertEqual(lines[0], 'stdout before start')
        self.assertEqual(lines[1], 'stdout mid 1')
        self.assertEqual(lines[2], 'stdout pre finish 1')