|
|
|
|
@ -7,21 +7,39 @@ import kr.re.etri.autoflow.entity.ExperimentsEntity;
|
|
|
|
|
import kr.re.etri.autoflow.payload.request.ProjectBaseSearchRequest;
|
|
|
|
|
import kr.re.etri.autoflow.service.ExperimentsService;
|
|
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
import org.springdoc.core.annotations.ParameterObject;
|
|
|
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
|
|
|
import org.springframework.data.domain.Page;
|
|
|
|
|
import org.springframework.http.MediaType;
|
|
|
|
|
import org.springframework.http.ResponseEntity;
|
|
|
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
|
|
import org.springframework.web.reactive.function.client.WebClient;
|
|
|
|
|
import reactor.core.publisher.Mono;
|
|
|
|
|
|
|
|
|
|
import java.time.OffsetDateTime;
|
|
|
|
|
import java.time.ZoneId;
|
|
|
|
|
import java.time.ZoneOffset;
|
|
|
|
|
import java.time.format.DateTimeFormatter;
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
|
|
|
|
|
@Tag(name = "Experiments", description = "Kubeflow 및 MLflow Experiment API")
|
|
|
|
|
@RestController
|
|
|
|
|
@RequestMapping("/api/experiments")
|
|
|
|
|
@RequiredArgsConstructor
|
|
|
|
|
@Slf4j
|
|
|
|
|
public class ExperimentsController {
|
|
|
|
|
|
|
|
|
|
private final ExperimentsService experimentsService;
|
|
|
|
|
|
|
|
|
|
private final WebClient.Builder webClientBuilder;
|
|
|
|
|
|
|
|
|
|
@Value("${kubeflow.url}")
|
|
|
|
|
private String kubeflowBaseUrl; // 예: http://192.168.10.135:32473/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Operation(summary = "모든 Experiments 조회")
|
|
|
|
|
@GetMapping
|
|
|
|
|
public ResponseEntity<List<ExperimentsEntity>> getAllExperiments() {
|
|
|
|
|
@ -48,9 +66,42 @@ public class ExperimentsController {
|
|
|
|
|
|
|
|
|
|
@Operation(summary = "Experiment 등록")
|
|
|
|
|
@PostMapping
|
|
|
|
|
public ResponseEntity<ExperimentsEntity> createExperiment(@RequestBody ExperimentsEntity experiment) {
|
|
|
|
|
return ResponseEntity.ok(experimentsService.save(experiment));
|
|
|
|
|
public Mono<ResponseEntity<ExperimentsEntity>> createExperiment(@RequestBody ExperimentsEntity experiment) {
|
|
|
|
|
|
|
|
|
|
// 1️⃣ DB 저장
|
|
|
|
|
ExperimentsEntity saved = experimentsService.save(experiment);
|
|
|
|
|
|
|
|
|
|
// 2️⃣ Kubeflow POST 요청 payload
|
|
|
|
|
Map<String, Object> payload = new HashMap<>();
|
|
|
|
|
payload.put("display_name", saved.getDisplayName());
|
|
|
|
|
payload.put("description", saved.getDescription());
|
|
|
|
|
payload.put("namespace", "default"); // 필요에 따라 변경
|
|
|
|
|
|
|
|
|
|
// 3️⃣ WebClient POST
|
|
|
|
|
return webClientBuilder.build()
|
|
|
|
|
.post()
|
|
|
|
|
.uri(kubeflowBaseUrl + "/apis/v2beta1/experiments")
|
|
|
|
|
.contentType(MediaType.APPLICATION_JSON)
|
|
|
|
|
.bodyValue(payload)
|
|
|
|
|
.retrieve()
|
|
|
|
|
.bodyToMono(Map.class) // Kubeflow 응답
|
|
|
|
|
.map(resp -> {
|
|
|
|
|
// resp에서 필요한 값 추출 후 entity에 반영
|
|
|
|
|
if (resp.get("last_run_created_at") != null) {
|
|
|
|
|
String lastRunStr = resp.get("last_run_created_at").toString();
|
|
|
|
|
OffsetDateTime odt = OffsetDateTime.parse(lastRunStr);
|
|
|
|
|
saved.setLastRunCreatedAt(odt.withOffsetSameInstant(ZoneId.of("Asia/Seoul").getRules().getOffset(odt.toInstant()))
|
|
|
|
|
.toLocalDateTime());
|
|
|
|
|
}
|
|
|
|
|
if(resp.get("id") != null) {
|
|
|
|
|
saved.setKubeFlowId(resp.get("id").toString());
|
|
|
|
|
}
|
|
|
|
|
return saved;
|
|
|
|
|
})
|
|
|
|
|
.map(entity -> ResponseEntity.ok(entity))
|
|
|
|
|
.doOnError(e -> log.error("Kubeflow experiment 등록 실패", e));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Operation(summary = "Experiment 수정")
|
|
|
|
|
@PutMapping("/{id}")
|
|
|
|
|
|