package kr.re.etri.autoflow.controllers; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.transaction.Transactional; 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.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.time.Instant; 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 = "RUNS", description = "Kubeflow Runs API") @RestController @RequestMapping("/api/runs") @RequiredArgsConstructor @Slf4j public class KubeflowRunsController { private final WebClient.Builder webClientBuilder; @Value("${kubeflow.url}") private String kubeflowBaseUrl; // 예: http://192.168.10.135:32473/ @Operation(summary = "Kubeflow Run 목록 조회", description = "Kubeflow API를 호출하여 Run 목록을 조회합니다.") @ApiResponses({ @ApiResponse(responseCode = "200", description = "Run 목록 조회 성공"), @ApiResponse(responseCode = "400", description = "잘못된 요청"), @ApiResponse(responseCode = "500", description = "서버 내부 오류") }) @GetMapping("/runs") public Mono> listRuns( @Parameter(description = "페이지 토큰 (다음 페이지 조회 시 사용)", example = "") @RequestParam(value = "page_token", defaultValue = "") String pageToken, @Parameter(description = "페이지 크기", example = "10") @RequestParam(value = "page_size", defaultValue = "10") int pageSize, @Parameter(description = "정렬 기준 (sort_by)", example = "created_at desc") @RequestParam(value = "sort_by", defaultValue = "created_at desc") String sortBy, @Parameter(description = "필터 JSON 문자열 (URL 인코딩 필요)", example = "{\"predicates\":[{\"key\":\"storage_state\",\"operation\":\"NOT_EQUALS\",\"string_value\":\"ARCHIVED\"}]}") @RequestParam(value = "filter", required = false) String filter ) { try { // filter가 없으면 기본값 적용 if (filter == null || filter.isBlank()) { filter = "{\"predicates\":[{\"key\":\"storage_state\",\"operation\":\"NOT_EQUALS\",\"string_value\":\"ARCHIVED\"}]}"; } String encodedFilter = URLEncoder.encode(filter, StandardCharsets.UTF_8); String uri = String.format( "%s/apis/v2beta1/runs?page_token=%s&page_size=%d&sort_by=%s&filter=%s", kubeflowBaseUrl, pageToken, pageSize, URLEncoder.encode(sortBy, StandardCharsets.UTF_8), encodedFilter ); return webClientBuilder.build() .get() .uri(uri) .accept(MediaType.APPLICATION_JSON) .retrieve() .bodyToMono(Map.class) .map(ResponseEntity::ok) .doOnError(e -> log.error("Kubeflow Runs 조회 실패", e)); } catch (Exception e) { log.error("URI 생성 실패", e); return Mono.just(ResponseEntity.status(500).body(Map.of( "status", 500, "error", "Internal Server Error", "message", e.getMessage() ))); } } }