[UPDATE] Kubeflow 파이프라인 업로드 API 설명 및 요약 수정 (PipelineUploadController)

main
bjkim 9 months ago
parent ade9bf6189
commit a2b0906343

@ -0,0 +1,104 @@
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.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import kr.re.etri.autoflow.service.PipelineUploadService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@Slf4j
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
@CrossOrigin(origins = "*")
@io.swagger.v3.oas.annotations.tags.Tag(name = "Kubeflow Pipeline", description = "Kubeflow 파이프라인 API")
public class KubeflowExperimentsController {
private final PipelineUploadService pipelineUploadService;
@Operation(
summary = "실험 목록 조회",
description = "Kubeflow에 등록된 Experiment 리스트를 조회합니다."
)
@ApiResponses({
@ApiResponse(responseCode = "200", description = "실험 목록 조회 성공"),
@ApiResponse(responseCode = "500", description = "서버 내부 오류", content = @Content)
})
@GetMapping("/experiments")
public ResponseEntity<Map<String, Object>> listExperiments(
@Parameter(description = "조회할 namespace (생략 시 기본값)")
@RequestParam(value = "namespace", required = false) String namespace,
@Parameter(description = "페이지 크기 (기본값: 10)")
@RequestParam(value = "pageSize", required = false, defaultValue = "10") int pageSize,
@Parameter(description = "다음 페이지 토큰")
@RequestParam(value = "pageToken", required = false) String pageToken
) {
try {
Map<String, Object> result = pipelineUploadService.listExperiments(namespace, pageSize, pageToken);
return ResponseEntity.ok(result);
} catch (Exception e) {
log.error("List experiments failed", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(Map.of(
"status", 500,
"error", "Internal Server Error",
"message", e.getMessage()
));
}
}
@Operation(
summary = "실험 단건 조회",
description = "experiment_id로 Kubeflow Experiment 상세 정보를 조회합니다."
)
@ApiResponses({
@ApiResponse(responseCode = "200", description = "실험 조회 성공"),
@ApiResponse(responseCode = "404", description = "실험을 찾을 수 없음"),
@ApiResponse(responseCode = "500", description = "서버 내부 오류")
})
@GetMapping("/experiments/{experimentId}")
public ResponseEntity<?> getExperimentById(
@Parameter(description = "조회할 Experiment ID") @PathVariable String experimentId
) {
try {
Map<String, Object> result = pipelineUploadService.getExperimentById(experimentId);
if (result == null || result.isEmpty()) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(Map.of(
"status", 404,
"error", "Not Found",
"message", "Experiment not found"
));
}
return ResponseEntity.ok(result);
} catch (IllegalArgumentException e) {
log.warn("잘못된 요청: experimentId={}", experimentId, e);
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(Map.of(
"status", 400,
"error", "Bad Request",
"message", "Invalid experiment ID format"
));
} catch (Exception e) {
log.error("Experiment 조회 실패: experimentId={}", experimentId, e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(Map.of(
"status", 500,
"error", "Internal Server Error",
"message", "An unexpected error occurred while retrieving experiment"
));
}
}
}

@ -3,6 +3,7 @@ package kr.re.etri.autoflow.controllers;
import io.minio.MinioClient; import io.minio.MinioClient;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.responses.ApiResponses;
import kr.re.etri.autoflow.entity.MinioAttachmentEntity; import kr.re.etri.autoflow.entity.MinioAttachmentEntity;
@ -35,53 +36,6 @@ public class PipelineUploadController {
private final MinioAttachmentService minioAttachmentService; private final MinioAttachmentService minioAttachmentService;
// @Operation(summary = "파이프라인 업로드", description = "Kubeflow에 파이프라인 파일(Multipart)을 업로드")
// @ApiResponses({
// @ApiResponse(responseCode = "200", description = "파이프라인 업로드 성공"),
// @ApiResponse(responseCode = "400", description = "잘못된 요청"),
// @ApiResponse(responseCode = "500", description = "서버 내부 오류")
// })
// @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
// public ResponseEntity<Map<String, Object>> uploadPipe(
// @RequestParam("uploadfile") MultipartFile file,
// @RequestParam("name") String name,
// @RequestParam("display_name") String displayName,
// @RequestParam(value = "description", required = false) String description,
// @RequestParam(value = "namespace", required = false) String namespace,
// @RequestParam("regUserId") String regUserId,
// @RequestParam("projectId") Long projectId
// ) {
// try {
// Map<String, Object> result = pipelineUploadService.uploadPipeline(file, name, displayName, description, namespace);
//
// WorkflowEntity workflow = WorkflowEntity.builder()
// .pipelineId((String) result.get("pipeline_id"))
// .displayName((String) result.get("display_name"))
// .name((String) result.get("name"))
// .description((String) result.get("description"))
// .namespace((String) result.get("namespace"))
// .regUserId(regUserId)
// .projectId(projectId)
// .kubeflowStatus("Created")
// .version(1)
// .build();
//
// workFlowService.save(workflow);
//
// return ResponseEntity.ok(result);
//
// } catch (Exception e) {
// log.error("Pipeline upload failed", e);
// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
// .body(Map.of(
// "status", 500,
// "error", "Internal Server Error",
// "message", e.getMessage()
// ));
// }
// }
@Operation(summary = "파이프라인 생성 및 MinIO업로드", description = "Kubeflow에 파이프라인 파일(Multipart)을 업로드하고 MinIO에 저장") @Operation(summary = "파이프라인 생성 및 MinIO업로드", description = "Kubeflow에 파이프라인 파일(Multipart)을 업로드하고 MinIO에 저장")
@ApiResponses({ @ApiResponses({
@ApiResponse(responseCode = "200", description = "파이프라인 업로드 및 MinIO 저장 성공"), @ApiResponse(responseCode = "200", description = "파이프라인 업로드 및 MinIO 저장 성공"),

@ -1,6 +1,5 @@
package kr.re.etri.autoflow.service; package kr.re.etri.autoflow.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import kr.re.etri.autoflow.payload.request.CreateRunRequest; import kr.re.etri.autoflow.payload.request.CreateRunRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -90,4 +89,52 @@ public class PipelineUploadService {
} }
} }
/**
* Experiments
*/
public Map listExperiments(String namespace, int pageSize, String pageToken) {
try {
UriComponentsBuilder builder = UriComponentsBuilder
.fromHttpUrl(kubeflowBaseUrl + "/apis/v2beta1/experiments");
if (namespace != null && !namespace.isBlank()) {
builder.queryParam("namespace", namespace);
}
if (pageSize > 0) {
builder.queryParam("page_size", pageSize);
}
if (pageToken != null && !pageToken.isBlank()) {
builder.queryParam("page_token", pageToken);
}
return webClient.get()
.uri(builder.toUriString())
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(Map.class)
.block();
} catch (Exception e) {
throw new RuntimeException("Kubeflow Experiments 조회 실패", e);
}
}
/**
* Experiment
*/
public Map getExperimentById(String experimentId) {
try {
String url = kubeflowBaseUrl + "/apis/v2beta1/experiments/" + experimentId;
return webClient.get()
.uri(url)
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(Map.class)
.block();
} catch (Exception e) {
throw new RuntimeException("Kubeflow experiment 조회 실패: " + experimentId, e);
}
}
} }

Loading…
Cancel
Save