diff --git a/src/main/java/com/blockcloud/controller/TerraformController.java b/src/main/java/com/blockcloud/controller/TerraformController.java index e7edf0c..d950da2 100644 --- a/src/main/java/com/blockcloud/controller/TerraformController.java +++ b/src/main/java/com/blockcloud/controller/TerraformController.java @@ -1,7 +1,7 @@ package com.blockcloud.controller; import com.blockcloud.dto.RequestDto.TerraformApplyRequestDto; -import com.blockcloud.dto.RequestDto.TerraformDestroyRequestDto; + import com.blockcloud.dto.RequestDto.TerraformPlanRequestDto; import com.blockcloud.dto.RequestDto.TerraformValidateRequestDto; import com.blockcloud.dto.ResponseDto.DeploymentListResponseDto; @@ -35,7 +35,6 @@ public class TerraformController { /** * Terraform 코드를 검증합니다. * - * @param projectId 프로젝트 ID * @param requestDto Terraform 코드 검증 요청 * @return 검증 결과가 담긴 응답 객체 */ @@ -45,9 +44,8 @@ public class TerraformController { ) @PostMapping("/validate") public ResponseDto validateTerraform( - @Parameter(description = "프로젝트 ID", required = true) @PathVariable Long projectId, @Valid @RequestBody TerraformValidateRequestDto requestDto) { - return ResponseDto.ok(terraformService.validateTerraform(projectId, requestDto)); + return ResponseDto.ok(terraformService.validateTerraform(requestDto)); } /** @@ -90,26 +88,28 @@ public ResponseDto applyTerraform( } /** - * Terraform 코드를 실행하여 인프라를 삭제합니다. + * 특정 배포의 인프라를 삭제합니다. * * @param projectId 프로젝트 ID - * @param requestDto Terraform 삭제 요청 + * @param deploymentId 배포 ID * @param authentication 인증 정보 - * @return 삭제 시작 정보가 담긴 응답 객체 + * @return 삭제 결과가 담긴 응답 객체 */ @Operation( - summary = "Terraform 인프라 삭제", - description = "Terraform 코드를 실행하여 생성된 인프라를 삭제합니다. 배포는 비동기로 실행되며, 삭제 ID를 반환합니다." + summary = "특정 배포 인프라 삭제", + description = "특정 배포의 인프라를 삭제합니다. 원본 배포의 Terraform 코드를 사용하여 삭제를 수행합니다." ) - @PostMapping("/destroy") - public ResponseDto destroyTerraform( + @DeleteMapping("/deployments/{deploymentId}/destroy") + public ResponseDto destroyTerraformByDeployment( @Parameter(description = "프로젝트 ID", required = true) @PathVariable Long projectId, - @Valid @RequestBody TerraformDestroyRequestDto requestDto, + @Parameter(description = "배포 ID", required = true) @PathVariable Long deploymentId, Authentication authentication) { CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal(); - return ResponseDto.ok(terraformService.destroyTerraform(projectId, requestDto, userDetails.getUsername())); + return ResponseDto.ok(terraformService.destroyTerraformByDeployment(projectId, deploymentId, userDetails.getUsername())); } + + /** * 특정 배포의 상태를 조회합니다. * diff --git a/src/main/java/com/blockcloud/service/TerraformService.java b/src/main/java/com/blockcloud/service/TerraformService.java index 5f75b88..3a0a757 100644 --- a/src/main/java/com/blockcloud/service/TerraformService.java +++ b/src/main/java/com/blockcloud/service/TerraformService.java @@ -6,7 +6,7 @@ import com.blockcloud.domain.project.Project; import com.blockcloud.domain.project.ProjectRepository; import com.blockcloud.dto.RequestDto.TerraformApplyRequestDto; -import com.blockcloud.dto.RequestDto.TerraformDestroyRequestDto; + import com.blockcloud.dto.RequestDto.TerraformPlanRequestDto; import com.blockcloud.dto.RequestDto.TerraformValidateRequestDto; import com.blockcloud.dto.ResponseDto.DeploymentListResponseDto; @@ -40,10 +40,7 @@ public class TerraformService { /** * Terraform 코드를 검증합니다. */ - public TerraformValidateResponseDto validateTerraform(Long projectId, TerraformValidateRequestDto requestDto) { - Project project = projectRepository.findById(projectId) - .orElseThrow(() -> new CommonException(ErrorCode.NOT_FOUND_PROJECT)); - + public TerraformValidateResponseDto validateTerraform(TerraformValidateRequestDto requestDto) { TerraformExecutor.TerraformExecutionResult result = terraformExecutor.validate(requestDto.getTerraformCode()); return TerraformValidateResponseDto.builder() @@ -72,9 +69,6 @@ public TerraformPlanResponseDto planTerraform(Long projectId, TerraformPlanReque .build(); } - /** - * Terraform 코드를 적용하여 배포를 시작합니다. - */ @Transactional public TerraformApplyResponseDto applyTerraform(Long projectId, TerraformApplyRequestDto requestDto, String username) { Project project = projectRepository.findById(projectId) @@ -109,46 +103,48 @@ public TerraformApplyResponseDto applyTerraform(Long projectId, TerraformApplyRe .build(); } - /** - * Terraform 코드를 실행하여 인프라를 삭제합니다. - */ @Transactional - public TerraformDestroyResponseDto destroyTerraform(Long projectId, TerraformDestroyRequestDto requestDto, String username) { + public TerraformDestroyResponseDto destroyTerraformByDeployment(Long projectId, Long deploymentId, String username) { Project project = projectRepository.findById(projectId) .orElseThrow(() -> new CommonException(ErrorCode.NOT_FOUND_PROJECT)); - // 배포 이력 생성 (삭제용) - Deployment deployment = Deployment.builder() + Deployment deployment = deploymentRepository.findById(deploymentId) + .orElseThrow(() -> new CommonException(ErrorCode.NOT_FOUND_DEPLOYMENT)); + + // 프로젝트에 속한 배포인지 확인 + if (!deployment.getProject().getId().equals(projectId)) { + throw new CommonException(ErrorCode.ACCESS_DENIED); + } + + // 삭제용 배포 이력 생성 + Deployment destroyDeployment = Deployment.builder() .project(project) .status(DeploymentStatus.PENDING) .message("인프라 삭제 대기 중") - .terraformCode(requestDto.getTerraformCode()) + .terraformCode(deployment.getTerraformCode()) .startedAt(LocalDateTime.now()) .build(); - Deployment savedDeployment = deploymentRepository.save(deployment); + Deployment savedDestroyDeployment = deploymentRepository.save(destroyDeployment); // 비동기로 삭제 실행 CompletableFuture.runAsync(() -> { try { - executeTerraformDestroy(savedDeployment.getId(), projectId, requestDto.getTerraformCode()); + executeTerraformDestroy(savedDestroyDeployment.getId(), projectId, deployment.getTerraformCode()); } catch (Exception e) { - log.error("Terraform destroy failed for deployment {}: {}", savedDeployment.getId(), e.getMessage()); - updateDeploymentStatus(savedDeployment.getId(), DeploymentStatus.FAILED, "삭제 실패: " + e.getMessage()); + log.error("Terraform destroy failed for deployment {}: {}", savedDestroyDeployment.getId(), e.getMessage()); + updateDeploymentStatus(savedDestroyDeployment.getId(), DeploymentStatus.FAILED, "삭제 실패: " + e.getMessage()); } }); return TerraformDestroyResponseDto.builder() - .deploymentId(savedDeployment.getId()) + .deploymentId(savedDestroyDeployment.getId()) .status("PENDING") .message("인프라 삭제가 시작되었습니다.") - .startedAt(savedDeployment.getStartedAt()) + .startedAt(savedDestroyDeployment.getStartedAt()) .build(); } - /** - * 배포 상태를 조회합니다. - */ public DeploymentStatusResponseDto getDeploymentStatus(Long projectId, Long deploymentId) { Project project = projectRepository.findById(projectId) .orElseThrow(() -> new CommonException(ErrorCode.NOT_FOUND_PROJECT)); @@ -171,9 +167,6 @@ public DeploymentStatusResponseDto getDeploymentStatus(Long projectId, Long depl .build(); } - /** - * 프로젝트의 배포 이력을 조회합니다. - */ public DeploymentListResponseDto getDeploymentHistory(Long projectId, Long lastId, int size) { Project project = projectRepository.findById(projectId) .orElseThrow(() -> new CommonException(ErrorCode.NOT_FOUND_PROJECT)); @@ -203,8 +196,6 @@ public DeploymentListResponseDto getDeploymentHistory(Long projectId, Long lastI .build(); } - // Private helper methods - private void executeTerraformApply(Long deploymentId, Long projectId, String terraformCode) { try { // 상태를 RUNNING으로 업데이트