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.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 = "파이프라인 업로드", 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> 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 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 = "파이프라인 업로드", 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, "pipelines/" + projectId, // 저장 경로 예시 workflow.getId(), // refId : 방금 저장한 워크플로우 PK "PIPELINE", // 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() )); } } }