-
Notifications
You must be signed in to change notification settings - Fork 0
Add Interactive task type and keeper #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -241,10 +241,10 @@ def __init__( | |||||||||||||
| # we need to ensure that they can read and write to the directory. | ||||||||||||||
| # But we don't want everybody on the system to, which is why the | ||||||||||||||
| # outer directory exists with no read permissions. | ||||||||||||||
| self._outer_dir = tempfile.mkdtemp( | ||||||||||||||
| self._outer_dir: str = tempfile.mkdtemp( | ||||||||||||||
| dir=self.temp_dir, prefix="cms-%s-" % (self.name) | ||||||||||||||
| ) | ||||||||||||||
| self._home = os.path.join(self._outer_dir, "home") | ||||||||||||||
| self._home: str = os.path.join(self._outer_dir, "home") | ||||||||||||||
| self._home_dest = "/tmp" | ||||||||||||||
| os.mkdir(self._home) | ||||||||||||||
|
|
||||||||||||||
|
|
@@ -266,15 +266,16 @@ def __init__( | |||||||||||||
| self.inherit_env: list[str] = [] # -E | ||||||||||||||
| self.set_env: dict[str, str] = {} # -E | ||||||||||||||
| self.fsize: int | None = None # -f | ||||||||||||||
| self.stdin_file: str | None = None # -i | ||||||||||||||
| self.stdout_file: str | None = None # -o | ||||||||||||||
| self.stderr_file: str | None = None # -r | ||||||||||||||
| self.stdin_file: str | int | None = None # -i | ||||||||||||||
| self.stdout_file: str | int | None = None # -o | ||||||||||||||
| self.stderr_file: str | int | None = None # -r | ||||||||||||||
| self.stack_space: int | None = None # -k | ||||||||||||||
| self.address_space: int | None = None # -m | ||||||||||||||
| self.timeout: float | None = None # -t | ||||||||||||||
| self.verbosity: int = 0 # -v | ||||||||||||||
| self.wallclock_timeout: float | None = None # -w | ||||||||||||||
| self.extra_timeout: float | None = None # -x | ||||||||||||||
| self.close_fds = True | ||||||||||||||
|
|
||||||||||||||
| self.max_processes: int = 1 | ||||||||||||||
|
|
||||||||||||||
|
|
@@ -656,13 +657,15 @@ def execute_without_std( | |||||||||||||
| return the Popen object from subprocess. | ||||||||||||||
|
|
||||||||||||||
| """ | ||||||||||||||
| popen = self._popen( | ||||||||||||||
| command, | ||||||||||||||
| stdin=subprocess.PIPE, | ||||||||||||||
| stdout=subprocess.PIPE, | ||||||||||||||
| stderr=subprocess.PIPE, | ||||||||||||||
| close_fds=True, | ||||||||||||||
| stdin = self.stdin_file if isinstance(self.stdin_file, int) else subprocess.PIPE | ||||||||||||||
| stdout = ( | ||||||||||||||
| self.stdout_file if isinstance(self.stdout_file, int) else subprocess.PIPE | ||||||||||||||
| ) | ||||||||||||||
| stderr = ( | ||||||||||||||
| self.stderr_file if isinstance(self.stderr_file, int) else subprocess.PIPE | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
| popen = self._popen(command, stdin=stdin, stdout=stdout, stderr=stderr) | ||||||||||||||
|
|
||||||||||||||
| # If the caller wants us to wait for completion, we also avoid | ||||||||||||||
| # std*** to interfere with command. Otherwise we let the | ||||||||||||||
|
|
@@ -730,12 +733,13 @@ def cleanup(self, delete: bool = False): | |||||||||||||
| self._home_dest, | ||||||||||||||
| ], | ||||||||||||||
| stdout=subprocess.DEVNULL, | ||||||||||||||
| stderr=subprocess.STDOUT, | ||||||||||||||
| stderr=subprocess.DEVNULL, | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
| # Tell isolate to cleanup the sandbox. | ||||||||||||||
| subprocess.check_call( | ||||||||||||||
| exe + ["--cleanup"], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT | ||||||||||||||
| exe + ["--cleanup"], | ||||||||||||||
| stdout=subprocess.DEVNULL, | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
| if delete: | ||||||||||||||
|
|
@@ -878,21 +882,21 @@ def build_box_options(self) -> list[str]: | |||||||||||||
| if self.fsize is not None: | ||||||||||||||
| # Isolate wants file size as KiB. | ||||||||||||||
| res += ["--fsize=%d" % (self.fsize // 1024)] | ||||||||||||||
| if self.stdin_file is not None: | ||||||||||||||
| if isinstance(self.stdin_file, str): | ||||||||||||||
| res += ["--stdin=%s" % self.inner_absolute_path(self.stdin_file)] | ||||||||||||||
| if self.stack_space is not None: | ||||||||||||||
| # Isolate wants stack size as KiB. | ||||||||||||||
| res += ["--stack=%d" % (self.stack_space // 1024)] | ||||||||||||||
| if self.address_space is not None: | ||||||||||||||
| # Isolate wants memory size as KiB. | ||||||||||||||
| res += ["--cg-mem=%d" % (self.address_space // 1024)] | ||||||||||||||
| if self.stdout_file is not None: | ||||||||||||||
| if isinstance(self.stdout_file, str): | ||||||||||||||
| res += ["--stdout=%s" % self.inner_absolute_path(self.stdout_file)] | ||||||||||||||
| if self.max_processes is not None: | ||||||||||||||
| res += ["--processes=%d" % self.max_processes] | ||||||||||||||
| else: | ||||||||||||||
| res += ["--processes"] | ||||||||||||||
| if self.stderr_file is not None: | ||||||||||||||
| if isinstance(self.stderr_file, str): | ||||||||||||||
| res += ["--stderr=%s" % self.inner_absolute_path(self.stderr_file)] | ||||||||||||||
| if self.timeout is not None: | ||||||||||||||
| res += ["--time=%g" % self.timeout] | ||||||||||||||
|
|
@@ -901,6 +905,8 @@ def build_box_options(self) -> list[str]: | |||||||||||||
| res += ["--wall-time=%g" % self.wallclock_timeout] | ||||||||||||||
| if self.extra_timeout is not None: | ||||||||||||||
| res += ["--extra-time=%g" % self.extra_timeout] | ||||||||||||||
| if not self.close_fds: | ||||||||||||||
| res += ["--inherit-fds", "--open-files=0"] | ||||||||||||||
| res += ["--meta=%s" % ("%s.%d" % (self.info_basename, self.exec_num))] | ||||||||||||||
| res += ["--run"] | ||||||||||||||
| return res | ||||||||||||||
|
|
@@ -958,7 +964,6 @@ def _popen( | |||||||||||||
| stdin: int | None = None, | ||||||||||||||
| stdout: int | None = None, | ||||||||||||||
| stderr: int | None = None, | ||||||||||||||
| close_fds: bool = True, | ||||||||||||||
| ) -> subprocess.Popen: | ||||||||||||||
| """Execute the given command in the sandbox using | ||||||||||||||
| subprocess.Popen, assigning the corresponding standard file | ||||||||||||||
|
|
@@ -968,7 +973,6 @@ def _popen( | |||||||||||||
| stdin: a file descriptor. | ||||||||||||||
| stdout: a file descriptor. | ||||||||||||||
| stderr: a file descriptor. | ||||||||||||||
| close_fds: close all file descriptor before executing. | ||||||||||||||
|
|
||||||||||||||
| return: popen object. | ||||||||||||||
|
|
||||||||||||||
|
|
@@ -989,7 +993,11 @@ def _popen( | |||||||||||||
| os.chmod(self._home, prev_permissions) | ||||||||||||||
| try: | ||||||||||||||
| p = subprocess.Popen( | ||||||||||||||
| args, stdin=stdin, stdout=stdout, stderr=stderr, close_fds=close_fds | ||||||||||||||
| args, | ||||||||||||||
| stdin=stdin, | ||||||||||||||
| stdout=stdout, | ||||||||||||||
| stderr=stderr, | ||||||||||||||
| close_fds=self.close_fds, | ||||||||||||||
| ) | ||||||||||||||
| except OSError: | ||||||||||||||
| logger.critical( | ||||||||||||||
|
|
@@ -1005,6 +1013,6 @@ def initialize_isolate(self): | |||||||||||||
| """Initialize isolate's box.""" | ||||||||||||||
| init_cmd = ["isolate", "--box-id=%d" % self.box_id, "--cg", "--init"] | ||||||||||||||
| try: | ||||||||||||||
| subprocess.check_call(init_cmd) | ||||||||||||||
| subprocess.check_call(init_cmd, stdout=subprocess.DEVNULL) | ||||||||||||||
|
||||||||||||||
| subprocess.check_call(init_cmd, stdout=subprocess.DEVNULL) | |
| subprocess.check_call( | |
| init_cmd, | |
| stdout=subprocess.DEVNULL, | |
| stderr=subprocess.DEVNULL, | |
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -136,8 +136,8 @@ def evaluation_step( | |
| for command in commands: | ||
| success = evaluation_step_before_run( | ||
| sandbox, command, time_limit, memory_limit, | ||
| dirs_map, writable_files, stdin_redirect, stdout_redirect, | ||
| multiprocess, wait=True) | ||
| None, dirs_map, writable_files, stdin_redirect, | ||
| stdout_redirect, multiprocess, wait=True) | ||
| if not success: | ||
|
Comment on lines
136
to
141
|
||
| logger.debug("Job failed in evaluation_step_before_run.") | ||
| return False, None, None | ||
|
|
@@ -154,11 +154,13 @@ def evaluation_step_before_run( | |
| command: list[str], | ||
| time_limit: float | None = None, | ||
| memory_limit: int | None = None, | ||
| wall_limit: float | None = None, | ||
| dirs_map: dict[str, tuple[str | None, str | None]] | None = None, | ||
| writable_files: list[str] | None = None, | ||
| stdin_redirect: str | None = None, | ||
| stdout_redirect: str | None = None, | ||
| stdin_redirect: str | int | None = None, | ||
| stdout_redirect: str | int | None = "stdout.txt", | ||
| multiprocess: bool = False, | ||
| close_fds: bool = True, | ||
| wait: bool = False, | ||
| ) -> bool | subprocess.Popen: | ||
| """First part of an evaluation step, up to the execution, included. | ||
|
|
@@ -175,6 +177,8 @@ def evaluation_step_before_run( | |
| # Ensure parameters are appropriate. | ||
| if time_limit is not None and time_limit <= 0: | ||
| raise ValueError("Time limit must be positive, is %s" % time_limit) | ||
| if wall_limit is not None and wall_limit <= 0: | ||
| raise ValueError("Wall limit must be positive, is %s" % wall_limit) | ||
| if memory_limit is not None and memory_limit <= 0: | ||
| raise ValueError( | ||
| "Memory limit must be positive, is %s" % memory_limit) | ||
|
|
@@ -184,8 +188,6 @@ def evaluation_step_before_run( | |
| dirs_map = {} | ||
| if writable_files is None: | ||
| writable_files = [] | ||
| if stdout_redirect is None: | ||
| stdout_redirect = "stdout.txt" | ||
|
|
||
| # Set sandbox parameters suitable for evaluation. | ||
| if time_limit is not None: | ||
|
|
@@ -195,6 +197,9 @@ def evaluation_step_before_run( | |
| sandbox.timeout = None | ||
| sandbox.wallclock_timeout = None | ||
|
|
||
| if wall_limit is not None: | ||
| sandbox.wallclock_timeout = wall_limit | ||
|
|
||
| if memory_limit is not None: | ||
| sandbox.address_space = memory_limit | ||
| else: | ||
|
|
@@ -210,11 +215,12 @@ def evaluation_step_before_run( | |
| for src, (dest, options) in dirs_map.items(): | ||
| sandbox.add_mapped_directory(src, dest=dest, options=options) | ||
| for name in [sandbox.stderr_file, sandbox.stdout_file]: | ||
| if name is not None: | ||
| if isinstance(name, str): | ||
| writable_files.append(name) | ||
| sandbox.allow_writing_only(writable_files) | ||
|
|
||
| sandbox.set_multiprocess(multiprocess) | ||
| sandbox.close_fds = close_fds | ||
|
|
||
| # Actually run the evaluation command. | ||
| logger.debug("Starting execution step.") | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cleanup() now calls isolate --cleanup with stdout suppressed but leaves stderr inherited. This can leak isolate noise/errors into worker logs (and differs from the earlier behavior that fully silenced isolate output). Pass stderr=DEVNULL (or redirect it consistently) to keep sandbox cleanup quiet and predictable.