|
|
|
|
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<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 = "파이프라인 업로드", 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<Map<String, Object>> 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<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);
|
|
|
|
|
|
|
|
|
|
// 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<String, Object> 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<Map<String, Object>> createRun(
|
|
|
|
|
@RequestBody CreateRunRequest runRequest
|
|
|
|
|
) {
|
|
|
|
|
try {
|
|
|
|
|
Map<String, Object> 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()
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|