package kr.re.etri.autoflow.controllers; import io.minio.MinioClient; 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.entity.MinioAttachmentEntity; import kr.re.etri.autoflow.entity.WorkflowEntity; import kr.re.etri.autoflow.payload.request.CreateRunRequest; import kr.re.etri.autoflow.service.MinioAttachmentService; import kr.re.etri.autoflow.service.PipelineUploadService; import kr.re.etri.autoflow.service.WorkFlowService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.util.HashMap; import java.util.Map; @Slf4j @RestController @RequestMapping("/pipelines") @RequiredArgsConstructor @CrossOrigin(origins = "*") @io.swagger.v3.oas.annotations.tags.Tag(name = "Kubeflow Pipeline", description = "Kubeflow 파이프라인 API") public class PipelineUploadController { private final PipelineUploadService pipelineUploadService; private final WorkFlowService workFlowService; private final MinioAttachmentService minioAttachmentService; @Operation(summary = "파이프라인 생성 및 MinIO업로드", description = "Kubeflow에 파이프라인 파일(Multipart)을 업로드하고 MinIO에 저장") @ApiResponses({ @ApiResponse(responseCode = "200", description = "파이프라인 업로드 및 MinIO 저장 성공"), @ApiResponse(responseCode = "400", description = "잘못된 요청"), @ApiResponse(responseCode = "500", description = "서버 내부 오류") }) @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity> uploadPipeline( @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 { // 1. Kubeflow 파이프라인 업로드 Map 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); // 2. MinIO 업로드 MinioAttachmentEntity attachment = minioAttachmentService.uploadFile( file, "workflows/" + projectId, // 저장 경로 예시 workflow.getId(), // refId : 방금 저장한 워크플로우 PK "workflows", // refType displayName, // title description, // description 1, // version regUserId, projectId ); String minioUrl = minioAttachmentService.getFileUrl(attachment.getStoragePath()); // 3. 최종 응답 구성 Map response = new HashMap<>(); response.put("pipeline", result); response.put("workflow", workflow); response.put("attachment", attachment); response.put("minioUrl", minioUrl); return ResponseEntity.ok(response); } catch (Exception e) { log.error("Pipeline + MinIO upload failed", e); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body(Map.of( "status", 500, "error", "Internal Server Error", "message", e.getMessage() )); } } @PostMapping("/runs") @Operation( summary = "Kubeflow Run 생성", description = "Kubeflow에 Run을 생성합니다." ) @ApiResponses({ @ApiResponse(responseCode = "200", description = "Run 생성 성공"), @ApiResponse(responseCode = "400", description = "display_name 필수"), @ApiResponse(responseCode = "500", description = "서버 오류") }) public ResponseEntity> createRun( @RequestBody CreateRunRequest runRequest ) { try { Map result = pipelineUploadService.createRun(runRequest); return ResponseEntity.ok(result); } catch (IllegalArgumentException e) { log.error("Invalid run request", e); return ResponseEntity.status(HttpStatus.BAD_REQUEST) .body(Map.of( "status", 400, "error", "Bad Request", "message", e.getMessage() )); } catch (Exception e) { log.error("Run creation failed", e); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body(Map.of( "status", 500, "error", "Internal Server Error", "message", e.getMessage() )); } } }