class ExecutionServiceAuthorizationTest(unittest.TestCase):
    owner_user = User('user_x', {audit_utils.AUTH_USERNAME: '******'})

    @parameterized.expand([(owner_user.user_id, None),
                           ('another_user', AccessProhibitedException),
                           ('admin_user', AccessProhibitedException),
                           ('history_user', AccessProhibitedException)])
    def test_get_active_executor(self, user_id, expected_exception):
        self._assert_throws_exception(
            expected_exception, self.executor_service.get_active_executor,
            self.execution_id, User(user_id, {}))

    @parameterized.expand([(owner_user.user_id, None),
                           ('another_user', AccessProhibitedException),
                           ('admin_user', AccessProhibitedException),
                           ('history_user', AccessProhibitedException)])
    def test_stop_script(self, user_id, expected_exception):
        self._assert_throws_exception(expected_exception,
                                      self.executor_service.stop_script,
                                      self.execution_id,
                                      User(user_id, {}),
                                      has_results=False)

    @parameterized.expand([(owner_user.user_id, None),
                           ('another_user', AccessProhibitedException),
                           ('admin_user', AccessProhibitedException),
                           ('history_user', AccessProhibitedException)])
    def test_kill_script(self, user_id, expected_exception):
        self._assert_throws_exception(expected_exception,
                                      self.executor_service.kill_script,
                                      self.execution_id,
                                      User(user_id, {}),
                                      has_results=False)

    @parameterized.expand([(owner_user.user_id, None),
                           ('another_user', AccessProhibitedException),
                           ('admin_user', None), ('history_user', None)])
    def test_is_running(self, user_id, expected_exception):
        self._assert_throws_exception(expected_exception,
                                      self.executor_service.is_running,
                                      self.execution_id, User(user_id, {}))

    @parameterized.expand([(owner_user.user_id, None),
                           ('another_user', AccessProhibitedException),
                           ('admin_user', AccessProhibitedException),
                           ('history_user', AccessProhibitedException)])
    def test_get_config(self, user_id, expected_exception):
        self._assert_throws_exception(expected_exception,
                                      self.executor_service.get_config,
                                      self.execution_id, User(user_id, {}))

    @parameterized.expand([(owner_user.user_id, None),
                           ('another_user', AccessProhibitedException),
                           ('admin_user', AccessProhibitedException),
                           ('history_user', AccessProhibitedException)])
    def test_cleanup(self, user_id, expected_exception):
        self.executor_service.stop_script(self.execution_id, self.owner_user)

        self._assert_throws_exception(expected_exception,
                                      self.executor_service.cleanup_execution,
                                      self.execution_id,
                                      User(user_id, {}),
                                      has_results=False)

        self.script_cleaned = True

    def _assert_throws_exception(self,
                                 expected_exception,
                                 func,
                                 *parameters,
                                 has_results=True):
        try:
            result = func(*parameters)
            if expected_exception:
                self.fail('Should throw ' + str(expected_exception) +
                          ', but did not')
            if has_results:
                self.assertIsNotNone(result)

        except Exception as e:
            self.assertIsInstance(e, expected_exception)

    def setUp(self) -> None:
        super().setUp()

        def create_process(executor, command, working_directory,
                           env_variables):
            return _MockProcessWrapper(executor, command, working_directory,
                                       env_variables)

        executor._process_creator = create_process

        authorizer = Authorizer([ANY_USER], ['admin_user'], ['history_user'],
                                [], EmptyGroupProvider())
        self.executor_service = ExecutionService(authorizer,
                                                 _IdGeneratorMock())

        self.execution_id = _start(self.executor_service,
                                   self.owner_user.user_id)

        self.script_cleaned = False

    def tearDown(self) -> None:
        super().tearDown()

        executor._process_creator = create_process_wrapper

        if not self.script_cleaned:
            self.executor_service.kill_script(self.execution_id,
                                              self.owner_user)
            self.executor_service.cleanup_execution(self.execution_id,
                                                    self.owner_user)
Пример #2
0
class ExecutionLoggingInitiatorTest(unittest.TestCase):
    def test_start_logging_on_execution_start(self):
        execution_id = self.executor_service.start_script(
            create_config_model('my_script'),
            {},
            'userX',
            create_audit_names(ip='localhost'))

        executor = self.executor_service.get_active_executor(execution_id)
        executor.process_wrapper.finish(0)

        entry = self.logging_service.find_history_entry(execution_id, 'userX')
        self.assertIsNotNone(entry)

    def test_logging_values(self):
        param1 = create_script_param_config('p1')
        param2 = create_script_param_config('p2', param='-x')
        param3 = create_script_param_config('p3', param='-y', no_value=True)
        param4 = create_script_param_config('p4', param='-z', type='int')
        config_model = create_config_model(
            'my_script', script_command='echo', parameters=[param1, param2, param3, param4])

        execution_id = self.executor_service.start_script(
            config_model,
            {'p1': 'abc', 'p3': True, 'p4': 987},
            'userX',
            create_audit_names(ip='localhost', auth_username='******'))

        executor = self.executor_service.get_active_executor(execution_id)
        executor.process_wrapper._write_script_output('some text\n')
        executor.process_wrapper._write_script_output('another text')
        executor.process_wrapper.finish(0)

        wait_observable_close_notification(executor.get_anonymized_output_stream(), 2)

        entry = self.logging_service.find_history_entry(execution_id, 'userX')
        self.assertIsNotNone(entry)
        self.assertEqual('userX', entry.user_id)
        self.assertEqual('sandy', entry.user_name)
        self.assertEqual('my_script', entry.script_name)
        self.assertEqual('echo abc -y -z 987', entry.command)
        self.assertEqual('my_script', entry.script_name)

        log = self.logging_service.find_log(execution_id)
        self.assertEqual('some text\nanother text', log)

    def test_exit_code(self):
        config_model = create_config_model(
            'my_script', script_command='ls', parameters=[])

        execution_id = self.executor_service.start_script(
            config_model,
            {},
            'userX',
            create_audit_names(ip='localhost'))

        executor = self.executor_service.get_active_executor(execution_id)
        executor.process_wrapper._write_script_output('some text\n')
        executor.process_wrapper._write_script_output('another text')
        executor.process_wrapper.finish(14)

        wait_observable_close_notification(executor.get_anonymized_output_stream(), 2)

        entry = self.logging_service.find_history_entry(execution_id, 'userX')
        self.assertEqual(14, entry.exit_code)

    def setUp(self):
        test_utils.setup()

        executor._process_creator = _MockProcessWrapper

        authorizer = Authorizer([], [], [], EmptyGroupProvider())
        self.logging_service = ExecutionLoggingService(test_utils.temp_folder, LogNameCreator(), authorizer)
        self.executor_service = ExecutionService(_IdGeneratorMock())

        self.controller = ExecutionLoggingController(self.executor_service, self.logging_service)
        self.controller.start()

    def tearDown(self):
        test_utils.cleanup()

        executions = self.executor_service.get_active_executions('userX')
        for execution_id in executions:
            try:
                self.executor_service.kill_script(execution_id)
                self.executor_service.cleanup_execution(execution_id)
            except:
                traceback.print_exc()
Пример #3
0
class TestInlineImages(unittest.TestCase):
    def setUp(self) -> None:
        test_utils.setup()

        executor._process_creator = _MockProcessWrapper
        self.executor_service = ExecutionService(_IdGeneratorMock())

        self.file_download_feature = file_download_feature.FileDownloadFeature(
            UserFileStorage(b'123456'), test_utils.temp_folder)
        self.file_download_feature.subscribe(self.executor_service)

        self.images = []

    def tearDown(self) -> None:
        test_utils.cleanup()

        executions = self.executor_service.get_active_executions('userX')
        for execution in executions:
            self.executor_service.kill_script(execution)

    def _add_image(self, original_path, new_path):
        self.images.append((original_path, new_path))

    def test_single_static_image(self):
        path = test_utils.create_file('test.png')
        config = create_config_model('my_script',
                                     output_files=[inline_image(path)])

        execution_id = self.start_execution(config)

        self.write_output(execution_id, '123\n456')

        self.wait_output_chunks(execution_id, chunks_count=1)

        self.assert_images(path)

    def test_multiple_static_images(self):
        path1 = test_utils.create_file('test1.png')
        path2 = test_utils.create_file('test2.png')
        path3 = test_utils.create_file('test3.png')
        config = create_config_model('my_script',
                                     output_files=[
                                         inline_image(path1),
                                         inline_image(path2),
                                         inline_image(path3)
                                     ])

        execution_id = self.start_execution(config)

        self.write_output(execution_id, '123\n' + '456')

        self.wait_output_chunks(execution_id, chunks_count=1)

        self.assert_images(path1, path2, path3)

    def test_single_static_image_when_multiple_outputs(self):
        path = test_utils.create_file('test.png')
        config = create_config_model('my_script',
                                     output_files=[inline_image(path)])

        execution_id = self.start_execution(config)

        self.write_output(execution_id, '123\n456')
        self.wait_output_chunks(execution_id, chunks_count=1)

        self.write_output(execution_id, '789\n0')
        self.wait_output_chunks(execution_id, chunks_count=2)

        self.assert_images(path)

    def test_single_dynamic_image(self):
        path = test_utils.create_file('test.png')
        config = create_config_model(
            'my_script', output_files=[inline_image('##any_path.png#')])

        execution_id = self.start_execution(config)

        full_path = file_utils.normalize_path(path)
        self.write_output(execution_id, '123\n' + full_path + '\n456')
        self.wait_output_chunks(execution_id, chunks_count=1)

        self.assert_images(full_path)

    def test_single_dynamic_image_when_unnormalized(self):
        test_utils.create_file('sub/test.png')
        config = create_config_model(
            'my_script', output_files=[inline_image('#([\.\w]+/)+\w+.png#')])

        execution_id = self.start_execution(config)

        unnormalized_path = os.path.join(test_utils.temp_folder, '.', 'sub',
                                         '..', 'sub', 'test.png')
        self.write_output(execution_id, '_ ' + unnormalized_path + ' _\n')
        self.wait_output_chunks(execution_id, chunks_count=1)

        image_keys = [img[0] for img in self.images]
        self.assertEqual([unnormalized_path], image_keys)

    def test_mixed_images_when_multiple_output(self):
        path1 = test_utils.create_file('test123.png')
        path2 = test_utils.create_file('images/test.png')
        path3 = test_utils.create_file('a.b.c.png')
        path4 = test_utils.create_file('test456.png')
        path5 = test_utils.create_file('some/long/path/me.jpg')

        config = create_config_model(
            'my_script',
            output_files=[
                inline_image(test_utils.temp_folder + os_utils.path_sep() +
                             '#test\d+.png#'),
                inline_image(path2),
                inline_image(path3),
                inline_image('##any_path/path/\w+#.jpg')
            ])

        execution_id = self.start_execution(config)

        paths = [
            normalize_path(p) for p in (path1, path2, path3, path4, path5)
        ]
        for index, path in enumerate(paths):
            self.write_output(execution_id, '__ ' + path + ' __\n')
            self.wait_output_chunks(execution_id, chunks_count=index + 1)

        self.write_output(execution_id, '__ ' + path2 + ' __\n')
        self.wait_output_chunks(execution_id, chunks_count=len(paths) + 1)

        self.assert_images(*paths)

    def test_find_multiple_images_by_same_pattern(self):
        path1 = test_utils.create_file('test123.png')
        test_utils.create_file('images/test.png')
        path3 = test_utils.create_file('a.b.c.png')
        path4 = test_utils.create_file('some/sub/folder/test456.png')

        config = create_config_model(
            'my_script', output_files=[inline_image('##any_path.png#')])

        execution_id = self.start_execution(config)

        paths = [normalize_path(p) for p in (path1, path3, path4)]
        for index, path in enumerate(paths):
            self.write_output(execution_id, '__ ' + path + ' __\n')
            self.wait_output_chunks(execution_id, chunks_count=index + 1)

        self.assert_images(*paths)

    def test_image_path_split_in_chunks(self):
        path = test_utils.create_file('test123.png')

        config = create_config_model(
            'my_script', output_files=[inline_image('##any_path.png#')])

        execution_id = self.start_execution(config)

        normalized = normalize_path(path)

        self.write_output(execution_id, normalized[:4])
        self.wait_output_chunks(execution_id, chunks_count=1)

        self.write_output(execution_id, normalized[4:] + '\n')
        self.wait_output_chunks(execution_id, chunks_count=2)

        self.assert_images(path)

    def test_image_path_split_in_chunks_and_no_newlines(self):
        path = test_utils.create_file('test123.png')

        config = create_config_model(
            'my_script', output_files=[inline_image('##any_path.png#')])

        execution_id = self.start_execution(config)

        normalized = normalize_path(path)

        self.write_output(execution_id, normalized[:4])
        self.wait_output_chunks(execution_id, chunks_count=1)

        self.write_output(execution_id, normalized[4:])
        self.wait_output_chunks(execution_id, chunks_count=2)

        self.executor_service.get_active_executor(
            execution_id).process_wrapper.stop()
        self.wait_close(execution_id)

        self.assert_images(path)

    def wait_output_chunks(self, execution_id, *, chunks_count):
        waiter = OutputWaiter()
        self.executor_service.get_anonymized_output_stream(
            execution_id).subscribe(waiter)
        waiter.wait_chunks(chunks_count, timeout=0.5)

    def wait_close(self, execution_id):
        chunk_condition = threading.Condition()
        closed = False

        def waiter():
            global closed
            closed = True
            with chunk_condition:
                chunk_condition.notify_all()

        self.executor_service.get_anonymized_output_stream(
            execution_id).subscribe_on_close(waiter)
        with chunk_condition:
            chunk_condition.wait_for(lambda: closed, 0.5)

    def write_output(self, execution_id, output):
        process_wrapper = self.executor_service.get_active_executor(
            execution_id).process_wrapper
        process_wrapper.write_output(output)

    def start_execution(self, config):
        execution_id = self.executor_service.start_script(
            config, {}, 'userX', {})
        self.file_download_feature.subscribe_on_inline_images(
            execution_id, self._add_image)
        return execution_id

    def assert_images(self, *paths):
        normalized_paths = [file_utils.normalize_path(p) for p in paths]
        actual_paths = [
            file_utils.normalize_path(image[0]) for image in self.images
        ]

        self.assertCountEqual(normalized_paths, actual_paths)
Пример #4
0
class ExecutionLoggingInitiatorTest(unittest.TestCase):
    def test_start_logging_on_execution_start(self):
        execution_id = self.executor_service.start_script(
            create_config_model('my_script'),
            {},
            'userX',
            create_audit_names(ip='localhost'))

        executor = self.executor_service.get_active_executor(execution_id)
        executor.process_wrapper.finish(0)

        entry = self.logging_service.find_history_entry(execution_id)
        self.assertIsNotNone(entry)

    def test_logging_values(self):
        param1 = create_script_param_config('p1')
        param2 = create_script_param_config('p2', param='-x')
        param3 = create_script_param_config('p3', param='-y', no_value=True)
        param4 = create_script_param_config('p4', param='-z', type='int')
        config_model = create_config_model(
            'my_script', script_command='echo', parameters=[param1, param2, param3, param4])

        execution_id = self.executor_service.start_script(
            config_model,
            {'p1': 'abc', 'p3': True, 'p4': 987},
            'userX',
            create_audit_names(ip='localhost', auth_username='******'))

        executor = self.executor_service.get_active_executor(execution_id)
        executor.process_wrapper._write_script_output('some text\n')
        executor.process_wrapper._write_script_output('another text')
        executor.process_wrapper.finish(0)

        wait_observable_close_notification(executor.get_anonymized_output_stream(), 2)

        entry = self.logging_service.find_history_entry(execution_id)
        self.assertIsNotNone(entry)
        self.assertEqual('userX', entry.user_id)
        self.assertEqual('sandy', entry.user_name)
        self.assertEqual('my_script', entry.script_name)
        self.assertEqual('echo abc -y -z 987', entry.command)
        self.assertEqual('my_script', entry.script_name)

        log = self.logging_service.find_log(execution_id)
        self.assertEqual('some text\nanother text', log)

    def test_exit_code(self):
        config_model = create_config_model(
            'my_script', script_command='ls', parameters=[])

        execution_id = self.executor_service.start_script(
            config_model,
            {},
            'userX',
            create_audit_names(ip='localhost'))

        executor = self.executor_service.get_active_executor(execution_id)
        executor.process_wrapper._write_script_output('some text\n')
        executor.process_wrapper._write_script_output('another text')
        executor.process_wrapper.finish(14)

        wait_observable_close_notification(executor.get_anonymized_output_stream(), 2)

        entry = self.logging_service.find_history_entry(execution_id)
        self.assertEqual(14, entry.exit_code)

    def setUp(self):
        test_utils.setup()

        executor._process_creator = _MockProcessWrapper

        self.logging_service = ExecutionLoggingService(test_utils.temp_folder, LogNameCreator())
        self.executor_service = ExecutionService(_IdGeneratorMock())

        self.controller = ExecutionLoggingController(self.executor_service, self.logging_service)
        self.controller.start()

    def tearDown(self):
        test_utils.cleanup()

        executions = self.executor_service.get_active_executions('userX')
        for execution_id in executions:
            try:
                self.executor_service.kill_script(execution_id)
                self.executor_service.cleanup_execution(execution_id)
            except:
                traceback.print_exc()