From b03e9e3b30434ec390ac640c2380157d60d1f81c Mon Sep 17 00:00:00 2001 From: virusdefender Date: Sun, 2 Oct 2016 02:05:16 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84SpecialJudge=E7=9A=84?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/Python/client.py | 41 ++++++++++++++++------- client/Python/languages.py | 7 +++- compiler.py | 5 +-- config.py | 4 +-- docker-compose.example.yml | 2 +- judge_client.py | 66 ++++++++++++++++++++++++++++++++------ server.py | 13 +++++--- 7 files changed, 105 insertions(+), 33 deletions(-) diff --git a/client/Python/client.py b/client/Python/client.py index de84aaf..e93eed1 100644 --- a/client/Python/client.py +++ b/client/Python/client.py @@ -31,18 +31,20 @@ class JudgeServerClient(object): def ping(self): return self._request(self.server_base_url + "/ping") - def judge(self, src, language_config, submission_id, max_cpu_time, max_memory, test_case_id): + def judge(self, src, language_config, submission_id, max_cpu_time, max_memory, test_case_id, spj_version=None, spj_config=None): data = {"language_config": language_config, "submission_id": submission_id, "src": src, "max_cpu_time": max_cpu_time, "max_memory": max_memory, - "test_case_id": test_case_id} + "test_case_id": test_case_id, + "spj_version": spj_version, + "spj_config": spj_config} return self._request(self.server_base_url + "/judge", data=data) - def compile_spj(self, src, spj_version, spj_config, test_case_id): + def compile_spj(self, src, spj_version, spj_compile_config, test_case_id): data = {"src": src, "spj_version": spj_version, - "spj_compile_config": spj_config, "test_case_id": test_case_id} + "spj_compile_config": spj_compile_config, "test_case_id": test_case_id} return self._request(self.server_base_url + "/compile_spj", data=data) @@ -59,6 +61,13 @@ if __name__ == "__main__": } """ + c_spj_src = r""" + #include + int main(){ + return 1; + } + """ + cpp_src = r""" #include @@ -87,14 +96,22 @@ if __name__ == "__main__": client = JudgeServerClient(token="token", server_base_url="http://123.57.151.42:11235") print client.ping(), "\n\n" - print client.compile_spj(src=c_src, spj_version="4", spj_config=c_lang_config["spj"], - test_case_id="d8c460de943189a83bad166ec96d975d"), "\n\n" + print client.compile_spj(src=c_spj_src, spj_version="1", spj_compile_config=c_lang_config["spj_compile"], + test_case_id="spj"), "\n\n" - print client.judge(src=cpp_src, language_config=cpp_lang_config, submission_id=str(int(time.time())), + print client.judge(src=c_src, language_config=c_lang_config, submission_id=str(int(time.time())), max_cpu_time=1000, max_memory=1024 * 1024 * 128, - test_case_id="d8c460de943189a83bad166ec96d975d"), "\n\n" - time.sleep(2) - print client.judge(src=java_src, language_config=java_lang_config, submission_id=str(int(time.time())), + test_case_id="normal"), "\n\n" + + print client.judge(src=cpp_src, language_config=cpp_lang_config, submission_id="1", max_cpu_time=1000, max_memory=1024 * 1024 * 128, - test_case_id="d8c460de943189a83bad166ec96d975d"), "\n\n" - time.sleep(2) + test_case_id="normal"), "\n\n" + + print client.judge(src=java_src, language_config=java_lang_config, submission_id="2", + max_cpu_time=1000, max_memory=1024 * 1024 * 1024, + test_case_id="normal"), "\n\n" + + print client.judge(src=c_src, language_config=c_lang_config, submission_id="3", + max_cpu_time=1000, max_memory=1024 * 1024 * 128, + test_case_id="spj", + spj_version="1", spj_config=c_lang_config["spj_config"]), "\n\n" diff --git a/client/Python/languages.py b/client/Python/languages.py index 0d98ef9..bf048d9 100644 --- a/client/Python/languages.py +++ b/client/Python/languages.py @@ -15,13 +15,18 @@ c_lang_config = { "seccomp_rule": None, "max_process_number": -1 }, - "spj": { + "spj_compile": { "src_name": "spj-{spj_version}.c", "exe_name": "spj-{spj_version}", "max_cpu_time": 10000, "max_real_time": 20000, "max_memory": 1024 * 1024 * 1024, "compile_command": "/usr/bin/gcc -DONLINE_JUDGE -O2 -w -fmax-errors=3 -std=c99 {src_path} -lm -o {exe_path}" + }, + "spj_config": { + "exe_name": "spj-{spj_version}", + "command": "{exe_path} {in_file_path} {user_out_file_path}", + "seccomp_rule": "c_cpp" } } diff --git a/compiler.py b/compiler.py index b6c2ccd..c061299 100644 --- a/compiler.py +++ b/compiler.py @@ -38,12 +38,9 @@ class Compiler(object): if result["result"] != _judger.RESULT_SUCCESS: with open(compiler_out) as f: error = f.read().strip() + os.remove(compiler_out) if error: raise CompileError(error) - - # 如果是spj的话, 不要在test_case文件夹中留下这个文件 - os.remove(compiler_out) - raise CompileError("Compiler runtime error, info: %s" % json.dumps(result).decode("utf-8")) return exe_path diff --git a/config.py b/config.py index cd3a37a..cc594ed 100644 --- a/config.py +++ b/config.py @@ -8,8 +8,8 @@ import pwd JUDGER_WORKSPACE_BASE = "/judger_run" LOG_BASE = "/log" -COMPILER_LOG_PATH = os.path.join(LOG_BASE, "compile.log") -JUDGER_RUN_LOG_PATH = os.path.join(LOG_BASE, "judger.log") +COMPILER_LOG_PATH = os.path.join(LOG_BASE, "compile.log").encode("utf-8") +JUDGER_RUN_LOG_PATH = os.path.join(LOG_BASE, "judger.log").encode("utf-8") LOW_PRIVILEDGE_UID = pwd.getpwnam("nobody").pw_uid LOW_PRIVILEDGE_GID = grp.getgrnam("nogroup").gr_gid diff --git a/docker-compose.example.yml b/docker-compose.example.yml index e1b24e0..88d2226 100644 --- a/docker-compose.example.yml +++ b/docker-compose.example.yml @@ -1,7 +1,7 @@ judge_server: image: judge_server volumes: - - /data/test_case:/test_case + - /data/JudgeServer/test/test_case:/test_case - /data/log:/log - /data/JudgeServer:/code environment: diff --git a/judge_client.py b/judge_client.py index ba9cede..61d82d5 100644 --- a/judge_client.py +++ b/judge_client.py @@ -12,12 +12,18 @@ from config import TEST_CASE_DIR, JUDGER_RUN_LOG_PATH, LOW_PRIVILEDGE_GID, LOW_P from exception import JudgeClientError +WA = -1 +SPJ_WA = 1 +SPJ_AC = 0 +SPJ_ERROR = -1 + + def _run(instance, test_case_file_id): return instance._judge_one(test_case_file_id) class JudgeClient(object): - def __init__(self, run_config, exe_path, max_cpu_time, max_memory, test_case_id, submission_dir): + def __init__(self, run_config, exe_path, max_cpu_time, max_memory, test_case_id, submission_dir, spj_version, spj_config): self._run_config = run_config self._exe_path = exe_path self._max_cpu_time = max_cpu_time @@ -30,6 +36,9 @@ class JudgeClient(object): self._pool = Pool(processes=psutil.cpu_count()) self._test_case_info = self._load_test_case_info() + self._spj_version = spj_version + self._spj_config = spj_config + def _load_test_case_info(self): try: with open(os.path.join(self._test_case_dir, "info")) as f: @@ -52,9 +61,36 @@ class JudgeClient(object): output_md5 = hashlib.md5(f.read().rstrip()).hexdigest() return output_md5, output_md5 == self._test_case_info["test_cases"][str(test_case_file_id)]["striped_output_md5"] + def _spj(self, in_file_path, user_out_file_path): + command = self._spj_config["command"].format(exe_path=os.path.join(self._test_case_dir, + self._spj_config["exe_name"].format(spj_version=self._spj_version)), + in_file_path=in_file_path, user_out_file_path=user_out_file_path).split(" ") + result = _judger.run(max_cpu_time=self._max_cpu_time * 3, + max_real_time=self._max_cpu_time * 9, + max_memory=self._max_memory * 3, + max_output_size=1024 * 1024 * 1024, + max_process_number=self._run_config["max_process_number"], + exe_path=command[0].encode("utf-8"), + input_path=in_file_path.encode("utf-8"), + output_path="/tmp/spj.out".encode("utf-8"), + error_path="/tmp/spj.out".encode("utf-8"), + args=[item.encode("utf-8") for item in command[1::]], + env=[("PATH=" + os.environ.get("PATH", "")).encode("utf-8")], + log_path=JUDGER_RUN_LOG_PATH, + seccomp_rule_so_path=self._seccomp_rule_path(self._spj_config["seccomp_rule"]), + uid=LOW_PRIVILEDGE_UID, + gid=LOW_PRIVILEDGE_GID) + print result + + if result["result"] == _judger.RESULT_SUCCESS or \ + (result["result"] == _judger.RESULT_RUNTIME_ERROR and result["exit_code"] in [SPJ_WA, SPJ_ERROR]): + return result["exit_code"] + else: + return SPJ_ERROR + def _judge_one(self, test_case_file_id): - in_file = os.path.join(self._test_case_dir, str(test_case_file_id) + ".in") - out_file = os.path.join(self._submission_dir, str(test_case_file_id) + ".out") + in_file = os.path.join(self._test_case_dir, str(test_case_file_id) + ".in").encode("utf-8") + out_file = os.path.join(self._submission_dir, str(test_case_file_id) + ".out").encode("utf-8") command = self._run_config["command"].format(exe_path=self._exe_path, exe_dir=os.path.dirname(self._exe_path), max_memory=self._max_memory / 1024).split(" ") @@ -69,7 +105,7 @@ class JudgeClient(object): output_path=out_file, error_path=out_file, args=[item.encode("utf-8") for item in command[1::]], - env=[("PATH=" + os.getenv("PATH")).encode("utf-8")], + env=[("PATH=" + os.getenv("PATH", "")).encode("utf-8")], log_path=JUDGER_RUN_LOG_PATH, seccomp_rule_so_path=self._seccomp_rule_path(self._run_config["seccomp_rule"]), uid=LOW_PRIVILEDGE_UID, @@ -78,11 +114,23 @@ class JudgeClient(object): # if progress exited normally, then we should check output result run_result["output_md5"] = None - if run_result["result"] == 0: - run_result["output_md5"], is_ac = self._compare_output(test_case_file_id) - # -1 == Wrong Answer - if not is_ac: - run_result["result"] = -1 + if run_result["result"] == _judger.RESULT_SUCCESS: + if self._test_case_info["spj"]: + if not self._spj_config or not self._spj_version: + raise JudgeClientError("spj_config or spj_version not set") + spj_result = self._spj(in_file_path=in_file, user_out_file_path=out_file) + + print "spj_result", spj_result + + if spj_result == SPJ_WA: + run_result["result"] = WA + elif spj_result == SPJ_ERROR: + run_result["result"] = _judger.RESULT_SYSTEM_ERROR + else: + run_result["output_md5"], is_ac = self._compare_output(test_case_file_id) + # -1 == Wrong Answer + if not is_ac: + run_result["result"] = WA return run_result diff --git a/server.py b/server.py index 69cf90b..85fafb8 100644 --- a/server.py +++ b/server.py @@ -6,6 +6,7 @@ import json import os import shutil import socket +import logging import _judger import psutil @@ -52,11 +53,12 @@ class JudgeServer(object): raise TokenVerificationFailed("token not set") return hashlib.sha256(t).hexdigest() - def judge(self, language_config, submission_id, src, max_cpu_time, max_memory, test_case_id): + def judge(self, language_config, submission_id, src, max_cpu_time, max_memory, test_case_id, + spj_version=None, spj_config=None): # init compile_config = language_config["compile"] - with InitSubmissionEnv(JUDGER_WORKSPACE_BASE, submission_id=submission_id) as submission_dir: + with InitSubmissionEnv(JUDGER_WORKSPACE_BASE, submission_id=str(submission_id)) as submission_dir: src_path = os.path.join(submission_dir, compile_config["src_name"]) # write source code into file @@ -72,8 +74,10 @@ class JudgeServer(object): exe_path=exe_path, max_cpu_time=max_cpu_time, max_memory=max_memory, - test_case_id=test_case_id, - submission_dir=submission_dir) + test_case_id=str(test_case_id), + submission_dir=submission_dir, + spj_version=str(spj_version), + spj_config=spj_config) run_result = judge_client.run() return run_result @@ -116,6 +120,7 @@ class JudgeServer(object): return json.dumps({"err": "invalid-method", "data": None}) return json.dumps({"err": None, "data": callback(**data)}) except Exception as e: + logging.exception(e) ret = dict() ret["err"] = e.__class__.__name__ ret["data"] = e.message