예제 #1
0
파일: server.py 프로젝트: sbofgayschool/KV2
        def api_task_search():
            """
            Flask Handler: API Interface: Search for tasks with specified conditions
            :return: Json containing the result, including total page number
            """
            # Check and get all conditions
            failed_result = {
                "result": ReturnCode.INVALID_INPUT,
                "pages": 0,
                "tasks": []
            }
            try:
                id = flask.request.args.get("id", None)
                if id is not None and not check_id(id):
                    return flask.jsonify(failed_result)
                user = flask.request.args.get("user", None)
                if user is not None:
                    user = int(user)
                    if not check_int(user):
                        return flask.jsonify(failed_result)
                start_time = flask.request.args.get("start_time", None)
                end_time = flask.request.args.get("end_time", None)
                old_to_new = bool(flask.request.args.get("old_to_new", False))
                limit = int(flask.request.args.get("limit", 0))
                if not check_int(limit):
                    return flask.jsonify(failed_result)
                page = int(flask.request.args.get("page", 0))
                if not check_int(page):
                    return flask.jsonify(failed_result)
            except:
                self.logger.error("Failed to get all search conditions.",
                                  exc_info=True)
                return flask.jsonify(failed_result)

            self.logger.info("Parsed searching conditions.")

            # Search for the task
            res = select_from_etcd_and_call("search", self.local_etcd,
                                            self.conf["judicator_etcd_path"],
                                            self.logger, id, user, start_time,
                                            end_time, old_to_new, limit, page)

            # Handle the result and return
            tasks = [extract(x, brief=True) for x in res.tasks]
            self.logger.info("Found result: %s." %
                             str([x["id"] for x in tasks]))
            for t in tasks:
                t["add_time"] = "" if not t["add_time"] else t[
                    "add_time"].isoformat()
                t["report_time"] = "" if not t["report_time"] else t[
                    "report_time"].isoformat()

            return flask.jsonify({
                "result": res.result,
                "pages": res.pages,
                "tasks": tasks
            })
예제 #2
0
파일: server.py 프로젝트: sbofgayschool/KV2
        def api_task_cancel():
            """
            Flask Handler: API Interface: Cancel a task
            :return: Json with only result code
            """
            # Get the id, and return directly if no id is specified
            id = flask.request.args.get("id", None)
            if id is None:
                return flask.jsonify({"result": ReturnCode.INVALID_INPUT})

            # Cancel and return the result
            self.logger.info("Canceling task %s." % id)
            res = select_from_etcd_and_call("cancel", self.local_etcd,
                                            self.conf["judicator_etcd_path"],
                                            self.logger, id)
            return flask.jsonify({"result": res})
예제 #3
0
파일: server.py 프로젝트: sbofgayschool/KV2
 def api_executors():
     """
     Flask Handler: API Interface: Fetch executor list
     :return: Json containing executor list
     """
     # Fetch all executors from rpc and return
     self.logger.info("Getting executors.")
     res = select_from_etcd_and_call("executors", self.local_etcd,
                                     self.conf["judicator_etcd_path"],
                                     self.logger)
     return flask.jsonify({
         "result":
         res.result,
         "executors": [{
             "id": x.id,
             "hostname": x.hostname,
             "report_time": x.report_time
         } for x in res.executors]
     })
예제 #4
0
def report(complete, executing, vacant, local_etcd, config, logger):
    """
    Get the address of a judicator and report the tasks status
    :param complete: Complete task list
    :param executing: Executing task list
    :param vacant: Vacant task places
    :param local_etcd: Proxy of local etcd
    :param config: Configuration json
    :param logger: Logger object
    :return: Tuple contain RPC report return
    """
    res = select_from_etcd_and_call("report", local_etcd,
                                    config["judicator_etcd_path"], logger,
                                    config["name"], complete, executing,
                                    vacant)
    if res.result != ReturnCode.OK:
        raise Exception("Return code from judicator is not 0 but %d." %
                        res.result)
    return res.cancel, res.assign
예제 #5
0
파일: server.py 프로젝트: sbofgayschool/KV2
        def api_task_add():
            """
            Flask Handler: API Interface: Add a new task
            :return: Json with result code and id of new task
            """
            # Extract all necessary data
            try:
                data = {
                    "id": None,
                    "user": int(flask.request.form.get("user")),
                    "compile": {
                        "source":
                        b"",
                        "command":
                        zlib.compress(
                            flask.request.form.get("compile_command").replace(
                                "\r\n", "\n").encode("utf-8")),
                        "timeout":
                        int(flask.request.form.get("compile_timeout"))
                    },
                    "execute": {
                        "input":
                        zlib.compress(
                            flask.request.form.get("execute_input").replace(
                                "\r\n", "\n").encode("utf-8")),
                        "data":
                        b"",
                        "command":
                        zlib.compress(
                            flask.request.form.get("execute_command").replace(
                                "\r\n", "\n").encode("utf-8")),
                        "timeout":
                        int(flask.request.form.get("execute_timeout")),
                        "standard":
                        zlib.compress(
                            flask.request.form.get("execute_standard").replace(
                                "\r\n", "\n").encode("utf-8"))
                    },
                    "add_time": None,
                    "done": False,
                    "status": 0,
                    "executor": None,
                    "report_time": None,
                    "result": None
                }
                if not (check_int(data["user"])
                        and check_int(data["compile"]["timeout"])
                        and check_int(data["execute"]["timeout"])):
                    raise Exception("An int parameter is out of bound.")
            except:
                self.logger.error("Failed to parse added task.", exc_info=True)
                return flask.jsonify({
                    "result": ReturnCode.INVALID_INPUT,
                    "id": None
                })

            self.logger.info("Generating all extra fields for added task.")
            # Deal with compile source
            compile_source = flask.request.files.get("compile_source")
            compile_source_name = flask.request.form.get("compile_source_name")
            compile_source_str = flask.request.form.get("compile_source_str")
            # If the zip file has been uploaded, use it
            # Else if some text is given, zipped it and use it
            if compile_source:
                self.logger.info("Detected compile source.")
                data["compile"]["source"] = compile_source.stream.read()
            elif compile_source_str and compile_source_name:
                self.logger.info("Detected compile source text.")
                # Create a temp dir
                temp_dir = tempfile.TemporaryDirectory(
                    dir=self.conf["data_dir"])
                # Write the text in the file with specified name
                file_path = join(temp_dir.name, compile_source_name)
                with open(file_path, "w") as f:
                    f.write(compile_source_str.replace("\r\n", "\n"))
                # Create the zip file
                zip_path = join(temp_dir.name, "source.zip")
                with zipfile.ZipFile(zip_path, "w") as f:
                    f.write(file_path, compile_source_name)
                # Read the binary
                with open(zip_path, "rb") as f:
                    data["compile"]["source"] = f.read()

            # Deal with execute data
            execute_data = flask.request.files.get("execute_data")
            execute_data_name = flask.request.form.get("execute_data_name")
            execute_data_str = flask.request.form.get("execute_data_str")
            # If the zip file has been uploaded, use it
            # Else if some text is given, zipped it and use it
            if execute_data:
                self.logger.info("Detected execute data.")
                data["execute"]["data"] = execute_data.stream.read()
            elif execute_data_str and execute_data_name:
                self.logger.info("Detected execute data text.")
                # Create a temp dir
                temp_dir = tempfile.TemporaryDirectory(
                    dir=self.conf["data_dir"])
                # Write the text in the file with specified name
                file_path = join(temp_dir.name, execute_data_name)
                with open(file_path, "w") as f:
                    f.write(execute_data_str.replace("\r\n", "\n"))
                # Create the zip file
                zip_path = join(temp_dir.name, "data.zip")
                with zipfile.ZipFile(zip_path, "w") as f:
                    f.write(file_path, execute_data_name)
                # Read the binary
                with open(zip_path, "rb") as f:
                    data["execute"]["data"] = f.read()

            self.logger.info("Generated all fields for added task.")

            # Check the size of the data before submit.
            if not check_task_dict_size(data):
                return flask.jsonify({
                    "result": ReturnCode.TOO_LARGE,
                    "id": None
                })

            # Add through rpc and return
            res = select_from_etcd_and_call("add", self.local_etcd,
                                            self.conf["judicator_etcd_path"],
                                            self.logger, generate(data))
            return flask.jsonify({"result": res.result, "id": res.id})
예제 #6
0
파일: server.py 프로젝트: sbofgayschool/KV2
        def api_task_get():
            """
            Flask Handler: API Interface: Get a specified task, or one of its files
            :return: A file if getting a file, or a json containing tasks
            """
            # Get the id and the name of the file, and if the plain text should be truncate
            id = flask.request.args.get("id", None)
            file = flask.request.args.get("file", None)
            truncate = not flask.request.args.get("no_truncate", False)
            # Return directly if no id is specified
            if id is None:
                return flask.jsonify({
                    "result": ReturnCode.INVALID_INPUT,
                    "task": None
                })

            # Get the task
            self.logger.info("Getting task %s." % id)
            res = select_from_etcd_and_call("get", self.local_etcd,
                                            self.conf["judicator_etcd_path"],
                                            self.logger, id)
            # If not found, return
            # Otherwise return required data.
            if res.result != ReturnCode.OK:
                if file:
                    flask.abort(404)
                return flask.jsonify({
                    "result": ReturnCode.NOT_EXIST,
                    "task": None
                })

            task = extract(res.task)

            # If requesting files, try to fetch it
            if file:
                # Compile source and execute_data are in zip format
                # Others are plain text
                if file == "compile_source" or file == "execute_data":
                    postfix = ".zip"
                    mimetype = "application/zip"
                    content = task["compile"][
                        "source"] if file == "compile_source" else task[
                            "execute"]["data"]
                else:
                    postfix = ".txt"
                    mimetype = "plain/text"
                    if file == "compile_command":
                        content = task["compile"]["command"]

                    elif file == "execute_input":
                        content = task["execute"]["input"]
                    elif file == "execute_command":
                        content = task["execute"]["command"]
                    elif file == "execute_standard":
                        content = task["execute"]["standard"]

                    else:
                        content = task.get("result", {}).get(file, b"")
                    if content:
                        content = zlib.decompress(content)
                # If nothing has been found, return 404
                if not content:
                    self.logger.warning(
                        "Returning 404 as %s is empty for task %s." %
                        (file, id))
                    flask.abort(404)
                # Write a temp file and return it
                self.logger.info("Returning %s for task %s." % (file, id))
                temp_file = tempfile.TemporaryFile(dir=self.conf["data_dir"])
                temp_file.write(content)
                temp_file.seek(0)
                return flask.send_file(temp_file,
                                       cache_timeout=-1,
                                       as_attachment=True,
                                       attachment_filename=id + "_" + file +
                                       postfix,
                                       mimetype=mimetype)

            # Deal with zip field
            task["compile"]["source"] = bool(task["compile"]["source"])
            task["execute"]["data"] = bool(task["execute"]["data"])

            self.logger.info(
                "Decompressing all fields compressed by zlib of task %s." % id)
            # Deal with zlib decompressed field in compile section
            task["compile"]["command"] = decompress_and_truncate(
                task["compile"]["command"], truncate)

            # Deal with zlib decompressed field in execute section
            task["execute"]["input"] = decompress_and_truncate(
                task["execute"]["input"], truncate)
            task["execute"]["command"] = decompress_and_truncate(
                task["execute"]["command"], truncate)
            task["execute"]["standard"] = decompress_and_truncate(
                task["execute"]["standard"], truncate)

            # Deal with zlib decompressed field in result section
            if task["result"]:
                task["result"]["compile_output"] = decompress_and_truncate(
                    task["result"]["compile_output"], truncate)
                task["result"]["compile_error"] = decompress_and_truncate(
                    task["result"]["compile_error"], truncate)
                task["result"]["execute_output"] = decompress_and_truncate(
                    task["result"]["execute_output"], truncate)
                task["result"]["execute_error"] = decompress_and_truncate(
                    task["result"]["execute_error"], truncate)

            # Deal with time section
            task["add_time"] = "" if not task["add_time"] else task[
                "add_time"].isoformat()
            task["report_time"] = "" if not task["report_time"] else task[
                "report_time"].isoformat()

            self.logger.info("Returning task %s." % id)

            return flask.jsonify({"result": res.result, "task": task})