Пример #1
0
class TestRunExecutorWithSudo(TestRunExecutor):
    """
    Run tests using the sudo mode of RunExecutor, if possible.
    sudo is typically set up to allow executing as our own user,
    so we try that. Note that this will not catch all problems,
    for example if we forget to use "sudo kill" to send a signal
    and instead send it directly, but requiring a second user for tests
    would not be good, either.
    """

    # Use user name defined in environment variable if present,
    # or fall back to current user (sudo always allows this).
    # sudo allows refering to numerical uids with '#'.
    user = os.environ.get('BENCHEXEC_TEST_USER', '#' + str(os.getuid()))

    def setUp(self, *args, **kwargs):
        try:
            self.runexecutor = RunExecutor(user=self.user, *args, **kwargs)
        except SystemExit as e:
            # sudo seems not to be available
            self.skipTest(e)

    def check_exitcode(self, result, expected, msg=None):
        actual = int(result['exitcode'])
        if expected == 15 and actual == 0:
            # On Ubuntu 16.04, sudo returns 0 if process is killed with signal 15
            return

        # Using sudo may affect the exit code:
        # what was the returnsignal is now the returnvalue.
        # The distinction between returnsignal and returnvalue of the actual
        # process is lost.
        # If the returnsignal (of the sudo process) is 0,
        # we replace the exit code with the mixed returnsignal/returnvalue of
        # the actual process (with bit for core dump cleared).
        returnsignal = actual & 0x7F
        returnvalue = (actual >> 8) & 0x7F
        if returnsignal == 0:
            actual = returnvalue

        self.assertEqual(actual, expected, msg)

    def check_command_in_output(self, output, cmd):
        self.assertTrue(output[0].endswith(cmd), 'run output misses executed command')

    def test_detect_new_files_in_home(self):
        if not os.path.exists('/usr/bin/mktemp'):
            self.skipTest('missing /usr/bin/mktemp')
        home_dir = runexecutor._get_user_account_info(self.user).pw_dir
        tmp_file_pattern = '.BenchExec_test_runexecutor_'+unichr(0xe4)+unichr(0xf6)+unichr(0xfc)+'_XXXXXXXXXX'
        (result, output) = self.execute_run(
            '/usr/bin/mktemp', '--tmpdir=' + home_dir, tmp_file_pattern)
        try:
            self.check_exitcode(result, 0, 'exit code of /usr/bin/mktemp is not zero')
            tmp_file = output[-1]
            self.assertIn(tmp_file, self.runexecutor.check_for_new_files_in_home(),
                          'runexecutor failed to detect new temporary file in home directory')
        finally:
            subprocess.check_call(self.runexecutor._build_cmdline(['rm', tmp_file]))
Пример #2
0
class _Worker(threading.Thread):
    """
    A Worker is a deamonic thread, that takes jobs from the working_queue and runs them.
    """
    working_queue = Queue()

    def __init__(self, benchmark, my_cpus, my_memory_nodes, my_user, output_handler):
        threading.Thread.__init__(self) # constuctor of superclass
        self.benchmark = benchmark
        self.my_cpus = my_cpus
        self.my_memory_nodes = my_memory_nodes
        self.output_handler = output_handler
        self.run_executor = RunExecutor(user=my_user)
        self.setDaemon(True)

        self.start()


    def run(self):
        while not _Worker.working_queue.empty() and not STOPPED_BY_INTERRUPT:
            currentRun = _Worker.working_queue.get_nowait()
            try:
                logging.debug('Executing run "%s"', currentRun.identifier)
                self.execute(currentRun)
                logging.debug('Finished run "%s"', currentRun.identifier)
            except SystemExit as e:
                logging.critical(e)
            except BaseException as e:
                logging.exception('Exception during run execution')
            _Worker.working_queue.task_done()


    def execute(self, run):
        """
        This function executes the tool with a sourcefile with options.
        It also calls functions for output before and after the run.
        """
        self.output_handler.output_before_run(run)
        benchmark = self.benchmark

        memlimit = benchmark.rlimits.get(MEMLIMIT)

        args = run.cmdline()
        logging.debug('Command line of run is %s', args)
        result = \
            self.run_executor.execute_run(
                args, run.log_file,
                hardtimelimit=benchmark.rlimits.get(TIMELIMIT),
                softtimelimit=benchmark.rlimits.get(SOFTTIMELIMIT),
                cores=self.my_cpus,
                memory_nodes=self.my_memory_nodes,
                memlimit=memlimit,
                environments=benchmark.environment(),
                workingDir=benchmark.working_directory(),
                maxLogfileSize=benchmark.config.maxLogfileSize)

        for key, value in result.items():
            if key == 'walltime':
                run.walltime = value
            elif key == 'cputime':
                run.cputime = value
            elif key == 'memory':
                run.values['memUsage'] = result['memory']
            elif key == 'energy':
                for ekey, evalue in value.items():
                    run.values['energy-'+ekey] = evalue
            else:
                run.values['@' + key] = value

        if self.my_cpus:
            run.values['@cpuCores'] = self.my_cpus
        if self.my_memory_nodes:
            run.values['@memoryNodes'] = self.my_memory_nodes

        if self.run_executor.PROCESS_KILLED:
            # If the run was interrupted, we ignore the result and cleanup.
            run.walltime = 0
            run.cputime = 0
            try:
                if benchmark.config.debug:
                    os.rename(run.log_file, run.log_file + ".killed")
                else:
                    os.remove(run.log_file)
            except OSError:
                pass
            return 1

        run.after_execution(result['exitcode'], termination_reason=result.get('terminationreason', None))
        self.output_handler.output_after_run(run)


    def stop(self):
        # asynchronous call to runexecutor,
        # the worker will stop asap, but not within this method.
        self.run_executor.stop()

    def cleanup(self):
        self.run_executor.check_for_new_files_in_home()
Пример #3
0
class _Worker(threading.Thread):
    """
    A Worker is a deamonic thread, that takes jobs from the working_queue and runs them.
    """
    working_queue = Queue()

    def __init__(self, benchmark, my_cpus, my_memory_nodes, my_user,
                 output_handler):
        threading.Thread.__init__(self)  # constuctor of superclass
        self.benchmark = benchmark
        self.my_cpus = my_cpus
        self.my_memory_nodes = my_memory_nodes
        self.output_handler = output_handler
        self.run_executor = RunExecutor(user=my_user,
                                        **benchmark.config.containerargs)
        self.setDaemon(True)

        self.start()

    def run(self):
        while not _Worker.working_queue.empty() and not STOPPED_BY_INTERRUPT:
            currentRun = _Worker.working_queue.get_nowait()
            try:
                logging.debug('Executing run "%s"', currentRun.identifier)
                self.execute(currentRun)
                logging.debug('Finished run "%s"', currentRun.identifier)
            except SystemExit as e:
                logging.critical(e)
            except BenchExecException as e:
                logging.critical(e)
            except BaseException as e:
                logging.exception('Exception during run execution')
            _Worker.working_queue.task_done()

    def execute(self, run):
        """
        This function executes the tool with a sourcefile with options.
        It also calls functions for output before and after the run.
        """
        self.output_handler.output_before_run(run)
        benchmark = self.benchmark

        memlimit = benchmark.rlimits.get(MEMLIMIT)

        args = run.cmdline()
        logging.debug('Command line of run is %s', args)
        run_result = \
            self.run_executor.execute_run(
                args,
                output_filename=run.log_file,
                output_dir=run.result_files_folder,
                result_files_patterns=benchmark.result_files_patterns,
                hardtimelimit=benchmark.rlimits.get(TIMELIMIT),
                softtimelimit=benchmark.rlimits.get(SOFTTIMELIMIT),
                walltimelimit=benchmark.rlimits.get(WALLTIMELIMIT),
                cores=self.my_cpus,
                memory_nodes=self.my_memory_nodes,
                memlimit=memlimit,
                environments=benchmark.environment(),
                workingDir=benchmark.working_directory(),
                maxLogfileSize=benchmark.config.maxLogfileSize,
                files_count_limit=benchmark.config.filesCountLimit,
                files_size_limit=benchmark.config.filesSizeLimit)

        if self.run_executor.PROCESS_KILLED:
            # If the run was interrupted, we ignore the result and cleanup.
            try:
                if benchmark.config.debug:
                    os.rename(run.log_file, run.log_file + ".killed")
                else:
                    os.remove(run.log_file)
            except OSError:
                pass
            return 1

        if self.my_cpus:
            run_result['cpuCores'] = self.my_cpus
        if self.my_memory_nodes:
            run_result['memoryNodes'] = self.my_memory_nodes

        run.set_result(run_result)
        self.output_handler.output_after_run(run)

    def stop(self):
        # asynchronous call to runexecutor,
        # the worker will stop asap, but not within this method.
        self.run_executor.stop()

    def cleanup(self):
        self.run_executor.check_for_new_files_in_home()
Пример #4
0
class TestRunExecutorWithSudo(TestRunExecutor):
    """
    Run tests using the sudo mode of RunExecutor, if possible.
    sudo is typically set up to allow executing as our own user,
    so we try that. Note that this will not catch all problems,
    for example if we forget to use "sudo kill" to send a signal
    and instead send it directly, but requiring a second user for tests
    would not be good, either.
    """

    # Use user name defined in environment variable if present,
    # or fall back to current user (sudo always allows this).
    # sudo allows refering to numerical uids with '#'.
    user = os.environ.get('BENCHEXEC_TEST_USER', '#' + str(os.getuid()))

    def setUp(self, *args, **kwargs):
        try:
            self.runexecutor = RunExecutor(user=self.user, *args, **kwargs)
        except SystemExit as e:
            # sudo seems not to be available
            self.skipTest(e)

    def execute_run(self, *args, **kwargs):
        result, output = super(TestRunExecutorWithSudo, self).execute_run(*args, **kwargs)
        self.fix_exitcode(result)
        return (result, output)

    def execute_run_extern(self, *args, **kwargs):
        result, output = super(TestRunExecutorWithSudo, self) \
            .execute_run_extern('--user', self.user, *args, **kwargs)
        self.fix_exitcode(result)
        return (result, output)

    def fix_exitcode(self, result):
        # Using sudo may affect the exit code:
        # what was the returnsignal is now the returnvalue.
        # The distinction between returnsignal and returnvalue of the actual
        # process is lost.
        # If the returnsignal (of the sudo process) is 0,
        # we replace the exit code with the mixed returnsignal/returnvalue of
        # the actual process (with bit for core dump cleared).
        exitcode = int(result['exitcode'])
        returnsignal = exitcode & 0x7F
        returnvalue = (exitcode >> 8) & 0x7F
        if returnsignal == 0:
            result['exitcode'] = returnvalue

    def check_command_in_output(self, output, cmd):
        self.assertTrue(output[0].endswith(cmd), 'run output misses executed command')

    def test_detect_new_files_in_home(self):
        if not os.path.exists('/usr/bin/mktemp'):
            self.skipTest('missing /usr/bin/mktemp')
        home_dir = runexecutor._get_user_account_info(self.user).pw_dir
        tmp_file_pattern = '.BenchExec_test_runexecutor_'+unichr(0xe4)+unichr(0xf6)+unichr(0xfc)+'_XXXXXXXXXX'
        (result, output) = self.execute_run(
            '/usr/bin/mktemp', '--tmpdir=' + home_dir, tmp_file_pattern)
        try:
            self.assertEqual(int(result['exitcode']), 0, 'exit code of /usr/bin/mktemp is not zero')
            tmp_file = output[-1]
            self.assertIn(tmp_file, self.runexecutor.check_for_new_files_in_home(),
                          'runexecutor failed to detect new temporary file in home directory')
        finally:
            subprocess.check_call(self.runexecutor._build_cmdline('rm', tmp_file))
Пример #5
0
class TestRunExecutorWithSudo(TestRunExecutor):
    """
    Run tests using the sudo mode of RunExecutor, if possible.
    sudo is typically set up to allow executing as our own user,
    so we try that. Note that this will not catch all problems,
    for example if we forget to use "sudo kill" to send a signal
    and instead send it directly, but requiring a second user for tests
    would not be good, either.
    """

    # Use user name defined in environment variable if present,
    # or fall back to current user (sudo always allows this).
    # sudo allows refering to numerical uids with '#'.
    user = os.environ.get('BENCHEXEC_TEST_USER', '#' + str(os.getuid()))

    def setUp(self, *args, **kwargs):
        try:
            self.runexecutor = RunExecutor(user=self.user, *args, **kwargs)
        except SystemExit as e:
            # sudo seems not to be available
            self.skipTest(e)

    def check_exitcode(self, result, expected, msg=None):
        actual = int(result['exitcode'])
        if expected == 15 and actual == 0:
            # On Ubuntu 16.04, sudo returns 0 if process is killed with signal 15
            return

        # Using sudo may affect the exit code:
        # what was the returnsignal is now the returnvalue.
        # The distinction between returnsignal and returnvalue of the actual
        # process is lost.
        # If the returnsignal (of the sudo process) is 0,
        # we replace the exit code with the mixed returnsignal/returnvalue of
        # the actual process (with bit for core dump cleared).
        returnsignal = actual & 0x7F
        returnvalue = (actual >> 8) & 0x7F
        if returnsignal == 0:
            actual = returnvalue

        self.assertEqual(actual, expected, msg)

    def check_command_in_output(self, output, cmd):
        self.assertTrue(output[0].endswith(cmd),
                        'run output misses executed command')

    def test_detect_new_files_in_home(self):
        if not os.path.exists('/usr/bin/mktemp'):
            self.skipTest('missing /usr/bin/mktemp')
        home_dir = runexecutor._get_user_account_info(self.user).pw_dir
        tmp_file_pattern = '.BenchExec_test_runexecutor_' + unichr(
            0xe4) + unichr(0xf6) + unichr(0xfc) + '_XXXXXXXXXX'
        (result, output) = self.execute_run('/usr/bin/mktemp',
                                            '--tmpdir=' + home_dir,
                                            tmp_file_pattern)
        try:
            self.check_exitcode(result, 0,
                                'exit code of /usr/bin/mktemp is not zero')
            tmp_file = output[-1]
            self.assertIn(
                tmp_file, self.runexecutor.check_for_new_files_in_home(),
                'runexecutor failed to detect new temporary file in home directory'
            )
        finally:
            subprocess.check_call(
                self.runexecutor._build_cmdline(['rm', tmp_file]))

    def test_append_environment_variable(self):
        # sudo-mode has a suboptimal implementation for additionalEnv:
        # If an environment variable is not modified, it will be cleared completely and in case of
        # PATH sudo will set it. If PATH is specified in additionalEnv, we will copy the value
        # from the current process (which is different than what sudo would set)
        # and append the given string.
        pass