From 90141f1925ed15d150f8cef3ac15bc098dc372ef Mon Sep 17 00:00:00 2001 From: bjkim Date: Tue, 23 Sep 2025 18:12:44 +0900 Subject: [PATCH] =?UTF-8?q?[UPDATE]=20Experiments=20API=EC=97=90=20Kubeflo?= =?UTF-8?q?w=20=EB=B0=8F=20MLflow=20=EC=97=B0=EB=8F=99=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=B6=94=EA=B0=80,=20=EC=97=94=ED=8B=B0=ED=8B=B0?= =?UTF-8?q?=20=ED=95=84=EB=93=9C=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20?= =?UTF-8?q?=EB=B0=8F=20=EC=9D=91=EB=8B=B5=20=EC=B2=98=EB=A6=AC=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0=20(ExperimentsController)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controllers/ExperimentsController.java | 75 +++++++++++++------ 1 file changed, 51 insertions(+), 24 deletions(-) diff --git a/src/main/java/kr/re/etri/autoflow/controllers/ExperimentsController.java b/src/main/java/kr/re/etri/autoflow/controllers/ExperimentsController.java index 3f02c53..7654091 100644 --- a/src/main/java/kr/re/etri/autoflow/controllers/ExperimentsController.java +++ b/src/main/java/kr/re/etri/autoflow/controllers/ExperimentsController.java @@ -40,6 +40,15 @@ public class ExperimentsController { @Value("${kubeflow.url}") private String kubeflowBaseUrl; // 예: http://192.168.10.135:32473/ + @Value("${mlflow.url}") + private String mlflowBaseUrl; // 예: http://192.168.10.135:32473/ + + + @Value("${mlflow.user}") + private String mlflowUser; // 예: http://192.168.10.135:32473/ + + @Value("${mlflow.password}") + private String mlflowPassword; // 예: http://192.168.10.135:32473/ @Operation(summary = "모든 Experiments 조회") @GetMapping @@ -115,60 +124,78 @@ public class ExperimentsController { // .doOnError(e -> log.error("Kubeflow experiment 등록 실패", e)); // } - @Operation(summary = "Experiment 등록") + @Operation(summary = "Experiment 등록 (Kubeflow + MLflow)") @PostMapping public Mono> createExperiment(@RequestBody ExperimentsEntity experiment) { + // 1️⃣ DB 저장 ExperimentsEntity saved = experimentsService.save(experiment); - Map payload = new HashMap<>(); - payload.put("display_name", saved.getDisplayName()); - payload.put("description", saved.getDescription()); - payload.put("namespace", "default"); // 필요에 따라 변경 + // 2️⃣ Kubeflow payload + Map kubeflowPayload = new HashMap<>(); + kubeflowPayload.put("display_name", saved.getDisplayName()); + kubeflowPayload.put("description", saved.getDescription()); + kubeflowPayload.put("namespace", "default"); return webClientBuilder.build() + // Kubeflow 등록 .post() .uri(kubeflowBaseUrl + "/apis/v2beta1/experiments") .contentType(MediaType.APPLICATION_JSON) - .bodyValue(payload) + .bodyValue(kubeflowPayload) .retrieve() - .bodyToMono(Map.class) // Kubeflow 응답 받기 - .flatMap(resp -> { - // Kubeflow 응답에서 값 꺼내기 - if (resp.containsKey("experiment_id")) { - saved.setKubeFlowId((String) resp.get("experiment_id")); + .bodyToMono(Map.class) + .flatMap(kubeflowResp -> { + // Kubeflow 응답 처리 + if (kubeflowResp.containsKey("experiment_id")) { + saved.setKubeFlowId((String) kubeflowResp.get("experiment_id")); } - - if (resp.containsKey("created_at")) { + if (kubeflowResp.containsKey("created_at")) { saved.setKubeflowCreatedAt( - Instant.parse((String) resp.get("created_at")) + Instant.parse((String) kubeflowResp.get("created_at")) .atZone(ZoneId.of("Asia/Seoul")) .toLocalDateTime() ); } - - if (resp.containsKey("last_run_created_at")) { + if (kubeflowResp.containsKey("last_run_created_at")) { saved.setKubeflowLastRunCreatedAt( - Instant.parse((String) resp.get("last_run_created_at")) + Instant.parse((String) kubeflowResp.get("last_run_created_at")) .atZone(ZoneId.of("Asia/Seoul")) .toLocalDateTime() ); } - - if (resp.containsKey("storage_state")) { - saved.setKubeflowStorageState((String) resp.get("storage_state")); + if (kubeflowResp.containsKey("storage_state")) { + saved.setKubeflowStorageState((String) kubeflowResp.get("storage_state")); } // DB 업데이트 experimentsService.save(saved); - - log.info("Kubeflow experiment 등록 완료: {}", resp); - return Mono.just(ResponseEntity.ok(saved)); + log.info("Kubeflow experiment 등록 완료: {}", kubeflowResp); + + // 3️⃣ MLflow 등록 + Map mlflowPayload = new HashMap<>(); + mlflowPayload.put("name", saved.getDisplayName()); + mlflowPayload.put("artifact_location", "/default/artifacts"); // 필요 시 변경 + // mlflowPayload.put("tags", ...); // 태그 필요 시 설정 + + return webClientBuilder.build() + .post() + .uri(mlflowBaseUrl + "/ajax-api/2.0/mlflow/experiments/create") + .headers(headers -> headers.setBasicAuth(mlflowUser, mlflowPassword)) + .contentType(MediaType.APPLICATION_JSON) + .bodyValue(mlflowPayload) + .retrieve() + .bodyToMono(Map.class) + .flatMap(mlflowResp -> { + log.info("MLflow experiment 등록 완료: {}", mlflowResp); + return Mono.just(ResponseEntity.ok(saved)); + }); }) - .doOnError(e -> log.error("Kubeflow experiment 등록 실패", e)); + .doOnError(e -> log.error("Experiment 등록 실패", e)); } + @Operation(summary = "Experiment 수정") @PutMapping("/{id}") public ResponseEntity updateExperiment(