示例#1
0
    def catch_api_proxy_jobs_post():

        try:
            job_spec = jobs.create_job_spec(request.json)
        except error.EnvironmentsDoNotExist as e:
            return (
                jsonify({
                    "message":
                    environments_missing_msg.format(missing_environment_uuids=[
                        ",".join(e.environment_uuids)
                    ]),
                }),
                500,
            )

        resp = requests.post(
            "http://" + current_app.config["ORCHEST_API_ADDRESS"] +
            "/api/jobs/",
            json=job_spec,
        )

        analytics.send_event(
            app,
            analytics.Event.JOB_CREATE,
            {
                "job_definition":
                job_spec,
                "snapshot_size":
                get_project_snapshot_size(job_spec["project_uuid"]),
            },
        )
        return resp.content, resp.status_code, resp.headers.items()
示例#2
0
    def catch_api_proxy_runs_single(run_uuid):

        if request.method == "GET":

            resp = requests.get(
                "http://" + app.config["ORCHEST_API_ADDRESS"] +
                "/api/runs/%s" % run_uuid, )

            return resp.content, resp.status_code, resp.headers.items()

        elif request.method == "DELETE":

            resp = requests.delete(
                "http://" + app.config["ORCHEST_API_ADDRESS"] +
                "/api/runs/%s" % run_uuid, )

            analytics.send_event(
                app,
                analytics.Event.PIPELINE_RUN_CANCEL,
                {
                    "run_uuid": run_uuid,
                    "run_type": "interactive"
                },
            )
            return resp.content, resp.status_code, resp.headers.items()
示例#3
0
    def catch_api_proxy_environment_image_builds():

        environment_image_build_requests = request.json[
            "environment_image_build_requests"]

        for environment_image_build_request in environment_image_build_requests:
            environment_image_build_request[
                "project_path"] = project_uuid_to_path(
                    environment_image_build_request["project_uuid"])

        resp = api_proxy_environment_image_builds(
            environment_image_build_requests,
            app.config["ORCHEST_API_ADDRESS"])

        for environment_image_build_request in environment_image_build_requests:
            environment_uuid = environment_image_build_request[
                "environment_uuid"]
            project_uuid = environment_image_build_request["project_uuid"]
            env = get_environment(environment_uuid, project_uuid)
            analytics.send_event(
                app,
                analytics.Event.ENVIRONMENT_BUILD_START,
                {
                    "environment_uuid": environment_uuid,
                    "project_uuid": project_uuid,
                    "language": env.language,
                    "gpu_support": env.gpu_support,
                    "base_image": env.base_image,
                },
            )
        return resp.content, resp.status_code, resp.headers.items()
示例#4
0
    def catch_api_proxy_sessions_post():

        json_obj = request.json

        json_obj["project_dir"] = get_project_directory(
            json_obj["project_uuid"], host_path=True)

        json_obj["pipeline_path"] = pipeline_uuid_to_path(
            json_obj["pipeline_uuid"],
            json_obj["project_uuid"],
        )

        json_obj["host_userdir"] = app.config["HOST_USER_DIR"]

        resp = requests.post(
            "http://" + app.config["ORCHEST_API_ADDRESS"] + "/api/sessions/",
            json=json_obj,
        )

        tel_props = {
            "project_uuid": json_obj["project_uuid"],
            "pipeline_uuid": json_obj["pipeline_uuid"],
        }
        analytics.send_event(app, "session start", tel_props)
        return resp.content, resp.status_code, resp.headers.items()
示例#5
0
    def catch_api_proxy_job_cronjobs_resume(job_uuid):

        resp = requests.post(
            "http://" + app.config["ORCHEST_API_ADDRESS"] +
            "/api/jobs/cronjobs/resume/%s" % (job_uuid), )

        analytics.send_event(app, analytics.Event.CRONJOB_RESUME,
                             {"job_uuid": job_uuid})
        return resp.content, resp.status_code, resp.headers.items()
示例#6
0
    def catch_api_proxy_job_delete(job_uuid):

        resp = requests.delete(
            "http://" + app.config["ORCHEST_API_ADDRESS"] + "/api/jobs/%s" %
            (job_uuid), )

        analytics.send_event(app, analytics.Event.JOB_CANCEL,
                             {"job_uuid": job_uuid})
        return resp.content, resp.status_code, resp.headers.items()
示例#7
0
    def catch_api_proxy_jobs_duplicate():

        json_obj = request.json
        try:
            job_spec = jobs.duplicate_job_spec(json_obj["job_uuid"])
        except error.ProjectDoesNotExist:
            msg = ("The job cannot be duplicated because its project does "
                   "not exist anymore.")
            return (
                jsonify({"message": msg}),
                409,
            )
        except error.PipelineDoesNotExist:
            msg = ("The job cannot be duplicated because its pipeline does "
                   "not exist anymore.")
            return (
                jsonify({"message": msg}),
                409,
            )
        except error.JobDoesNotExist:
            msg = "The job cannot be duplicated because it does not exist anymore."
            return (
                jsonify({"message": msg}),
                409,
            )
        except error.EnvironmentsDoNotExist as e:
            return (
                jsonify({
                    "message":
                    environments_missing_msg.format(missing_environment_uuids=[
                        ",".join(e.environment_uuids)
                    ]),
                }),
                500,
            )

        resp = requests.post(
            "http://" + current_app.config["ORCHEST_API_ADDRESS"] +
            "/api/jobs/",
            json=job_spec,
        )

        analytics.send_event(
            app,
            analytics.Event.JOB_DUPLICATE,
            {
                "job_definition":
                job_spec,
                "duplicate_from":
                json_obj["job_uuid"],
                "snapshot_size":
                get_project_snapshot_size(job_spec["project_uuid"]),
            },
        )
        return resp.content, resp.status_code, resp.headers.items()
示例#8
0
    def catch_api_proxy_session_put(project_uuid, pipeline_uuid):

        # check whether session is running
        try:
            resp = requests.get("http://" + app.config["ORCHEST_API_ADDRESS"] +
                                "/api/runs/?project_uuid=%s&pipeline_uuid=%s" %
                                (project_uuid, pipeline_uuid))

            runs = resp.json()["runs"]

            active_runs = False
            for run in runs:
                if run["status"] in ["PENDING", "STARTED"]:
                    active_runs = True

            if active_runs:
                analytics.send_event(
                    app,
                    analytics.Event.SESSION_RESTART,
                    {
                        "project_uuid": project_uuid,
                        "pipeline_uuid": pipeline_uuid,
                        "active_runs": True,
                    },
                )

                return (
                    jsonify({
                        "message": ("Cannot restart the memory "
                                    "server while the pipeline is running.")
                    }),
                    423,
                )
            else:
                resp = requests.put(
                    "http://" + app.config["ORCHEST_API_ADDRESS"] +
                    "/api/sessions/%s/%s" % (project_uuid, pipeline_uuid), )

                analytics.send_event(
                    app,
                    analytics.Event.SESSION_RESTART,
                    {
                        "project_uuid": project_uuid,
                        "pipeline_uuid": pipeline_uuid,
                        "active_runs": False,
                    },
                )
                return resp.content, resp.status_code, resp.headers.items()
        except Exception as e:
            app.logger.error(
                "Could not get session information from orchest-api. Error: %s (%s)"
                % (e, type(e)))

        return "", 500
示例#9
0
    def catch_api_proxy_sessions_delete(project_uuid, pipeline_uuid):

        resp = requests.delete(
            "http://" + app.config["ORCHEST_API_ADDRESS"] +
            "/api/sessions/%s/%s" % (project_uuid, pipeline_uuid), )

        tel_props = {
            "project_uuid": project_uuid,
            "pipeline_uuid": pipeline_uuid,
        }
        analytics.send_event(app, "session stop", tel_props)
        return resp.content, resp.status_code, resp.headers.items()
示例#10
0
    def catch_api_proxy_sessions_post():

        json_obj = request.json

        project_uuid = json_obj["project_uuid"]
        pipeline_uuid = json_obj["pipeline_uuid"]

        # Lock the project and pipeline row to avoid race conditions
        # with RenameProject and MovePipeline, which are locking for
        # update themselves.
        Project.query.with_for_update().filter(
            Project.uuid == project_uuid, ).one()
        Pipeline.query.with_for_update().filter(
            Pipeline.project_uuid == project_uuid,
            Pipeline.uuid == pipeline_uuid,
        ).one()

        pipeline_path = pipeline_uuid_to_path(
            json_obj["pipeline_uuid"],
            json_obj["project_uuid"],
        )

        project_dir = get_project_directory(json_obj["project_uuid"])

        services = get_pipeline_json(json_obj["pipeline_uuid"],
                                     json_obj["project_uuid"]).get(
                                         "services", {})

        session_config = {
            "project_uuid": project_uuid,
            "pipeline_uuid": pipeline_uuid,
            "pipeline_path": pipeline_path,
            "project_dir": project_dir,
            "userdir_pvc": app.config["USERDIR_PVC"],
            "services": services,
        }

        resp = requests.post(
            "http://" + app.config["ORCHEST_API_ADDRESS"] + "/api/sessions/",
            json=session_config,
        )

        analytics.send_event(
            app,
            analytics.Event.SESSION_START,
            {
                "project_uuid": project_uuid,
                "pipeline_uuid": pipeline_uuid,
                "services": services,
            },
        )
        return resp.content, resp.status_code, resp.headers.items()
示例#11
0
 def catch_api_proxy_job_pipeline_run_cleanup(job_uuid, run_uuid):
     resp = requests.delete(
         f"http://{current_app.config['ORCHEST_API_ADDRESS']}/api/"
         f"jobs/cleanup/{job_uuid}/{run_uuid}")
     analytics.send_event(
         app,
         analytics.Event.JOB_PIPELINE_RUN_DELETE,
         {
             "job_uuid": job_uuid,
             "run_uuid": run_uuid
         },
     )
     return resp.content, resp.status_code, resp.headers.items()
示例#12
0
    def catch_api_proxy_runs():

        if request.method == "POST":

            json_obj = request.json

            # add image mapping
            # TODO: replace with dynamic mapping instead of hardcoded
            # All the paths are container path
            json_obj["run_config"] = {
                "userdir_pvc":
                app.config["USERDIR_PVC"],
                "project_dir":
                get_project_directory(json_obj["project_uuid"]),
                "pipeline_path":
                pipeline_uuid_to_path(json_obj["pipeline_definition"]["uuid"],
                                      json_obj["project_uuid"]),
                "pipeline_uuid":
                json_obj["pipeline_definition"]["uuid"],
                "project_uuid":
                json_obj["project_uuid"],
            }

            resp = requests.post(
                "http://" + app.config["ORCHEST_API_ADDRESS"] + "/api/runs/",
                json=json_obj,
            )

            analytics.send_event(
                app,
                analytics.Event.PIPELINE_RUN_START,
                {
                    "run_uuid": resp.json().get("uuid"),
                    "run_type": "interactive",
                    "pipeline_definition": json_obj["pipeline_definition"],
                    "step_uuids_to_execute": json_obj["uuids"],
                },
            )

            return resp.content, resp.status_code, resp.headers.items()

        elif request.method == "GET":

            resp = requests.get(
                "http://" + app.config["ORCHEST_API_ADDRESS"] + "/api/runs/" +
                request_args_to_string(request.args), )

            return resp.content, resp.status_code, resp.headers.items()
示例#13
0
    def catch_api_proxy_job_put(job_uuid):

        resp = requests.put(
            "http://" + app.config["ORCHEST_API_ADDRESS"] + "/api/jobs/%s" %
            (job_uuid),
            json=request.json,
        )

        analytics.send_event(
            app,
            analytics.Event.JOB_UPDATE,
            {
                "job_uuid": job_uuid,
                "job_definition": request.json
            },
        )
        return resp.content, resp.status_code, resp.headers.items()
示例#14
0
    def catch_api_proxy_environment_image_build_delete(
        project_uuid,
        environment_uuid,
        image_tag,
    ):

        resp = requests.delete(
            "http://" + app.config["ORCHEST_API_ADDRESS"] +
            "/api/environment-builds/%s/%s/%s" %
            (project_uuid, environment_uuid, image_tag), )

        analytics.send_event(
            app,
            analytics.Event.ENVIRONMENT_BUILD_CANCEL,
            {
                "project_uuid": project_uuid,
                "environment_uuid": environment_uuid,
                "image_tag": image_tag,
            },
        )
        return resp.content, resp.status_code, resp.headers.items()
示例#15
0
    def catch_api_proxy_jobs_cleanup(job_uuid):
        try:
            # Get data before issuing deletion to the orchest-api. This
            # is needed to retrieve the job pipeline uuid and project
            # uuid. TODO: if the caller of the job knows about those
            # ids, we could avoid making a request to the orchest-api.
            resp = requests.get(
                (f'http://{current_app.config["ORCHEST_API_ADDRESS"]}/api'
                 f"/jobs/{job_uuid}"))
            data = resp.json()

            if resp.status_code == 200:
                pipeline_uuid = data["pipeline_uuid"]
                project_uuid = data["project_uuid"]

                # Tell the orchest-api that the job does not exist
                # anymore, will be stopped if necessary then cleaned up
                # from the orchest-api db.
                resp = requests.delete(
                    f"http://{current_app.config['ORCHEST_API_ADDRESS']}/api/"
                    f"jobs/cleanup/{job_uuid}")

                remove_job_directory(job_uuid, pipeline_uuid, project_uuid)
                analytics.send_event(
                    app,
                    analytics.Event.JOB_DELETE,
                    {"job_uuid": job_uuid},
                )
                return resp.content, resp.status_code, resp.headers.items()

            elif resp.status_code == 404:
                raise ValueError(f"Job {job_uuid} does not exist.")
            else:
                raise Exception(f"{data}, {resp.status_code}")

        except Exception as e:
            msg = f"Error during job deletion:{e}"
            return {"message": msg}, 500
示例#16
0
    def analytics_send_event():
        event_name = request.json["event"]
        try:
            analytics_event = analytics.Event(event_name)
        except ValueError:
            app.logger.error(
                f"No analytics event is defined for the given name: '{event_name}'."
            )
            return "Invalid analytics event name.", 500

        success = analytics.send_event(app, analytics_event,
                                       request.json["properties"])

        if success:
            return ""
        else:
            return "", 500
示例#17
0
 def catch_api_proxy_jupyter_builds_delete(build_uuid):
     resp = requests.delete(
         "http://" + app.config["ORCHEST_API_ADDRESS"] +
         "/api/jupyter-builds/%s" % build_uuid, )
     analytics.send_event(app, "jupyter-build cancel", {})
     return resp.content, resp.status_code, resp.headers.items()
示例#18
0
 def catch_api_proxy_jupyter_builds_post():
     resp = requests.post(
         "http://" + app.config["ORCHEST_API_ADDRESS"] +
         "/api/jupyter-builds/", )
     analytics.send_event(app, "jupyter-build start", {})
     return resp.content, resp.status_code, resp.headers.items()
示例#19
0
 def analytics_send_event():
     if send_event(app, request.json["event"], request.json["properties"]):
         return ""
     else:
         return "", 500
示例#20
0
文件: views.py 项目: orchest/orchest
    def pipelines_json(project_uuid, pipeline_uuid):

        if request.method == "POST":

            pipeline_json_path = get_pipeline_path(
                pipeline_uuid,
                project_uuid,
                None,
                request.args.get("pipeline_run_uuid"),
            )

            pipeline_directory = get_pipeline_directory(
                pipeline_uuid,
                project_uuid,
                None,
                request.args.get("pipeline_run_uuid"),
            )

            # Parse JSON.
            pipeline_json = json.loads(request.form.get("pipeline_json"))

            # Normalize relative paths.
            for step in pipeline_json["steps"].values():

                is_project_file = is_valid_pipeline_relative_path(
                    project_uuid, pipeline_uuid, step["file_path"])

                is_data_file = is_valid_data_path(step["file_path"])

                if not (is_project_file or is_data_file):
                    raise app_error.OutOfAllowedDirectoryError(
                        "File is neither in the project, nor in the data directory."
                    )

                if not step["file_path"].startswith("/"):
                    step["file_path"] = normalize_project_relative_path(
                        step["file_path"])

            errors = check_pipeline_correctness(pipeline_json)
            if errors:
                msg = {}
                msg = {"success": False}
                reason = ", ".join([key for key in errors])
                reason = f"Invalid value: {reason}."
                msg["reason"] = reason
                return jsonify(msg), 400

            # Side effect: for each Notebook in de pipeline.json set the
            # correct kernel.
            try:
                pipeline_set_notebook_kernels(pipeline_json,
                                              pipeline_directory, project_uuid)
            except KeyError:
                msg = {
                    "success": False,
                    "reason": "Invalid Notebook metadata structure.",
                }
                return jsonify(msg), 400

            with open(pipeline_json_path, "r") as json_file:
                old_pipeline_json = json.load(json_file)

            # Save the pipeline JSON again to make sure its keys are
            # sorted.
            with open(pipeline_json_path, "w") as json_file:
                json.dump(pipeline_json, json_file, indent=4, sort_keys=True)

            if old_pipeline_json["name"] != pipeline_json["name"]:
                resp = requests.put(
                    (f'http://{current_app.config["ORCHEST_API_ADDRESS"]}'
                     f"/api/pipelines/{project_uuid}/{pipeline_uuid}"),
                    json={"name": pipeline_json["name"]},
                )
                if resp.status_code != 200:
                    return (
                        jsonify(
                            {"message": "Failed to PUT name to orchest-api."}),
                        resp.status_code,
                    )

            # Analytics call.
            analytics.send_event(
                app,
                analytics.Event.PIPELINE_SAVE,
                {"pipeline_definition": pipeline_json},
            )
            return jsonify({
                "success": True,
                "message": "Successfully saved pipeline."
            })

        elif request.method == "GET":
            pipeline_json_path = get_pipeline_path(
                pipeline_uuid,
                project_uuid,
                request.args.get("job_uuid"),
                request.args.get("pipeline_run_uuid"),
            )

            if not os.path.isfile(pipeline_json_path):
                return (
                    jsonify({
                        "success":
                        False,
                        "reason":
                        ".orchest file doesn't exist at location " +
                        pipeline_json_path,
                    }),
                    404,
                )
            else:
                pipeline_json = get_pipeline_json(pipeline_uuid, project_uuid)

                return jsonify({
                    "success": True,
                    "pipeline_json": json.dumps(pipeline_json)
                })