def download_results(self): """ POST /admin/download_pack """ Logger.info("ADMIN", "Creating zip file") zip_directory = os.path.join(Config.storedir, "zips", Database.gen_id()) os.makedirs(zip_directory, exist_ok=True) zipf_name = ("results-" + Database.get_meta("admin_token").split("-", 1)[0] + "-" + time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) + ".zip") zipf_name = os.path.join(zip_directory, zipf_name) command = ("zip -r '" + zipf_name + "' db.sqlite3* log.sqlite3* " "files/input files/output " "files/source /version* " "/proc/cpuinfo* " "/var/log/nginx") try: gevent.subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: Logger.error("ADMIN", "Zip error: %s" % e.output) raise e return { "path": os.path.relpath(zipf_name, Config.storedir) } # pragma: nocover
def upload_source(self, input, file): """ POST /upload_source """ alerts = [] if get_exeflags(file["content"]): alerts.append({ "severity": "warning", "message": "You have submitted an executable! Please send the " "source code." }) Logger.info("UPLOAD", "User %s has uploaded an executable" % input["token"]) if not alerts: alerts.append({ "severity": "success", "message": "Source file uploaded correctly." }) source_id = Database.gen_id() try: path = StorageManager.new_source_file(source_id, file["name"]) except ValueError: BaseHandler.raise_exc(BadRequest, "INVALID_FILENAME", "The provided file has an invalid name") StorageManager.save_file(path, file["content"]) file_size = StorageManager.get_file_size(path) Database.add_source(source_id, input["id"], path, file_size) Logger.info("UPLOAD", "User %s has uploaded the source %s" % ( input["token"], source_id)) output = BaseHandler.format_dates(Database.get_source(source_id)) output["validation"] = {"alerts": alerts} return output
def upload_output(self, input, file): """ POST /upload_output """ output_id = Database.gen_id() try: path = StorageManager.new_output_file(output_id, file["name"]) except ValueError: BaseHandler.raise_exc(BadRequest, "INVALID_FILENAME", "The provided file has an invalid name") StorageManager.save_file(path, file["content"]) file_size = StorageManager.get_file_size(path) try: result = ContestManager.evaluate_output(input["task"], input["path"], path) except: BaseHandler.raise_exc(InternalServerError, "INTERNAL_ERROR", "Failed to evaluate the output") Database.add_output(output_id, input["id"], path, file_size, result) Logger.info( "UPLOAD", "User %s has uploaded the output %s" % (input["token"], output_id)) return InfoHandler.patch_output(Database.get_output(output_id))
def submit(self, output, source): """ POST /submit """ input = Database.get_input(output["input"]) if input is None: Logger.warning("DB_CONSISTENCY_ERROR", "Input %s not found in the db" % output["input"]) self.raise_exc(BadRequest, "WRONG_INPUT", "The provided input in invalid") if output["input"] != source["input"]: Logger.warning("POSSIBLE_CHEAT", "Trying to submit wrong pair source-output") self.raise_exc(Forbidden, "WRONG_OUTPUT_SOURCE", "The provided pair of source-output is invalid") score = ContestHandler.compute_score(input["task"], output["result"]) Database.begin() try: submission_id = Database.gen_id() if not Database.add_submission(submission_id, input["id"], output["id"], source["id"], score, autocommit=False): self.raise_exc(BadRequest, "INTERNAL_ERROR", "Error inserting the submission") ContestHandler.update_user_score(input["token"], input["task"], score) Database.set_user_attempt(input["token"], input["task"], None, autocommit=False) Database.commit() except sqlite3.IntegrityError as ex: Database.rollback() # provide a better error message if the input has already been # submitted if "UNIQUE constraint failed: submissions.input" in str(ex): self.raise_exc(Forbidden, "ALREADY_SUBMITTED", "This input has already been submitted") raise except: Database.rollback() raise Logger.info( "CONTEST", "User %s has submitted %s on %s" % (input["token"], submission_id, input["task"])) return InfoHandler.patch_submission( Database.get_submission(submission_id))
def test_gen_id(self): MIN_ID_LENGTH = 10 id = Database.gen_id() self.assertIsInstance(id, str) self.assertGreaterEqual(len(id), MIN_ID_LENGTH)
def worker(task_name): """ Method that stays in the background and generates inputs """ task = ContestManager.tasks[task_name] queue = ContestManager.input_queue[task_name] while True: try: id = Database.gen_id() path = StorageManager.new_input_file(id, task_name, "invalid") seed = int(sha256(id.encode()).hexdigest(), 16) % (2**31) stdout = os.open( StorageManager.get_absolute_path(path), os.O_WRONLY | os.O_CREAT, 0o644, ) try: start_time = time.monotonic() # generate the input and store the stdout into a file retcode = gevent.subprocess.call( [task["generator"], str(seed), "0"], stdout=stdout) if time.monotonic() > start_time + 1: Logger.warning( "TASK", "Generation of input %s for task %s took %f seconds" % (seed, task_name, time.monotonic() - start_time), ) finally: os.close(stdout) if retcode != 0: Logger.error( "TASK", "Error %d generating input %s (%d) for task %s" % (retcode, id, seed, task_name), ) # skip the input continue # if there is a validator in the task use it to check if the # generated input is valid if "validator" in task: stdin = os.open(StorageManager.get_absolute_path(path), os.O_RDONLY) try: start_time = time.monotonic() # execute the validator piping the input file to stdin retcode = gevent.subprocess.call( [task["validator"], "0"], stdin=stdin) if time.monotonic() > start_time + 1: Logger.warning( "TASK", "Validation of input %s for task %s took %f " "seconds" % (seed, task_name, time.monotonic() - start_time), ) finally: os.close(stdin) if retcode != 0: Logger.error( "TASK", "Error %d validating input %s (%d) for task %s" % (retcode, id, seed, task_name), ) # skip the input continue Logger.debug( "TASK", "Generated input %s (%d) for task %s" % (id, seed, task_name), ) # this method is blocking if the queue is full queue.put({"id": id, "path": path}) except: Logger.error( "TASK", "Exception while creating an input file: " + traceback.format_exc(), )