diff --git a/.vscode/settings.json b/.vscode/settings.json index 75c49d6..92c12cc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,5 @@ { "java.compile.nullAnalysis.mode": "automatic", - "java.dependency.packagePresentation": "hierarchical" + "java.dependency.packagePresentation": "hierarchical", + "java.configuration.updateBuildConfiguration": "automatic" } \ No newline at end of file diff --git a/applicationFE/package-lock.json b/applicationFE/package-lock.json index 58b76ee..90891f5 100644 --- a/applicationFE/package-lock.json +++ b/applicationFE/package-lock.json @@ -13,6 +13,7 @@ "application-manager-ui": "file:", "axios": "^1.7.2", "bootstrap": "^5.3.0", + "bootstrap-icons": "^1.11.3", "lodash": "^4.17.21", "pinia": "^2.1.7", "tabulator-tables": "^6.2.1", @@ -2380,6 +2381,22 @@ "@popperjs/core": "^2.11.8" } }, + "node_modules/bootstrap-icons": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.11.3.tgz", + "integrity": "sha512-+3lpHrCw/it2/7lBL15VR0HEumaBss0+f/Lb6ZvHISn1mlK83jjFpooTLsMWbIjJMDjDjOExMsTxnXSIT4k4ww==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "license": "MIT" + }, "node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", diff --git a/build.gradle b/build.gradle index 73251f3..21142ae 100644 --- a/build.gradle +++ b/build.gradle @@ -100,7 +100,11 @@ dependencies { implementation 'io.kubernetes:client-java-api:20.0.0' implementation 'io.kubernetes:client-java-extended:20.0.0' + implementation 'com.github.docker-java:docker-java:3.3.0' + implementation 'com.github.docker-java:docker-java-transport-httpclient5:3.3.0' + implementation 'io.github.cdancy:jenkins-rest:1.0.1:all' + } diff --git a/src/main/java/kr/co/mcmp/ApplicationManagerApplication.java b/src/main/java/kr/co/mcmp/ApplicationManagerApplication.java index 40d92c3..7e62448 100644 --- a/src/main/java/kr/co/mcmp/ApplicationManagerApplication.java +++ b/src/main/java/kr/co/mcmp/ApplicationManagerApplication.java @@ -3,6 +3,8 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.scheduling.annotation.EnableScheduling; + import springfox.documentation.swagger2.annotations.EnableSwagger2; import java.io.UnsupportedEncodingException; @@ -11,6 +13,7 @@ @EnableSwagger2 @SpringBootApplication @EnableFeignClients +@EnableScheduling public class ApplicationManagerApplication { public static void main(String[] args) throws GeneralSecurityException, UnsupportedEncodingException { diff --git a/src/main/java/kr/co/mcmp/ape/cbtumblebug/api/CbtumblebugRestApi.java b/src/main/java/kr/co/mcmp/ape/cbtumblebug/api/CbtumblebugRestApi.java index 78408bd..4bf9a73 100644 --- a/src/main/java/kr/co/mcmp/ape/cbtumblebug/api/CbtumblebugRestApi.java +++ b/src/main/java/kr/co/mcmp/ape/cbtumblebug/api/CbtumblebugRestApi.java @@ -14,8 +14,11 @@ import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; +import org.springframework.web.client.RestClientException; +import org.springframework.web.util.UriComponentsBuilder; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import kr.co.mcmp.ape.cbtumblebug.dto.K8sClusterDto; @@ -25,8 +28,9 @@ import kr.co.mcmp.ape.cbtumblebug.dto.MciResponse; import kr.co.mcmp.ape.cbtumblebug.dto.NamespaceDto; import kr.co.mcmp.ape.cbtumblebug.dto.NamespaceResponse; +import kr.co.mcmp.ape.cbtumblebug.dto.MciAccessInfoDto; import kr.co.mcmp.ape.cbtumblebug.dto.Spec; -import kr.co.mcmp.ape.cbtumblebug.dto.VmDto; +import kr.co.mcmp.ape.cbtumblebug.dto.VmAccessInfo; import kr.co.mcmp.ape.cbtumblebug.exception.CbtumblebugException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -50,6 +54,10 @@ public class CbtumblebugRestApi { private final CbtumblebugRestClient restClient; + private boolean isTumblebugReady = false; + private long lastCheckTime = 0; + private static final long CHECK_INTERVAL = 60000; // 1 minute + private HttpHeaders createCommonHeaders() { HttpHeaders headers = new HttpHeaders(); String auth = cbtumblebugId + ":" + cbtumblebugPass; @@ -66,7 +74,7 @@ private String createApiUrl(String endpoint) { return apiUrl; } - +/* public boolean checkTumblebug() { log.info("Checking if Tumblebug is ready"); String apiUrl = createApiUrl("/tumblebug/readyz"); @@ -79,7 +87,8 @@ public boolean checkTumblebug() { log.error("Tumblebug connection failed", e); return false; } - } + } + private T executeWithConnectionCheck(String operationName, Supplier apiCall) { if (!checkTumblebug()) { @@ -87,8 +96,95 @@ private T executeWithConnectionCheck(String operationName, Supplier apiCa throw new CbtumblebugException("Tumblebug 연결 실패"); } return apiCall.get(); + } + */ + + public boolean checkTumblebug() { + long currentTime = System.currentTimeMillis(); + if (currentTime - lastCheckTime > CHECK_INTERVAL || !isTumblebugReady) { + log.info("Checking if Tumblebug is ready"); + String apiUrl = createApiUrl("/tumblebug/readyz"); + HttpHeaders headers = createCommonHeaders(); + try { + ResponseEntity response = restClient.request(apiUrl, headers, null, HttpMethod.GET, new ParameterizedTypeReference() {}); + isTumblebugReady = response.getStatusCode().is2xxSuccessful(); + lastCheckTime = currentTime; + } catch (Exception e) { + log.error("Tumblebug connection failed", e); + isTumblebugReady = false; + } + } + return isTumblebugReady; + } + + public T executeWithConnectionCheck(String operationName, Supplier apiCall) { + if (!checkTumblebug()) { + throw new CbtumblebugException("Tumblebug is not ready"); + } + return apiCall.get(); } + + public String executeMciCommand(String nsId, String mciId, String command, String subGroupId, String vmId) { + log.info("Executing command on MCI: {}, VM: {}", mciId, vmId); + return executeWithConnectionCheck("executeMciCommand", () -> { + try { + String apiUrl = createApiUrl(String.format("/tumblebug/ns/%s/cmd/mci/%s", nsId, mciId)); + HttpHeaders headers = createCommonHeaders(); + + // 요청 본문 생성 + Map requestBody = new HashMap<>(); + requestBody.put("command", Collections.singletonList(command)); + + // 쿼리 파라미터 추가 + if (subGroupId != null && !subGroupId.isEmpty()) { + apiUrl += "?subGroupId=" + subGroupId; + } + if (vmId != null && !vmId.isEmpty()) { + apiUrl += (apiUrl.contains("?") ? "&" : "?") + "vmId=" + vmId; + } + + String jsonBody = new ObjectMapper().writeValueAsString(requestBody); + + ResponseEntity response = restClient.request( + apiUrl, + headers, + jsonBody, + HttpMethod.POST, + new ParameterizedTypeReference() {} + ); + + if (response.getStatusCode().is2xxSuccessful()) { + String responseBody = response.getBody(); + log.info("command result: {}", response.getBody()); + ObjectMapper mapper = new ObjectMapper(); + JsonNode rootNode = mapper.readTree(responseBody); + JsonNode resultsNode = rootNode.path("results"); + if (resultsNode.isArray() && resultsNode.size() > 0) { + JsonNode firstResult = resultsNode.get(0); + String stdout = firstResult.path("stdout").path("0").asText(); + String stderr = firstResult.path("stderr").path("0").asText(); + if (!stderr.isEmpty()) { + log.warn("Command execution produced stderr: {}", stderr); + } + return stdout; + } else { + throw new CbtumblebugException("Unexpected response format"); + } + } else { + throw new CbtumblebugException("MCI command execution failed. Status code: " + response.getStatusCodeValue()); + } + + } catch (JsonProcessingException e) { + log.error("Error serializing request body", e); + throw new CbtumblebugException("Failed to serialize request body: " + e.getMessage()); + } catch (RestClientException e) { + log.error("Error executing command on MCI", e); + throw new CbtumblebugException("Failed to execute command on MCI: " + e.getMessage()); + } + }); + } + public List getAllNamespace() { log.info("Fetching all namespaces"); return executeWithConnectionCheck("getAllNamespace", () ->{ @@ -109,15 +205,27 @@ public List getMcisByNamespace(String namespace) { }); } - // public String getK8sClusterInfo(){ - // log.info("Fetching all K8sClusterInfo"); - // return executeWithConnectionCheck("getK8sClusterInfo", () ->{ - // String apiUrl = createApiUrl("/k8sClusterInfo"); - // HttpHeaders headers = createCommonHeaders(); - // ResponseEntity response = restClient.request(apiUrl, headers, headers, HttpMethod.GET, new ParameterizedTypeReference() {}); - // return response.getBody() != null ? response.getBody() : null; - // }); - // } + public MciAccessInfoDto getSSHKeyForMci(String namespace, String mciId) { + log.info("Fetching SSH Key for MCI: {} in namespace: {}", mciId, namespace); + return executeWithConnectionCheck("getSSHKeyForMci", () -> { + String apiUrl = createApiUrl(String.format("/tumblebug/ns/%s/mci/%s", namespace, mciId)); + HttpHeaders headers = createCommonHeaders(); + + UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(apiUrl) + .queryParam("option", "accessinfo") + .queryParam("accessInfoOption", "showSshKey"); + + ResponseEntity response = restClient.request( + builder.toUriString(), + headers, + null, + HttpMethod.GET, + new ParameterizedTypeReference() {} + ); + + return response.getBody(); + }); + } public List getAllK8sClusters(String namespace){ log.info("Fetching K8s Clusters by namespace: {}", namespace); @@ -179,21 +287,22 @@ public Spec getSpecBySpecId(String nsId, String specId) { HttpMethod.GET, new ParameterizedTypeReference() {} ); + log.info("Spec : {}" , response.getBody().toString()); return response.getBody(); }); } - public VmDto getVmInfo(String nsId, String mciId, String vmId) { + public VmAccessInfo getVmInfo(String nsId, String mciId, String vmId) { log.info("Fetching VM info for VM ID: {}", vmId); return executeWithConnectionCheck("getVmInfo", () -> { String apiUrl = createApiUrl(String.format("/tumblebug/ns/%s/mci/%s/vm/%s", nsId, mciId, vmId)); HttpHeaders headers = createCommonHeaders(); - ResponseEntity response = restClient.request( + ResponseEntity response = restClient.request( apiUrl, headers, null, HttpMethod.GET, - new ParameterizedTypeReference() {} + new ParameterizedTypeReference() {} ); return response.getBody(); }); @@ -228,18 +337,5 @@ public K8sSpec lookupSpec(String connectionName, String cspResourceId) { return response.getBody(); }); - // String apiUrl = "http://localhost:1323/tumblebug/lookupSpec"; - // String requestBody = String.format("{\"connectionName\": \"%s\", \"cspResourceId\": \"%s\"}", connectionName, cspResourceId); - - // HttpHeaders headers = createCommonHeaders(); - // ResponseEntity response = restClient.request( - // apiUrl, - // headers, - // requestBody, - // HttpMethod.POST, - // new ParameterizedTypeReference() {} - // ); - - // return response.getBody(); } } diff --git a/src/main/java/kr/co/mcmp/ape/cbtumblebug/controller/CbtumblebugController.java b/src/main/java/kr/co/mcmp/ape/cbtumblebug/controller/CbtumblebugController.java index 95b66c2..baa27fd 100644 --- a/src/main/java/kr/co/mcmp/ape/cbtumblebug/controller/CbtumblebugController.java +++ b/src/main/java/kr/co/mcmp/ape/cbtumblebug/controller/CbtumblebugController.java @@ -2,7 +2,7 @@ import java.util.List; -import kr.co.mcmp.response.ResponseWrapper; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @@ -16,8 +16,8 @@ import kr.co.mcmp.ape.cbtumblebug.dto.NamespaceDto; import kr.co.mcmp.ape.cbtumblebug.dto.Spec; import kr.co.mcmp.ape.cbtumblebug.service.CbtumblebugService; +import kr.co.mcmp.response.ResponseWrapper; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.RequestParam; @Tag(name="tumblebug", description = "Tumblebug API queries") @@ -30,38 +30,44 @@ public class CbtumblebugController { @GetMapping("/ns") @Operation(summary = "Retrieve all namespaces", description = "Fetches all registered namespaces.") - public ResponseWrapper> getAllNamespaces() { - return new ResponseWrapper<>(cbtumblebugService.getAllNamespaces()) ; + public ResponseEntity>> getAllNamespaces() { + List result = cbtumblebugService.getAllNamespaces(); + return ResponseEntity.ok(new ResponseWrapper<>(result)); } @GetMapping("/ns/{nsId}/mci") @Operation(summary = "Retrieve MCIS for a specific namespace", description = "Fetches all MCIS belonging to the specified namespace.") - public ResponseWrapper> getMicsByNamespace(@Parameter(description = "Namespace ID", required = true) + public ResponseEntity>> getMicsByNamespace(@Parameter(description = "Namespace ID", required = true) @PathVariable String nsId) { - return new ResponseWrapper<>(cbtumblebugService.getMcisByNamespace(nsId)); + List result = cbtumblebugService.getMcisByNamespace(nsId); + return ResponseEntity.ok(new ResponseWrapper<>(result)); } @GetMapping("/ns/{nsId}/mci/{mciId}") @Operation(summary = "Retrieve a specific MCI", description = "Fetches the specified MCI.") - public ResponseWrapper getMicByMciId(@PathVariable String nsId, @PathVariable String mciId) { - return new ResponseWrapper<>(cbtumblebugService.getMciByMciId(nsId, mciId)); + public ResponseEntity> getMicByMciId(@PathVariable String nsId, @PathVariable String mciId) { + MciDto result = cbtumblebugService.getMciByMciId(nsId, mciId); + return ResponseEntity.ok(new ResponseWrapper<>(result)); } @GetMapping("/ns/{nsId}/k8scluster") @Operation(summary = "Retrieve k8sclusters for a specific namespace", description = "Fetches all k8sclusters belonging to the specified namespace.") - public ResponseWrapper> getK8sCluster(@PathVariable String nsId) { - return new ResponseWrapper<>(cbtumblebugService.getAllK8sClusters(nsId)); + public ResponseEntity>> getK8sCluster(@PathVariable String nsId) { + List result = cbtumblebugService.getAllK8sClusters(nsId); + return ResponseEntity.ok(new ResponseWrapper<>(result)); } @GetMapping("/ns/{nsId}/k8scluster/{clusterName}") @Operation(summary = "Retrieve a specific k8scluster", description = "Fetches the specified k8scluster.") - public ResponseWrapper getK8sClusterByName(@PathVariable String nsId, @PathVariable String clusterName) { - return new ResponseWrapper<>(cbtumblebugService.getK8sClusterByName(nsId, clusterName)); + public ResponseEntity> getK8sClusterByName(@PathVariable String nsId, @PathVariable String clusterName) { + K8sClusterDto result = cbtumblebugService.getK8sClusterByName(nsId, clusterName); + return ResponseEntity.ok(new ResponseWrapper<>(result)); } @GetMapping("/ns/{nsId}/resources/spec/{specId}") - public ResponseWrapper getMethodName(@PathVariable String nsId, @PathVariable String specId) { - return new ResponseWrapper<>(cbtumblebugService.getSpecBySpecId(nsId, specId)); + public ResponseEntity> getMethodName(@PathVariable String nsId, @PathVariable String specId) { + Spec result = cbtumblebugService.getSpecBySpecId(nsId, specId); + return ResponseEntity.ok(new ResponseWrapper<>(result)); } diff --git a/src/main/java/kr/co/mcmp/ape/cbtumblebug/dto/MciAccessInfoDto.java b/src/main/java/kr/co/mcmp/ape/cbtumblebug/dto/MciAccessInfoDto.java new file mode 100644 index 0000000..0ab482c --- /dev/null +++ b/src/main/java/kr/co/mcmp/ape/cbtumblebug/dto/MciAccessInfoDto.java @@ -0,0 +1,48 @@ +package kr.co.mcmp.ape.cbtumblebug.dto; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class MciAccessInfoDto { + @JsonProperty("MciId") + private String mciId; + + @JsonProperty("MciSubGroupAccessInfo") + private List mciSubGroupAccessInfo; + + @Data + public static class MciSubGroupAccessInfo { + @JsonProperty("SubGroupId") + private String subGroupId; + + @JsonProperty("BastionVmId") + private String bastionVmId; + + @JsonProperty("MciVmAccessInfo") + private List mciVmAccessInfo; + } + + @Data + public static class MciVmAccessInfo { + @JsonProperty("vmId") + private String vmId; + + @JsonProperty("publicIP") + private String publicIP; + + @JsonProperty("privateIP") + private String privateIP; + + @JsonProperty("sshPort") + private String sshPort; + + @JsonProperty("privateKey") + private String privateKey; + } +} \ No newline at end of file diff --git a/src/main/java/kr/co/mcmp/ape/cbtumblebug/dto/MciDto.java b/src/main/java/kr/co/mcmp/ape/cbtumblebug/dto/MciDto.java index 76ee892..c0ddcdb 100644 --- a/src/main/java/kr/co/mcmp/ape/cbtumblebug/dto/MciDto.java +++ b/src/main/java/kr/co/mcmp/ape/cbtumblebug/dto/MciDto.java @@ -58,10 +58,10 @@ public class MciDto { private String description; @ApiModelProperty(value = "List of VMs") - private List vm; + private List vm; @ApiModelProperty(value = "List of new VMs") - private List newVmList; + private List newVmList; } diff --git a/src/main/java/kr/co/mcmp/ape/cbtumblebug/dto/Region.java b/src/main/java/kr/co/mcmp/ape/cbtumblebug/dto/Region.java index a056f54..c02be3b 100644 --- a/src/main/java/kr/co/mcmp/ape/cbtumblebug/dto/Region.java +++ b/src/main/java/kr/co/mcmp/ape/cbtumblebug/dto/Region.java @@ -3,17 +3,19 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; +import lombok.Data; import lombok.NoArgsConstructor; @NoArgsConstructor @AllArgsConstructor +@Data @ApiModel(description = "Region information") public class Region { @ApiModelProperty(value = "Region") - private String Region; + private String region; @ApiModelProperty(value = "Zone") - private String Zone; + private String zone; } diff --git a/src/main/java/kr/co/mcmp/ape/cbtumblebug/dto/Spec.java b/src/main/java/kr/co/mcmp/ape/cbtumblebug/dto/Spec.java index ed057b5..7b5e1eb 100644 --- a/src/main/java/kr/co/mcmp/ape/cbtumblebug/dto/Spec.java +++ b/src/main/java/kr/co/mcmp/ape/cbtumblebug/dto/Spec.java @@ -3,10 +3,12 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; +import lombok.ToString; import java.util.List; @Data +@ToString public class Spec { private int acceleratorCount; @@ -64,5 +66,6 @@ public class Spec { private int storageGiB; private String systemLabel; private String uid; - private int vCPU; + @JsonProperty("vCPU") + private Double vCPU; } \ No newline at end of file diff --git a/src/main/java/kr/co/mcmp/ape/cbtumblebug/dto/VmAccessInfo.java b/src/main/java/kr/co/mcmp/ape/cbtumblebug/dto/VmAccessInfo.java new file mode 100644 index 0000000..26fe75b --- /dev/null +++ b/src/main/java/kr/co/mcmp/ape/cbtumblebug/dto/VmAccessInfo.java @@ -0,0 +1,252 @@ +package kr.co.mcmp.ape.cbtumblebug.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; + +import java.util.List; +import java.util.Map; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@ToString +@ApiModel(description = "VM (Virtual Machine) information") +public class VmAccessInfo { + @ApiModelProperty(value = "Resource type", example = "vm") + private String resourceType; + + @ApiModelProperty(value = "VM ID", example = "vm01-1") + private String id; + + @ApiModelProperty(value = "VM UID", example = "cstcna3ebd5s73bq2o3g") + private String uid; + + @ApiModelProperty(value = "CSP Resource Name") + private String cspResourceName; + + @ApiModelProperty(value = "CSP Resource ID") + private String cspResourceId; + + @ApiModelProperty(value = "VM name", example = "vm01-1") + private String name; + + @ApiModelProperty(value = "Sub group ID") + private String subGroupId; + + @ApiModelProperty(value = "Location information") + private Location location; + + @ApiModelProperty(value = "VM status", example = "Running") + private String status; + + @ApiModelProperty(value = "Target status", example = "None") + private String targetStatus; + + @ApiModelProperty(value = "Target action", example = "None") + private String targetAction; + + @ApiModelProperty(value = "Monitoring agent status") + private String monAgentStatus; + + @ApiModelProperty(value = "Network agent status") + private String networkAgentStatus; + + @ApiModelProperty(value = "System message") + private String systemMessage; + + @ApiModelProperty(value = "Created time") + private String createdTime; + + @ApiModelProperty(value = "Label") + private Map label; + + @ApiModelProperty(value = "Description", example = "") + private String description; + + @ApiModelProperty(value = "Region information") + private Region region; + + @ApiModelProperty(value = "Public IP") + private String publicIP; + + @ApiModelProperty(value = "SSH port") + private String sshPort; + + @ApiModelProperty(value = "Public DNS") + private String publicDNS; + + @ApiModelProperty(value = "Private IP") + private String privateIP; + + @ApiModelProperty(value = "Private DNS") + private String privateDNS; + + @ApiModelProperty(value = "Root disk type") + private String rootDiskType; + + @ApiModelProperty(value = "Root disk size") + private String rootDiskSize; + + @ApiModelProperty(value = "Root device name") + private String rootDeviceName; + + @ApiModelProperty(value = "Connection name") + private String connectionName; + + @ApiModelProperty(value = "Connection configuration") + private ConnectionConfig connectionConfig; + + @ApiModelProperty(value = "Spec ID") + private String specId; + + @ApiModelProperty(value = "CSP spec name") + private String cspSpecName; + + @ApiModelProperty(value = "Image ID") + private String imageId; + + @ApiModelProperty(value = "CSP image name") + private String cspImageName; + + @ApiModelProperty(value = "VNet ID") + private String vNetId; + + @ApiModelProperty(value = "CSP VNet ID") + private String cspVNetId; + + @ApiModelProperty(value = "Subnet ID") + private String subnetId; + + @ApiModelProperty(value = "CSP subnet ID") + private String cspSubnetId; + + @ApiModelProperty(value = "Network interface") + private String networkInterface; + + @ApiModelProperty(value = "Security group IDs") + private List securityGroupIds; + + @ApiModelProperty(value = "Data disk IDs") + private List dataDiskIds; + + @ApiModelProperty(value = "SSH key ID") + private String sshKeyId; + + @ApiModelProperty(value = "CSP SSH key ID") + private String cspSshKeyId; + + @ApiModelProperty(value = "VM user name") + private String vmUserName; + + @ApiModelProperty(value = "Additional details") + private List additionalDetails; + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class Location { + @ApiModelProperty(value = "Display name") + private String display; + + @ApiModelProperty(value = "Latitude") + private Double latitude; + + @ApiModelProperty(value = "Longitude") + private Double longitude; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class Region { + @JsonProperty("Region") + @ApiModelProperty(value = "Region") + private String region; + + @JsonProperty("Zone") + @ApiModelProperty(value = "Zone") + private String zone; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class ConnectionConfig { + @ApiModelProperty(value = "Config name") + private String configName; + + @ApiModelProperty(value = "Provider name") + private String providerName; + + @ApiModelProperty(value = "Driver name") + private String driverName; + + @ApiModelProperty(value = "Credential name") + private String credentialName; + + @ApiModelProperty(value = "Credential holder") + private String credentialHolder; + + @ApiModelProperty(value = "Region zone info name") + private String regionZoneInfoName; + + @ApiModelProperty(value = "Region zone info") + private RegionZoneInfo regionZoneInfo; + + @ApiModelProperty(value = "Region detail") + private RegionDetail regionDetail; + + @ApiModelProperty(value = "Region representative") + private Boolean regionRepresentative; + + @ApiModelProperty(value = "Verified") + private Boolean verified; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class RegionZoneInfo { + @ApiModelProperty(value = "Assigned region") + private String assignedRegion; + + @ApiModelProperty(value = "Assigned zone") + private String assignedZone; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class RegionDetail { + @ApiModelProperty(value = "Region ID") + private String regionId; + + @ApiModelProperty(value = "Region name") + private String regionName; + + @ApiModelProperty(value = "Description") + private String description; + + @ApiModelProperty(value = "Location") + private Location location; + + @ApiModelProperty(value = "Zones") + private List zones; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class AdditionalDetail { + @ApiModelProperty(value = "Key") + private String key; + + @ApiModelProperty(value = "Value") + private String value; + } +} \ No newline at end of file diff --git a/src/main/java/kr/co/mcmp/ape/cbtumblebug/dto/VmDto.java b/src/main/java/kr/co/mcmp/ape/cbtumblebug/dto/VmDto.java deleted file mode 100644 index 592bdcc..0000000 --- a/src/main/java/kr/co/mcmp/ape/cbtumblebug/dto/VmDto.java +++ /dev/null @@ -1,138 +0,0 @@ -package kr.co.mcmp.ape.cbtumblebug.dto; - -import java.util.List; -import java.util.Map; - -import org.apache.http.config.ConnectionConfig; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -// @JsonIgnoreProperties(ignoreUnknown = true) -@ApiModel(description = "VM (Virtual Machine) information") -public class VmDto { - @ApiModelProperty(value = "Resource type", example = "mci") - private String resourceType; - - @ApiModelProperty(value = "VM ID", example = "g1-1-3") - private String id; - - @ApiModelProperty(value = "VM UID", example = "crr3fq5n7lsc739fdq0g") - private String uid; - - @ApiModelProperty(value = "VM name", example = "mci01") - private String name; - - @ApiModelProperty(value = "Sub group ID") - private String subGroupId; - - @ApiModelProperty(value = "Location information") - private Location location; - - @ApiModelProperty(value = "VM status", example = "Creating") - private String status; - - @ApiModelProperty(value = "Target status", example = "Running") - private String targetStatus; - - @ApiModelProperty(value = "Target action", example = "Create") - private String targetAction; - - @ApiModelProperty(value = "Monitoring agent status") - private String monAgentStatus; - - @ApiModelProperty(value = "Network agent status") - private String networkAgentStatus; - - @ApiModelProperty(value = "System message") - private String systemMessage; - - @ApiModelProperty(value = "Created time") - private String createdTime; - - @ApiModelProperty(value = "Label") - private Map label; - - @ApiModelProperty(value = "Description", example = "Made in CB-TB") - private String description; - - @ApiModelProperty(value = "Region information") - private Region region; - - @ApiModelProperty(value = "Public IP") - private String publicIP; - - @ApiModelProperty(value = "SSH port") - private String sshPort; - - @ApiModelProperty(value = "Public DNS") - private String publicDNS; - - @ApiModelProperty(value = "Private IP") - private String privateIP; - - @ApiModelProperty(value = "Private DNS") - private String privateDNS; - - @ApiModelProperty(value = "Root disk type") - private String rootDiskType; - - @ApiModelProperty(value = "Root disk size") - private String rootDiskSize; - - @ApiModelProperty(value = "Root device name") - private String rootDeviceName; - - @ApiModelProperty(value = "Connection name") - private String connectionName; - - // @ApiModelProperty(value = "Connection configuration") - // private ConnectionConfig connectionConfig; - - @ApiModelProperty(value = "Spec ID") - private String specId; - - @ApiModelProperty(value = "CSP spec name") - private String cspSpecName; - - @ApiModelProperty(value = "Image ID") - private String imageId; - - @ApiModelProperty(value = "CSP image name") - private String cspImageName; - - @ApiModelProperty(value = "VNet ID") - private String vNetId; - - @ApiModelProperty(value = "CSP VNet ID") - private String cspVNetId; - - @ApiModelProperty(value = "Subnet ID") - private String subnetId; - - @ApiModelProperty(value = "CSP subnet ID") - private String cspSubnetId; - - @ApiModelProperty(value = "Network interface") - private String networkInterface; - - @ApiModelProperty(value = "Security group IDs") - private List securityGroupIds; - - @ApiModelProperty(value = "Data disk IDs") - private List dataDiskIds; - - @ApiModelProperty(value = "SSH key ID") - private String sshKeyId; - - @ApiModelProperty(value = "CSP SSH key ID") - private String cspSshKeyId; -} \ No newline at end of file diff --git a/src/main/java/kr/co/mcmp/ape/controller/AppProvEngineController.java b/src/main/java/kr/co/mcmp/ape/controller/AppProvEngineController.java index a1d9f1f..c8b2010 100644 --- a/src/main/java/kr/co/mcmp/ape/controller/AppProvEngineController.java +++ b/src/main/java/kr/co/mcmp/ape/controller/AppProvEngineController.java @@ -25,6 +25,10 @@ @RestController @RequestMapping("/ape") @RequiredArgsConstructor +/** + * @deprecated Ape not used + */ +@Deprecated public class AppProvEngineController { private final AppProvEngineService appProvEngineService; diff --git a/src/main/java/kr/co/mcmp/ape/service/AppProvEngineServiceImpl.java b/src/main/java/kr/co/mcmp/ape/service/AppProvEngineServiceImpl.java index 9ca8fb0..2cf36cd 100644 --- a/src/main/java/kr/co/mcmp/ape/service/AppProvEngineServiceImpl.java +++ b/src/main/java/kr/co/mcmp/ape/service/AppProvEngineServiceImpl.java @@ -15,11 +15,11 @@ import kr.co.mcmp.ape.dto.reqDto.JenkinsJobDto; import kr.co.mcmp.ape.dto.resDto.ApeLogResDto; import kr.co.mcmp.ape.service.jenkins.service.JenkinsService; -import kr.co.mcmp.catalog.application.model.ApplicationStatus; -import kr.co.mcmp.catalog.application.service.ApplicationService; import kr.co.mcmp.oss.dto.OssDto; import kr.co.mcmp.oss.dto.OssTypeDto; import kr.co.mcmp.oss.service.OssService; +import kr.co.mcmp.softwarecatalog.application.model.ApplicationStatus; +import kr.co.mcmp.softwarecatalog.application.service.ApplicationService; import lombok.extern.slf4j.Slf4j; @Service @@ -28,9 +28,6 @@ public class AppProvEngineServiceImpl implements AppProvEngineService { @Autowired private JenkinsService jenkinsService; - - @Autowired - private ApplicationService applicationService; @Lazy @Autowired @@ -130,15 +127,15 @@ public String triggerJenkinsJob(JenkinsJobDto jobDto) { private void logJob(JenkinsJobDto jobDto){ - if (jobDto instanceof JenkinsJobDto.VmApplicationInstall) { - applicationService.logVmInstallation((JenkinsJobDto.VmApplicationInstall) jobDto, ApplicationStatus.INSTALL); - } else if (jobDto instanceof JenkinsJobDto.VmApplicationUninstall) { - applicationService.updateVmApplicationStatus((JenkinsJobDto.VmApplicationUninstall) jobDto, ApplicationStatus.UNINSTALL); - } else if (jobDto instanceof JenkinsJobDto.HelmChartInstall) { - applicationService.logK8sInstallation((JenkinsJobDto.HelmChartInstall) jobDto, ApplicationStatus.INSTALL); - } else if (jobDto instanceof JenkinsJobDto.HelmChartUninstall) { - applicationService.updateK8sApplicationStatus((JenkinsJobDto.HelmChartUninstall) jobDto, ApplicationStatus.UNINSTALL); - } + // if (jobDto instanceof JenkinsJobDto.VmApplicationInstall) { + // applicationService.logVmInstallation((JenkinsJobDto.VmApplicationInstall) jobDto, ApplicationStatus.INSTALL); + // } else if (jobDto instanceof JenkinsJobDto.VmApplicationUninstall) { + // applicationService.updateVmApplicationStatus((JenkinsJobDto.VmApplicationUninstall) jobDto, ApplicationStatus.UNINSTALL); + // } else if (jobDto instanceof JenkinsJobDto.HelmChartInstall) { + // applicationService.logK8sInstallation((JenkinsJobDto.HelmChartInstall) jobDto, ApplicationStatus.INSTALL); + // } else if (jobDto instanceof JenkinsJobDto.HelmChartUninstall) { + // applicationService.updateK8sApplicationStatus((JenkinsJobDto.HelmChartUninstall) jobDto, ApplicationStatus.UNINSTALL); + // } } private String makeTumblebugUri(String url, String port){ diff --git a/src/main/java/kr/co/mcmp/catalog/CatalogController.java b/src/main/java/kr/co/mcmp/catalog/CatalogController.java deleted file mode 100644 index 65e3dc5..0000000 --- a/src/main/java/kr/co/mcmp/catalog/CatalogController.java +++ /dev/null @@ -1,95 +0,0 @@ -package kr.co.mcmp.catalog; - -import java.util.List; - -import kr.co.mcmp.response.ResponseWrapper; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RequestPart; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.multipart.MultipartFile; - -import io.swagger.annotations.ApiOperation; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import lombok.extern.log4j.Log4j2; - -@Tag(name="software catalog crud", description="software catalog 정보 입력, 수정 외") -@RestController -@Log4j2 -@RequestMapping("/catalog/software") -public class CatalogController { - - - @Autowired - CatalogService catalogService; - -// @ApiOperation(value="software catalog list(all)", notes="software catalog 리스트 불러오기") -// @Operation(summary = "get software catalog list") -// @GetMapping("/") -// public List getCatalogList(){ -// return catalogService.getCatalogList(); -// } - - - @ApiOperation(value="software catalog list(all)", notes="software catalog 리스트 불러오기") - @Operation(summary = "get software catalog list") - @GetMapping - public ResponseWrapper> getCatalogList(@RequestParam(required = false) String title){ - if(StringUtils.isEmpty(title)){ - return new ResponseWrapper<>(catalogService.getCatalogList()); - }else { - return new ResponseWrapper<>(catalogService.getCatalogListSearch(title)); - } - } - - @Operation(summary = "software catalogd detail(and reference)") - @ApiOperation(value="software catalog detail", notes="software catalog 내용 확인(연결된 정보들까지)") - @GetMapping("/{catalogIdx}") - public ResponseWrapper getCatalog(@PathVariable Integer catalogIdx){ - return new ResponseWrapper<>(catalogService.getCatalog(catalogIdx)); - } - - @Operation(summary = "create software catalog", description = "Insert a software catalog with an optional icon file.") - @ApiOperation(value="software catalog insert", notes="software catalog 등록") - @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public ResponseWrapper createCatalog( - @RequestPart(value = "catalogDto") CatalogDTO catalogDto, - @RequestPart(value ="iconFile", required = false) MultipartFile iconFile) - { - return new ResponseWrapper<>(catalogService.createCatalog(catalogDto, iconFile)); - } - - @Operation(summary = "delete software catalog") - @ApiOperation(value="software catalog delete", notes="software catalog 삭제") - @DeleteMapping("/{catalogIdx}") - public ResponseWrapper deleteCatalog(@PathVariable Integer catalogIdx){ - return new ResponseWrapper(catalogService.deleteCatalog(catalogIdx)); - } - - // @Operation(summary = "update software catalog") - // @ApiOperation(value="software catalog update", notes="software catalog 수정") - // @PutMapping - // public boolean updateCatalog(@RequestBody CatalogDTO catalogDto, ){ - // return catalogService.updateCatalog(catalogDto); - // } - - @Operation(summary = "update software catalog") - @ApiOperation(value="software catalog update", notes="software catalog 수정") - @PutMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public ResponseWrapper updateCatalog( - @RequestPart("catalogDto") CatalogDTO catalogDto, - @RequestPart(value = "iconFile", required = false) MultipartFile iconFile) { - return new ResponseWrapper<>(catalogService.updateCatalog(catalogDto, iconFile)); - } - - -} diff --git a/src/main/java/kr/co/mcmp/catalog/CatalogDTO.java b/src/main/java/kr/co/mcmp/catalog/CatalogDTO.java deleted file mode 100644 index 310818a..0000000 --- a/src/main/java/kr/co/mcmp/catalog/CatalogDTO.java +++ /dev/null @@ -1,54 +0,0 @@ -package kr.co.mcmp.catalog; - -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.util.List; - -import javax.persistence.Column; - -import kr.co.mcmp.catalog.Ref.CatalogRefDTO; - -@Getter -@Setter -@NoArgsConstructor -public class CatalogDTO { - - private Integer catalogIdx; - private String catalogTitle; - private String catalogDescription; - private String catalogSummary; - private String catalogIcon; - private String catalogCategory; - private List catalogRefData; - - private Integer recommendedCpu; - private Integer recommendedMemory; - private Integer recommendedDisk; - - private Boolean enableHpa; - private Integer hpaMinReplicas; - private Integer hpaMaxReplicas; - private Integer hpaCpuUtilization; - private Integer hpaMemoryUtilization; - - public CatalogDTO(CatalogEntity cEntity){ - if(cEntity.getId() != null){ this.catalogIdx = cEntity.getId(); } - this.catalogTitle = cEntity.getTitle(); - this.catalogDescription = cEntity.getDescription(); - this.catalogSummary = cEntity.getSummary(); - this.catalogIcon = cEntity.getIcon(); - this.catalogCategory = cEntity.getCategory(); - this.recommendedCpu = cEntity.getRecommendedCpu(); - this.recommendedMemory = cEntity.getRecommendedMemory(); - this.recommendedDisk = cEntity.getRecommendedDisk(); - this.enableHpa = cEntity.getEnableHpa(); - this.hpaMinReplicas = cEntity.getHpaMinReplicas(); - this.hpaMaxReplicas = cEntity.getHpaMaxReplicas(); - this.hpaCpuUtilization = cEntity.getHpaCpuUtilization(); - this.hpaMemoryUtilization = cEntity.getHpaMemoryUtilization(); - } - - -} diff --git a/src/main/java/kr/co/mcmp/catalog/CatalogEntity.java b/src/main/java/kr/co/mcmp/catalog/CatalogEntity.java deleted file mode 100644 index 1d2422f..0000000 --- a/src/main/java/kr/co/mcmp/catalog/CatalogEntity.java +++ /dev/null @@ -1,86 +0,0 @@ -package kr.co.mcmp.catalog; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Table; - -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Entity -@Getter -@Setter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@Table(name="SOFTWARE_CATALOG") -//@ToString(exclude = {"SOFTWARE_CATALOG"}) -public class CatalogEntity { - - @Id - @GeneratedValue(strategy= GenerationType.IDENTITY) - @Column(columnDefinition="INT", name="ID") - private Integer id; - - @Column(columnDefinition="VARCHAR(200) NOT NULL DEFAULT ''", name="TITLE") - private String title; - - @Column(columnDefinition="VARCHAR(5000) NOT NULL DEFAULT ''", name="DESCRIPTION") - private String description; - - @Column(columnDefinition="VARCHAR(200) NOT NULL DEFAULT ''", name="SUMMARY") - private String summary; - - @Column(columnDefinition="VARCHAR(200) NOT NULL DEFAULT ''", name="ICON") - private String icon; - - @Column(columnDefinition="VARCHAR(15) NOT NULL DEFAULT ''", name="CATEGORY") - private String category; - - @Column(columnDefinition="INT", name = "RECOMMENDED_CPU", nullable = false) - private Integer recommendedCpu; - - @Column(columnDefinition="INT", name = "RECOMMENDED_MEMORY", nullable = false) - private Integer recommendedMemory; - - @Column(columnDefinition="INT", name = "RECOMMENDED_DISK", nullable = false) - private Integer recommendedDisk; - - @Column(columnDefinition="BOOLEAN", name = "ENABLE_HPA", nullable = false) - private Boolean enableHpa; - - @Column(columnDefinition="INT", name="HPA_MIN_REPLICAS", nullable = true) - private Integer hpaMinReplicas; - - @Column(columnDefinition="INT", name="HPA_MAX_REPLICAS", nullable = true) - private Integer hpaMaxReplicas; - - @Column(columnDefinition="INT", name="HPA_CPU_UTILIZATION", nullable = true) - private Integer hpaCpuUtilization; - - @Column(columnDefinition="INT", name="HPA_MEMORY_UTILIZATION", nullable = true) - private Integer hpaMemoryUtilization; - - public CatalogEntity(CatalogDTO cDto){ - if(cDto.getCatalogIdx() != null) { this.id = cDto.getCatalogIdx(); } - this.title = cDto.getCatalogTitle(); - this.description = cDto.getCatalogDescription(); - this.summary = cDto.getCatalogSummary(); - this.icon = cDto.getCatalogIcon(); - this.category = cDto.getCatalogCategory(); - this.recommendedCpu = cDto.getRecommendedCpu(); - this.recommendedMemory = cDto.getRecommendedMemory(); - this.recommendedDisk = cDto.getRecommendedDisk(); - this.enableHpa = cDto.getEnableHpa(); - this.hpaMinReplicas = cDto.getHpaMinReplicas(); - this.hpaMaxReplicas = cDto.getHpaMaxReplicas(); - this.hpaCpuUtilization = cDto.getHpaCpuUtilization(); - this.hpaMemoryUtilization = cDto.getHpaMemoryUtilization(); - } - - - -} diff --git a/src/main/java/kr/co/mcmp/catalog/CatalogRepository.java b/src/main/java/kr/co/mcmp/catalog/CatalogRepository.java deleted file mode 100644 index 0059737..0000000 --- a/src/main/java/kr/co/mcmp/catalog/CatalogRepository.java +++ /dev/null @@ -1,21 +0,0 @@ -package kr.co.mcmp.catalog; - -import java.util.List; -import java.util.Optional; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface CatalogRepository extends JpaRepository { - - void deleteById(Integer catalogIdx); - - List findByTitleLikeIgnoreCase(String title); - - // Optional findByTitleAndVersion(String title, String version); - - // List findByTitleContainingIgnoreCaseAndVersion(String title, String version); - - -} diff --git a/src/main/java/kr/co/mcmp/catalog/CatalogService.java b/src/main/java/kr/co/mcmp/catalog/CatalogService.java deleted file mode 100644 index 382a85d..0000000 --- a/src/main/java/kr/co/mcmp/catalog/CatalogService.java +++ /dev/null @@ -1,243 +0,0 @@ -package kr.co.mcmp.catalog; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -import javax.persistence.EntityNotFoundException; - -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.multipart.MultipartFile; - -import kr.co.mcmp.catalog.Ref.CatalogRefDTO; -import kr.co.mcmp.catalog.Ref.CatalogRefEntity; -import kr.co.mcmp.catalog.Ref.CatalogRefRepository; -import kr.co.mcmp.catalog.Ref.CatalogRefService; -import kr.co.mcmp.util.FileUtils; -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; - -@Service -@Log4j2 -@RequiredArgsConstructor -public class CatalogService { - - private final CatalogRepository catalogRepository; - - private final CatalogRefRepository catalogRefRepository; - - private final CatalogRefService catalogRefService; - - /** - * List 조회 - * @return List - */ - public List getCatalogList(){ - return catalogRepository.findAll() - .stream() - .map(ce -> { - CatalogDTO dto = new CatalogDTO(ce); - dto.setCatalogRefData(getCatalogDetail(dto.getCatalogIdx())); - return dto; - }).collect(Collectors.toList()); - } - - - /** - * catalogIdx 검색 CatalogDTO 조회 - * @param catalogIdx - * @return catalogIdx 일치하는 CatalogDTO - */ - public CatalogDTO getCatalog(Integer catalogIdx){ - return Optional.ofNullable(catalogIdx) - .map(idx -> { - CatalogEntity cEntity = catalogRepository.findById(idx).orElseThrow(() -> new EntityNotFoundException("nothing findById from catalogIdx") ); - CatalogDTO cDto = new CatalogDTO(cEntity); - cDto.setCatalogRefData(getCatalogDetail(idx)); - return cDto; - }).orElseThrow(() -> new IllegalArgumentException("catalog index is null")); - } - - /** - * 제목과 버전으로 CatalogDTO 조회 - * @param title - * @param version - * @return 제목과 버전에 일치하는 CatalogDTO - */ - // public CatalogDTO getCatalogByTitleAndVersion(String title, String version) { - // return catalogRepository.findByTitleAndVersion(title, version) - // .map(CatalogDTO::new) - // .orElseThrow(() -> new EntityNotFoundException("Catalog not found with title: " + title + " and version: " + version)); - // } - - /** - * 제목 키워드 검색을 통한 CatalogDTO 목록 조회 - * @param keyword - * @return 키워드와 일치하는 제목의 CatalogDTO List - */ - public List getCatalogListSearch(String keyword){ - return catalogRepository.findByTitleLikeIgnoreCase("%" + keyword + "%") - .stream() - .map(ce -> { - CatalogDTO dto = new CatalogDTO(ce); - dto.setCatalogRefData(getCatalogDetail(dto.getCatalogIdx())); - return dto; - }).collect(Collectors.toList()); - } - - /** - * 제목과 버전으로 CatalogDTO 목록 조회 - * @param title - * @param version - * @return 제목을 포함하고 버전에 일치하는 CatalogDTO List - */ - // public List getCatalogsByTitleAndVersion(String title, String version) { - // return catalogRepository.findByTitleContainingIgnoreCaseAndVersion(title, version) - // .stream() - // .map(CatalogDTO::new) - // .collect(Collectors.toList()); - // } - - - /** - * CatalogRefDTO 조회 - * @param catalogIdx - * @return List - */ - public List getCatalogDetail(Integer catalogIdx){ - // TODO JPA join 필요.. - return Optional.ofNullable(catalogRefRepository.findByCatalogId(catalogIdx)) - .orElseGet(Collections::emptyList) - .stream() - .sorted(Comparator.comparing(CatalogRefEntity::getId)) - .map(CatalogRefDTO::new) - .collect(Collectors.toList()); - } - - /** - * catalog, catalogRef 생성 - * @param cDto - * @param iconFile - * @return CatalogDTO - */ - @Transactional - public CatalogDTO createCatalog(CatalogDTO cDto, MultipartFile iconFile){ - try { - Optional.ofNullable(iconFile) - .filter(file -> !file.isEmpty()) - .ifPresent(file -> { - try { - String iconPath = FileUtils.uploadIcon(iconFile); - cDto.setCatalogIcon(iconPath); - } catch (IOException e) { - throw new UncheckedIOException("Failed to upload icon", e); - } - }); - - CatalogEntity cEntity = catalogRepository.save(new CatalogEntity(cDto)); - cDto.setCatalogIdx(cEntity.getId()); - - Optional.ofNullable(cDto.getCatalogRefData()) - .filter(refData -> !refData.isEmpty()) - .ifPresent(refData ->{ - List refEntities = refData.stream().map(crDto -> { - crDto.setCatalogIdx(cEntity.getId()); - return new CatalogRefEntity(crDto); - }).toList(); - catalogRefRepository.saveAll(refEntities); - }); - return cDto; - } catch (UncheckedIOException e) { - log.error("Error creating catalog : {}", e.getMessage()); - throw new IllegalArgumentException("Failed to create catalog", e); - } - } - - - /** - * Catalog, CatalogRef 삭제 - * @param catalogIdx - * @return Boolean - */ - @Transactional - public boolean deleteCatalog(Integer catalogIdx){ - return catalogRepository.findById(catalogIdx) - .map(catalog -> { - /* CatalogRef 항목들 삭제 */ - catalogRefRepository.deleteAllByCatalogId(catalogIdx); - /* Catalog 삭제 */ - catalogRepository.delete(catalog); - - return true; - }).orElseThrow(() -> new EntityNotFoundException("Catalog not found with id: " + catalogIdx)); - } - - /** - * Catalog, catalogRef 수정 - * @param catalogDto - * @return Boolean - */ - @Transactional - public boolean updateCatalog(CatalogDTO catalogDto){ - return catalogRepository.findById(catalogDto.getCatalogIdx()) - .map(catalogEntity ->{ - CatalogEntity updateEntity = catalogRepository.save(new CatalogEntity(catalogDto)); - /* CatalogRef 항목들 삭제 */ - catalogRefRepository.deleteAllByCatalogId(updateEntity.getId()); - - if(catalogDto.getCatalogRefData() != null){ - List newRefs = catalogDto.getCatalogRefData().stream().map(CatalogRefEntity::new).collect(Collectors.toList()); - catalogRefRepository.saveAll(newRefs); - } - return true; - }).orElseThrow(() -> new EntityNotFoundException("catalog not found with id : " + catalogDto.getCatalogIdx())); - } - - @Transactional - public boolean updateCatalog(CatalogDTO catalogDto, MultipartFile iconFile) { - return catalogRepository.findById(catalogDto.getCatalogIdx()) - .map(catalogEntity -> { - // 기존 아이콘 파일 삭제 - if (catalogEntity.getIcon() != null && !catalogEntity.getIcon().isEmpty()) { - FileUtils.deleteFile(catalogEntity.getIcon()); - } - - // 새 아이콘 파일 업로드 - Optional.ofNullable(iconFile) - .filter(file -> !file.isEmpty()) - .ifPresent(file -> { - try { - String iconPath = FileUtils.uploadIcon(file); - catalogDto.setCatalogIcon(iconPath); - } catch (IOException e) { - throw new UncheckedIOException("Failed to upload new icon", e); - } - }); - - CatalogEntity updateEntity = catalogRepository.save(new CatalogEntity(catalogDto)); - - // CatalogRef 항목들 삭제 - catalogRefRepository.deleteAllByCatalogId(updateEntity.getId()); - - // 새 CatalogRef 항목들 저장 - if (catalogDto.getCatalogRefData() != null) { - List newRefs = catalogDto.getCatalogRefData().stream() - .map(refDto -> { - refDto.setCatalogIdx(updateEntity.getId()); - return new CatalogRefEntity(refDto); - }) - .collect(Collectors.toList()); - catalogRefRepository.saveAll(newRefs); - } - return true; - }) - .orElseThrow(() -> new EntityNotFoundException("Catalog not found with id: " + catalogDto.getCatalogIdx())); - } - -} - diff --git a/src/main/java/kr/co/mcmp/catalog/Ref/CatalogRefController.java b/src/main/java/kr/co/mcmp/catalog/Ref/CatalogRefController.java deleted file mode 100644 index 2810bf8..0000000 --- a/src/main/java/kr/co/mcmp/catalog/Ref/CatalogRefController.java +++ /dev/null @@ -1,59 +0,0 @@ -package kr.co.mcmp.catalog.Ref; - -import io.swagger.annotations.ApiOperation; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; - -import kr.co.mcmp.response.ResponseWrapper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -@Tag(name="software catalog reference crud", description="software catalog 관련정보(workflow, homepage, 기타자료) 입력, 수정 외") -@RestController -@RequestMapping("/catalog/software/ref") -public class CatalogRefController { - - Logger logger = LoggerFactory.getLogger(CatalogRefController.class); - - @Autowired - CatalogRefService catalogRefService; - -// @ApiOperation(value="catalog ref workflow", notes="create workflows reference catalog") -// @Operation(summary = "create catalog reference workflow") -// @PostMapping("/workflow") -// public String createCatalogRefWorkflow(){ -// return null; -// } - - @Operation(summary = "execute catalog reference workflow") - @PostMapping("/workflow") - public ResponseWrapper execWorkflow(){ - return null; - } - - @Operation(summary = "delete catalog reference workflow") - @DeleteMapping("/{catalogIdx}/{catalogRefIdx}") - public ResponseWrapper deleteCatalogRefWorkflow(@PathVariable Integer catalogIdx, @PathVariable Integer catalogRefIdx){ - return new ResponseWrapper<>(false); - } - - @Operation(summary = "get catalog reference") - @GetMapping("/{catalogIdx}") - public List getCatalogReference(@PathVariable Integer catalogIdx){ - return null; - } - - @Operation(summary = "insert software catalog reference(webpage, workflow, etc...)") - @ApiOperation(value="software catalog ref insert", notes="software catalog 관련정보 등록(webpage, workflow 등)") - @PostMapping("/{catalogIdx}") - public CatalogRefDTO createCatalogRef(CatalogRefDTO crDto){ - return catalogRefService.createCatalogRef(crDto); - } - - - -} diff --git a/src/main/java/kr/co/mcmp/catalog/Ref/CatalogRefDTO.java b/src/main/java/kr/co/mcmp/catalog/Ref/CatalogRefDTO.java deleted file mode 100644 index 3448b54..0000000 --- a/src/main/java/kr/co/mcmp/catalog/Ref/CatalogRefDTO.java +++ /dev/null @@ -1,29 +0,0 @@ -package kr.co.mcmp.catalog.Ref; - -import lombok.Getter; -import lombok.Setter; - -@Getter -@Setter -public class CatalogRefDTO { - - private Integer catalogRefIdx; - private Integer catalogIdx; - private Integer referncetIdx; - private String referenceValue; // ref url, ref value, etc... - private String referenceDescription; - private String referenceType; // homepage, manifest, workflow, image, etc... - - public CatalogRefDTO(CatalogRefEntity crEntity){ - this.catalogRefIdx = crEntity.getId(); - this.catalogIdx = crEntity.getCatalogId(); - this.referncetIdx = crEntity.getRefIdx(); - this.referenceValue = crEntity.getRefValue(); - this.referenceDescription = crEntity.getRefDesc(); - this.referenceType = crEntity.getRefType(); - } - - public CatalogRefDTO(){ - - } -} diff --git a/src/main/java/kr/co/mcmp/catalog/Ref/CatalogRefEntity.java b/src/main/java/kr/co/mcmp/catalog/Ref/CatalogRefEntity.java deleted file mode 100644 index 2061746..0000000 --- a/src/main/java/kr/co/mcmp/catalog/Ref/CatalogRefEntity.java +++ /dev/null @@ -1,58 +0,0 @@ -package kr.co.mcmp.catalog.Ref; - -import lombok.*; - -import javax.persistence.*; - -@Entity -@Getter -@Setter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@Table(name="SOFTWARE_CATALOG_REF") -//@ToString(exclude = {"SOFTWARE_CATALOG_REF"}) -public class CatalogRefEntity { - - @Id - @GeneratedValue(strategy= GenerationType.IDENTITY) - @Column(columnDefinition="INT", name="ID") - private Integer id; - - // software catalog pk - @Column(columnDefinition="INT DEFAULT 1 NOT NULL", name="CATALOG_ID") - private Integer catalogId; - - // workflow등 idx, 타 catalog idx등 index reference일때 - @Column(columnDefinition="INT DEFAULT 0 NOT NULL", name="REF_IDX") - private Integer refIdx; - - // info url, 설정값 등 - @Column(columnDefinition="VARCHAR(200) DEFAULT '' NOT NULL", name="REF_VALUE") - private String refValue; // ref url, ref value, etc... - - // 짧은 description - @Column(columnDefinition="VARCHAR(200) DEFAULT ''", name="REF_DESC") - private String refDesc; - - // workflow, url, catalog - @Column(columnDefinition="VARCHAR(10) DEFAULT ''", name="REF_TYPE") - private String refType; - - public CatalogRefEntity(CatalogRefDTO crDto){ - this.catalogId = crDto.getCatalogIdx(); - this.refIdx = crDto.getReferncetIdx(); - this.refValue = crDto.getReferenceValue(); - this.refDesc = crDto.getReferenceDescription(); - this.refType = crDto.getReferenceType(); - } - -/* - INSERT INTO SOFTWARE_CATALOG_REF(CATALOG_ID, REF_IDX, REF_VALUE, REF_DESC, REF_TYPE) - VALUES - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'APACHE TOMCAT'), 0, 'https://tomcat.apache.org/', '', 'HOMEPAGE'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'REDIS'), 0, 'https://redis.io/', '', 'HOMEPAGE'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'NGINX'), 0, 'https://nginx.org/en/', '', 'HOMEPAGE') - -*/ - - -} diff --git a/src/main/java/kr/co/mcmp/catalog/Ref/CatalogRefService.java b/src/main/java/kr/co/mcmp/catalog/Ref/CatalogRefService.java deleted file mode 100644 index e154f7a..0000000 --- a/src/main/java/kr/co/mcmp/catalog/Ref/CatalogRefService.java +++ /dev/null @@ -1,34 +0,0 @@ -package kr.co.mcmp.catalog.Ref; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import kr.co.mcmp.catalog.CatalogRepository; -import lombok.RequiredArgsConstructor; - -@Service -@RequiredArgsConstructor -public class CatalogRefService { - - Logger logger = LoggerFactory.getLogger(CatalogRefService.class); - - private final CatalogRepository catalogRepository; - - private final CatalogRefRepository catalogRefRepository; - - public CatalogRefDTO createCatalogRef(CatalogRefDTO crDto){ - CatalogRefEntity crEntity = new CatalogRefEntity(crDto); - crEntity = catalogRefRepository.save(crEntity); - crDto.setCatalogRefIdx(crEntity.getId()); - return crDto; - } - - public boolean deleteCatalogRef(CatalogRefDTO crDto){ - catalogRefRepository.deleteById(crDto.getCatalogRefIdx()); - return true; - } - - -} diff --git a/src/main/java/kr/co/mcmp/catalog/application/controller/ApplicationController.java b/src/main/java/kr/co/mcmp/catalog/application/controller/ApplicationController.java deleted file mode 100644 index 11e7623..0000000 --- a/src/main/java/kr/co/mcmp/catalog/application/controller/ApplicationController.java +++ /dev/null @@ -1,72 +0,0 @@ -package kr.co.mcmp.catalog.application.controller; - -import java.util.List; - -import kr.co.mcmp.response.ResponseWrapper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import io.swagger.v3.oas.annotations.tags.Tag; -import kr.co.mcmp.catalog.application.dto.K8sApplicationHistoryDTO; -import kr.co.mcmp.catalog.application.dto.VmApplicationHistoryDTO; -import kr.co.mcmp.catalog.application.service.ApplicationService; - -@RestController -@RequestMapping("/applications") -@Tag(name="Installed application ", description="Vm, k8s 환경 설치된 Application 목록을 조회 합니다.") -public class ApplicationController { - - @Autowired - private ApplicationService applicationService; - - /** - * 특정 VM의 설치된 애플리케이션 기록 조회 - * @param namespace - * @param mciName - * @param vmName - * @return uninstall 상태가 아닌 애플리케이션 기록 목록 - */ - @GetMapping("/vm") - public ResponseEntity> getActiveVmApplications( - @RequestParam String namespace, - @RequestParam String mciName, - @RequestParam String vmName) { - List histories = applicationService.getActiveVmApplicationHistory(namespace, mciName, vmName); - return ResponseEntity.ok(histories); - } - - /** - * 특정 K8s 클러스터의 설치된 애플리케이션 기록 조회 - * @param namespace - * @param clusterName - * @return uninstall 상태가 아닌 애플리케이션 기록 목록 - */ - @GetMapping("/k8s") - public ResponseEntity> getActiveK8sApplications( - @RequestParam String namespace, - @RequestParam String clusterName) { - List histories = applicationService.getActiveK8sApplicationHistory(namespace, clusterName); - return ResponseEntity.ok(histories); - } - - @GetMapping("/vm/check/application") - public ResponseWrapper canInstallApplicationForVM(@RequestParam String namespace, - @RequestParam String mciName, - @RequestParam String vmName, - @RequestParam Integer catalogId) { - return new ResponseWrapper<>(applicationService.canInstallApplicationOnVm(namespace, mciName, vmName, catalogId)); - } - - @GetMapping("/k8s/check/application") - public ResponseWrapper canInstallApplicationForK8s(@RequestParam String namespace, - @RequestParam String clusterName, - @RequestParam Integer catalogId) { - return new ResponseWrapper<>(applicationService.canInstallApplicationOnK8s(namespace, clusterName, catalogId)); - } - - -} diff --git a/src/main/java/kr/co/mcmp/catalog/application/dto/K8sApplicationHistoryDTO.java b/src/main/java/kr/co/mcmp/catalog/application/dto/K8sApplicationHistoryDTO.java deleted file mode 100644 index f13c311..0000000 --- a/src/main/java/kr/co/mcmp/catalog/application/dto/K8sApplicationHistoryDTO.java +++ /dev/null @@ -1,36 +0,0 @@ -package kr.co.mcmp.catalog.application.dto; - -import java.time.LocalDateTime; - -import kr.co.mcmp.catalog.application.model.ApplicationStatus; -import kr.co.mcmp.catalog.application.model.K8sApplicationHistory; -import lombok.Builder; -import lombok.Data; - -@Data -@Builder -public class K8sApplicationHistoryDTO { - private Integer id; - private String namespace; - private String clusterName; - private Integer catalogId; - private String catalogName; - private ApplicationStatus status; - private LocalDateTime installedAt; - private LocalDateTime uninstalledAt; - private LocalDateTime updatedAt; - - public static K8sApplicationHistoryDTO fromEntity(K8sApplicationHistory entity) { - return K8sApplicationHistoryDTO.builder() - .id(entity.getId()) - .namespace(entity.getNamespace()) - .clusterName(entity.getClusterName()) - .catalogId(entity.getCatalog().getId()) - .catalogName(entity.getCatalog().getTitle()) - .status(entity.getStatus()) - .installedAt(entity.getInstalledAt()) - .uninstalledAt(entity.getUninstalledAt()) - .updatedAt(entity.getUpdatedAt()) - .build(); - } -} diff --git a/src/main/java/kr/co/mcmp/catalog/application/dto/VmApplicationHistoryDTO.java b/src/main/java/kr/co/mcmp/catalog/application/dto/VmApplicationHistoryDTO.java deleted file mode 100644 index 46e010b..0000000 --- a/src/main/java/kr/co/mcmp/catalog/application/dto/VmApplicationHistoryDTO.java +++ /dev/null @@ -1,45 +0,0 @@ -package kr.co.mcmp.catalog.application.dto; - -import java.time.LocalDateTime; - -import com.fasterxml.jackson.annotation.JsonProperty; - -import kr.co.mcmp.catalog.application.model.ApplicationStatus; -import kr.co.mcmp.catalog.application.model.VmApplicationHistory; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class VmApplicationHistoryDTO { - - private Integer id; - private String namespace; - private String mciName; - private String vmName; - private Integer catalogId; - private String catalogName; - private ApplicationStatus status; - private LocalDateTime installedAt; - private LocalDateTime uninstalledAt; - private LocalDateTime updatedAt; - - public static VmApplicationHistoryDTO fromEntity(VmApplicationHistory entity) { - return VmApplicationHistoryDTO.builder() - .id(entity.getId()) - .namespace(entity.getNamespace()) - .mciName(entity.getMciName()) - .vmName(entity.getVmName()) - .catalogId(entity.getCatalog().getId()) - .catalogName(entity.getCatalog().getTitle()) - .status(entity.getStatus()) - .installedAt(entity.getInstalledAt()) - .uninstalledAt(entity.getUninstalledAt()) - .updatedAt(entity.getUpdatedAt()) - .build(); - } -} diff --git a/src/main/java/kr/co/mcmp/catalog/application/model/ApplicationStatus.java b/src/main/java/kr/co/mcmp/catalog/application/model/ApplicationStatus.java deleted file mode 100644 index 571a578..0000000 --- a/src/main/java/kr/co/mcmp/catalog/application/model/ApplicationStatus.java +++ /dev/null @@ -1,18 +0,0 @@ -package kr.co.mcmp.catalog.application.model; - -import java.util.EnumSet; - -public enum ApplicationStatus { - INSTALL, - RUNNING, - SUSPEND, - STOP, - UNINSTALL; - - public static final EnumSet UPDATE_STATUSES = EnumSet.of( - RUNNING, - STOP, - SUSPEND - ); - } - diff --git a/src/main/java/kr/co/mcmp/catalog/application/model/K8sApplicationHistory.java b/src/main/java/kr/co/mcmp/catalog/application/model/K8sApplicationHistory.java deleted file mode 100644 index 29e5d48..0000000 --- a/src/main/java/kr/co/mcmp/catalog/application/model/K8sApplicationHistory.java +++ /dev/null @@ -1,62 +0,0 @@ -package kr.co.mcmp.catalog.application.model; - -import java.time.LocalDateTime; - -import javax.persistence.*; - -import kr.co.mcmp.catalog.CatalogEntity; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - - - -@Entity -@Getter -@Setter -@Builder -@NoArgsConstructor -@AllArgsConstructor -@Table(name="k8s_application_history") -public class K8sApplicationHistory { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Integer id; - - private String namespace; - @Column(name="cluster_name", nullable = false) - private String clusterName; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "catalog_id", nullable = false) - private CatalogEntity catalog; - - @Enumerated(EnumType.STRING) - @Column(name = "status", nullable = false) - private ApplicationStatus status; - - @Column(name = "hpa_enabled", nullable = false) - private boolean hpaEnabled; - - @Column(name = "hpa_min_replicas", nullable = true) - private Integer hpaMinReplicas; - - @Column(name = "hpa_max_replicas", nullable = true) - private Integer hpaMaxReplicas; - - @Column(name = "hpa_target_cpu_utilization_percentage", nullable = true) - private Integer hpaTargetCpuUtilizationPercentage; - - @Column(name = "hpa_target_memory_utilization_percentage", nullable = true) - private Integer hpaTargetMemoryUtilizationPercentage; - - @Column(name = "installed_at") - private LocalDateTime installedAt; - @Column(name = "uninstalled_at") - private LocalDateTime uninstalledAt; - @Column(name="updated_at") - private LocalDateTime updatedAt; -} diff --git a/src/main/java/kr/co/mcmp/catalog/application/model/VmApplicationHistory.java b/src/main/java/kr/co/mcmp/catalog/application/model/VmApplicationHistory.java deleted file mode 100644 index e632b58..0000000 --- a/src/main/java/kr/co/mcmp/catalog/application/model/VmApplicationHistory.java +++ /dev/null @@ -1,57 +0,0 @@ -package kr.co.mcmp.catalog.application.model; - -import java.time.LocalDateTime; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.Table; - -import kr.co.mcmp.catalog.CatalogEntity; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Entity -@Getter -@Setter -@NoArgsConstructor -@AllArgsConstructor -@Builder -@Table(name = "vm_application_history") -public class VmApplicationHistory { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Integer id; - - private String namespace; - @Column(name="mci_name", nullable = false) - private String mciName; - @Column(name="vm_name", nullable = false) - private String vmName; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "catalog_id", nullable = false) - private CatalogEntity catalog; - - @Enumerated(EnumType.STRING) - @Column(name = "status", nullable = false) - private ApplicationStatus status; - - @Column(name = "installed_at") - private LocalDateTime installedAt; - @Column(name = "uninstalled_at") - private LocalDateTime uninstalledAt; - @Column(name="updated_at") - private LocalDateTime updatedAt; -} diff --git a/src/main/java/kr/co/mcmp/catalog/application/repository/K8sApplicationHistoryRepository.java b/src/main/java/kr/co/mcmp/catalog/application/repository/K8sApplicationHistoryRepository.java deleted file mode 100644 index 46642a7..0000000 --- a/src/main/java/kr/co/mcmp/catalog/application/repository/K8sApplicationHistoryRepository.java +++ /dev/null @@ -1,27 +0,0 @@ -package kr.co.mcmp.catalog.application.repository; - -import java.util.List; -import java.util.Optional; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; - -import kr.co.mcmp.catalog.application.model.ApplicationStatus; -import kr.co.mcmp.catalog.application.model.K8sApplicationHistory; - -public interface K8sApplicationHistoryRepository extends JpaRepository { - - List findByNamespaceAndClusterNameAndStatusNot( - String namespace, String clusterName, ApplicationStatus status); - - @Query("SELECT k FROM K8sApplicationHistory k " + - "WHERE k.namespace = :namespace " + - "AND k.clusterName = :clusterName " + - "AND k.catalog.id = :catalogId " + - "AND k.status <> 'UNINSTALL'") - Optional findHistoryByUninstall( - @Param("namespace") String namespace, - @Param("clusterName") String clusterName, - @Param("catalogId") int catalogId); -} \ No newline at end of file diff --git a/src/main/java/kr/co/mcmp/catalog/application/repository/VmApplicationHistoryRepository.java b/src/main/java/kr/co/mcmp/catalog/application/repository/VmApplicationHistoryRepository.java deleted file mode 100644 index 8ce96b8..0000000 --- a/src/main/java/kr/co/mcmp/catalog/application/repository/VmApplicationHistoryRepository.java +++ /dev/null @@ -1,32 +0,0 @@ -package kr.co.mcmp.catalog.application.repository; - -import java.util.List; -import java.util.Optional; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; - -import kr.co.mcmp.catalog.application.model.ApplicationStatus; -import kr.co.mcmp.catalog.application.model.VmApplicationHistory; - -@Repository -public interface VmApplicationHistoryRepository extends JpaRepository { - - List findByNamespaceAndMciNameAndVmNameAndStatusNot( - String namespace, String mciName, String vmName, ApplicationStatus status); - - - @Query("SELECT v FROM VmApplicationHistory v " + - "WHERE v.namespace = :namespace " + - "AND v.mciName = :mciName " + - "AND v.vmName = :vmName " + - "AND v.catalog.id = :catalogId " + - "AND v.status <> 'UNINSTALL'") - Optional findHistoryByNotUninstall( - @Param("namespace") String namespace, - @Param("mciName") String mciName, - @Param("vmName") String vmName, - @Param("catalogId") int catalogId); -} diff --git a/src/main/java/kr/co/mcmp/catalog/application/service/ApplicationService.java b/src/main/java/kr/co/mcmp/catalog/application/service/ApplicationService.java deleted file mode 100644 index d49e97b..0000000 --- a/src/main/java/kr/co/mcmp/catalog/application/service/ApplicationService.java +++ /dev/null @@ -1,216 +0,0 @@ -package kr.co.mcmp.catalog.application.service; - -import java.time.LocalDateTime; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import kr.co.mcmp.ape.cbtumblebug.api.CbtumblebugRestApi; -import kr.co.mcmp.ape.cbtumblebug.dto.K8sClusterDto; -import kr.co.mcmp.ape.cbtumblebug.dto.K8sSpec; -import kr.co.mcmp.ape.cbtumblebug.dto.Spec; -import kr.co.mcmp.ape.cbtumblebug.dto.VmDto; -import kr.co.mcmp.ape.dto.reqDto.JenkinsJobDto; -import kr.co.mcmp.catalog.CatalogDTO; -import kr.co.mcmp.catalog.CatalogEntity; -import kr.co.mcmp.catalog.CatalogService; -import kr.co.mcmp.catalog.application.dto.K8sApplicationHistoryDTO; -import kr.co.mcmp.catalog.application.dto.VmApplicationHistoryDTO; -import kr.co.mcmp.catalog.application.model.ApplicationStatus; -import kr.co.mcmp.catalog.application.model.K8sApplicationHistory; -import kr.co.mcmp.catalog.application.model.VmApplicationHistory; -import kr.co.mcmp.catalog.application.repository.K8sApplicationHistoryRepository; -import kr.co.mcmp.catalog.application.repository.VmApplicationHistoryRepository; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -@Service -@Transactional -@Slf4j -@RequiredArgsConstructor -public class ApplicationService { - - private final VmApplicationHistoryRepository vmHistoryRepo; - private final K8sApplicationHistoryRepository k8sHistoryRepo; - private final CatalogService catalogService; - private final CbtumblebugRestApi cbtumblebugRestApi; - - public List getActiveVmApplicationHistory(String namespace, String mciName, String vmName) { - return vmHistoryRepo.findByNamespaceAndMciNameAndVmNameAndStatusNot(namespace, mciName, vmName, ApplicationStatus.UNINSTALL) - .stream() - .map(VmApplicationHistoryDTO::fromEntity) - .collect(Collectors.toList()); - } - - public List getActiveK8sApplicationHistory(String namespace, String clusterName) { - return k8sHistoryRepo.findByNamespaceAndClusterNameAndStatusNot(namespace, clusterName, ApplicationStatus.UNINSTALL) - .stream() - .map(K8sApplicationHistoryDTO::fromEntity) - .collect(Collectors.toList()); - } - - public boolean isVmResourcesSufficient(String namespace, String mciName, String vmName, int availableCpu, int availableMemory) { - List activeApplications = vmHistoryRepo.findByNamespaceAndMciNameAndVmNameAndStatusNot(namespace, mciName, vmName, ApplicationStatus.UNINSTALL); - - int totalRecommendedCpu = activeApplications.stream().mapToInt(app -> app.getCatalog().getRecommendedCpu()).sum(); - int totalRecommendedMemory = activeApplications.stream().mapToInt(app -> app.getCatalog().getRecommendedMemory()).sum(); - - return totalRecommendedCpu <= availableCpu && totalRecommendedMemory <= availableMemory; - } - - public boolean canInstallApplicationOnK8s(String namespace, String clusterName, Integer catalogId) { - CatalogDTO catalogDTO = catalogService.getCatalog(catalogId); - K8sClusterDto k8sClusterDto = cbtumblebugRestApi.getK8sClusterByName(namespace, clusterName); - - Optional vmSpecNameOpt = Optional.ofNullable(k8sClusterDto.getCspViewK8sClusterDetail()) - .map(K8sClusterDto.CspViewK8sClusterDetail::getNodeGroupList) - .flatMap(nodeGroups -> nodeGroups.stream().map(K8sClusterDto.NodeGroup::getVmSpecName).filter(StringUtils::isNotBlank).findFirst()); - - if (vmSpecNameOpt.isPresent()) { - K8sSpec spec = cbtumblebugRestApi.lookupSpec(k8sClusterDto.getConnectionName(), vmSpecNameOpt.get()); - int availableCpu = Integer.parseInt(spec.getVCpu().getCount()) - catalogDTO.getRecommendedCpu(); - int availableMemGib = convertMemoryToGb(spec.getMem()) - catalogDTO.getRecommendedMemory(); - - return isK8sResourcesSufficient(namespace, clusterName, availableCpu, availableMemGib); - } - - return false; - } - - public boolean canInstallApplicationOnVm(String namespace, String mciName, String vmName, Integer catalogId) { - CatalogDTO catalogDTO = catalogService.getCatalog(catalogId); - VmDto vmDto = cbtumblebugRestApi.getVmInfo(namespace, mciName, vmName); - Spec spec = cbtumblebugRestApi.getSpecBySpecId(namespace, vmDto.getSpecId()); - - int availableCpu = spec.getVCPU() - catalogDTO.getRecommendedCpu(); - int availableMemory = spec.getMemoryGiB() - catalogDTO.getRecommendedMemory(); - - return isVmResourcesSufficient(namespace, mciName, vmName, availableCpu, availableMemory); - } - - public boolean isK8sResourcesSufficient(String namespace, String clusterName, int availableCpu, int availableMemory) { - List activeApplications = k8sHistoryRepo.findByNamespaceAndClusterNameAndStatusNot(namespace, clusterName, ApplicationStatus.UNINSTALL); - - int totalRecommendedCpu = activeApplications.stream().mapToInt(app -> app.getCatalog().getRecommendedCpu()).sum(); - int totalRecommendedMemory = activeApplications.stream().mapToInt(app -> app.getCatalog().getRecommendedMemory()).sum(); - - return totalRecommendedCpu <= availableCpu && totalRecommendedMemory <= availableMemory; - } - - public void logVmInstallation(JenkinsJobDto.VmApplicationInstall jobDto, ApplicationStatus status) { - try { - CatalogDTO catalogDto = getCatalogFromApplication(jobDto.getApplications()); - VmApplicationHistory history = createVmApplicationHistory(jobDto, catalogDto, status); - vmHistoryRepo.save(history); - } catch (Exception e) { - log.error("VM 설치 로깅 중 오류 발생: " + e.getMessage()); - } - } - - public void updateVmApplicationStatus(JenkinsJobDto.VmApplicationUninstall jobDto, ApplicationStatus status) { - try { - CatalogDTO catalogDto = getCatalogFromApplication(jobDto.getApplications()); - Optional historyOpt = findActiveVmApplicationHistory(jobDto, catalogDto); - historyOpt.ifPresent(history -> updateAndSaveVmApplicationHistory(history, jobDto, status)); - } catch (Exception e) { - log.error("VM 애플리케이션 상태 업데이트 중 오류 발생: " + e.getMessage()); - } - } - - public void logK8sInstallation(JenkinsJobDto.HelmChartInstall jobDto, ApplicationStatus status) { - try { - CatalogDTO catalogDto = getCatalogFromHelmChart(jobDto.getHelmCharts()); - K8sApplicationHistory history = createK8sApplicationHistory(jobDto, catalogDto, status); - k8sHistoryRepo.save(history); - } catch (Exception e) { - log.error("K8S 설치 로깅 중 오류 발생: " + e.getMessage()); - } - } - - public void updateK8sApplicationStatus(JenkinsJobDto.HelmChartUninstall jobDto, ApplicationStatus status) { - try { - CatalogDTO catalogDto = getCatalogFromHelmChart(jobDto.getHelmCharts()); - Optional historyOpt = findActiveK8sApplicationHistory(jobDto, catalogDto); - historyOpt.ifPresent(history -> updateAndSaveK8sApplicationHistory(history, jobDto, status)); - } catch (Exception e) { - log.error("K8S 애플리케이션 상태 업데이트 중 오류 발생: " + e.getMessage()); - } - } - - private CatalogDTO getCatalogFromApplication(List applications) { - return catalogService.getCatalogListSearch(applications.get(0)) - .stream() - .findFirst() - .orElseThrow(() -> new RuntimeException("애플리케이션에 대한 카탈로그를 찾을 수 없습니다: " + applications)); - } - - private CatalogDTO getCatalogFromHelmChart(List helmCharts) { - return catalogService.getCatalogListSearch(helmCharts.get(0)) - .stream() - .findFirst() - .orElseThrow(() -> new RuntimeException("Helm 차트에 대한 카탈로그를 찾을 수 없습니다: " + helmCharts)); - } - - private VmApplicationHistory createVmApplicationHistory(JenkinsJobDto.VmApplicationInstall jobDto, CatalogDTO catalogDto, ApplicationStatus status) { - return VmApplicationHistory.builder() - .namespace(jobDto.getNamespace()) - .mciName(jobDto.getMciName()) - .vmName(jobDto.getVmName()) - .catalog(new CatalogEntity(catalogDto)) - .status(status) - .installedAt(LocalDateTime.now()) - .build(); - } - - private K8sApplicationHistory createK8sApplicationHistory(JenkinsJobDto.HelmChartInstall jobDto, CatalogDTO catalogDto, ApplicationStatus status) { - return K8sApplicationHistory.builder() - .namespace(jobDto.getNamespace()) - .clusterName(jobDto.getClusterName()) - .catalog(new CatalogEntity(catalogDto)) - .status(status) - .hpaEnabled(jobDto.isEnableHpa()) - .hpaMaxReplicas(jobDto.isEnableHpa() ? jobDto.getHpaMaxReplicas() : null) - .hpaMinReplicas(jobDto.isEnableHpa() ? jobDto.getHpaMinReplicas() : null) - .hpaTargetCpuUtilizationPercentage(jobDto.isEnableHpa() ? jobDto.getHpaCpuUtilization() : null) - .hpaTargetMemoryUtilizationPercentage(jobDto.isEnableHpa() ? jobDto.getHpaMemoryUtilization() : null) - .installedAt(LocalDateTime.now()) - .build(); - } - - private Optional findActiveVmApplicationHistory(JenkinsJobDto.VmApplicationUninstall jobDto, CatalogDTO catalogDto) { - return vmHistoryRepo.findHistoryByNotUninstall( - jobDto.getNamespace(), jobDto.getMciName(), jobDto.getVmName(), catalogDto.getCatalogIdx()); - } - - private Optional findActiveK8sApplicationHistory(JenkinsJobDto.HelmChartUninstall jobDto, CatalogDTO catalogDto) { - return k8sHistoryRepo.findHistoryByUninstall(jobDto.getNamespace(), jobDto.getClusterName(), catalogDto.getCatalogIdx()); - } - - private void updateAndSaveVmApplicationHistory(VmApplicationHistory history, JenkinsJobDto.VmApplicationUninstall jobDto, ApplicationStatus status) { - history.setStatus(status); - history.setUninstalledAt(status == ApplicationStatus.UNINSTALL ? LocalDateTime.now() : null); - history.setUpdatedAt(ApplicationStatus.UPDATE_STATUSES.contains(status) ? LocalDateTime.now() : null); - vmHistoryRepo.save(history); - } - - private void updateAndSaveK8sApplicationHistory(K8sApplicationHistory history, JenkinsJobDto.HelmChartUninstall jobDto, ApplicationStatus status) { - history.setStatus(status); - history.setUninstalledAt(status == ApplicationStatus.UNINSTALL ? LocalDateTime.now() : null); - history.setUpdatedAt(ApplicationStatus.UPDATE_STATUSES.contains(status) ? LocalDateTime.now() : null); - k8sHistoryRepo.save(history); - } - - private int convertMemoryToGb(String memoryInMb) { - try { - int memoryMb = Integer.parseInt(memoryInMb); - return memoryMb % 1024 == 0 ? memoryMb / 1024 : memoryMb; - } catch (NumberFormatException e) { - log.error("잘못된 메모리 크기: " + memoryInMb); - return -1; - } - } -} \ No newline at end of file diff --git a/src/main/java/kr/co/mcmp/config/SimpleCORSFilter.java b/src/main/java/kr/co/mcmp/config/SimpleCORSFilter.java index 6f18197..6155e6b 100644 --- a/src/main/java/kr/co/mcmp/config/SimpleCORSFilter.java +++ b/src/main/java/kr/co/mcmp/config/SimpleCORSFilter.java @@ -29,7 +29,7 @@ public void doFilter(ServletRequest req, ServletResponse res, response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Credentials", "true"); - response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT"); + response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT, PATCH"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN, token, user_id"); diff --git a/src/main/java/kr/co/mcmp/dto/oss/repository/CommonRepository.java b/src/main/java/kr/co/mcmp/dto/oss/repository/CommonRepository.java index 7c026e3..0a16933 100644 --- a/src/main/java/kr/co/mcmp/dto/oss/repository/CommonRepository.java +++ b/src/main/java/kr/co/mcmp/dto/oss/repository/CommonRepository.java @@ -3,20 +3,24 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Builder; +import lombok.Data; import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.ToString; import javax.validation.Valid; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; @Getter +@Data public class CommonRepository { @Getter @Builder @AllArgsConstructor @NoArgsConstructor + @ToString public static class RepositoryDto { @Schema(title = "레포지토리 이름", required = true, example = "repo") @@ -49,6 +53,7 @@ public static class RepositoryDto { @Builder @NoArgsConstructor @AllArgsConstructor + @ToString public static class StorageDto { @Schema(title = "아티팩트를 저장하는 물리적 저장소 이름", required = true, example = "default") @@ -68,6 +73,7 @@ public static class StorageDto { @Builder @NoArgsConstructor @AllArgsConstructor + @ToString public static class DockerDto { @Schema(title = "도커 registry 버전 지원(false: v2 지원)", required = true) diff --git a/src/main/java/kr/co/mcmp/externalrepo/ExternalRepoService.java b/src/main/java/kr/co/mcmp/externalrepo/ExternalRepoService.java index 71ea3b8..6b943df 100644 --- a/src/main/java/kr/co/mcmp/externalrepo/ExternalRepoService.java +++ b/src/main/java/kr/co/mcmp/externalrepo/ExternalRepoService.java @@ -3,12 +3,15 @@ import kr.co.mcmp.externalrepo.model.ArtifactHubPackage; import kr.co.mcmp.externalrepo.model.ArtifactHubRespository; import kr.co.mcmp.externalrepo.model.DockerHubCatalog; +import lombok.extern.slf4j.Slf4j; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service +@Slf4j public class ExternalRepoService { @Autowired @@ -23,7 +26,9 @@ public List searchArtifactHubRepository(String keyword){ } public ArtifactHubPackage searchArtifactHubPackage(String keyword){ - return artfInt.searchPackage(keyword, "0"); + ArtifactHubPackage test = artfInt.searchPackage(keyword, "0"); + log.info("ArtifactHubPackage : {}", test.toString()); + return test; } public DockerHubNamespace searchDockerHubNamespace(String keyword){ @@ -31,7 +36,9 @@ public DockerHubNamespace searchDockerHubNamespace(String keyword){ } public DockerHubCatalog searchDockerHubCatalog(String keyword){ - return dockerInt.searchCatalog(keyword); + DockerHubCatalog catalog = dockerInt.searchCatalog(keyword); + log.info("DockerHubCatalog : {}",catalog.toString()); + return catalog; //return null; } diff --git a/src/main/java/kr/co/mcmp/externalrepo/model/ArtifactHubPackage.java b/src/main/java/kr/co/mcmp/externalrepo/model/ArtifactHubPackage.java index 37cca07..cbccf8e 100644 --- a/src/main/java/kr/co/mcmp/externalrepo/model/ArtifactHubPackage.java +++ b/src/main/java/kr/co/mcmp/externalrepo/model/ArtifactHubPackage.java @@ -1,10 +1,12 @@ package kr.co.mcmp.externalrepo.model; import lombok.Data; +import lombok.ToString; import java.util.List; @Data +@ToString public class ArtifactHubPackage { private List packages; diff --git a/src/main/java/kr/co/mcmp/externalrepo/model/DockerHubCatalog.java b/src/main/java/kr/co/mcmp/externalrepo/model/DockerHubCatalog.java index a072a5d..7f15fb2 100644 --- a/src/main/java/kr/co/mcmp/externalrepo/model/DockerHubCatalog.java +++ b/src/main/java/kr/co/mcmp/externalrepo/model/DockerHubCatalog.java @@ -1,16 +1,18 @@ package kr.co.mcmp.externalrepo.model; import lombok.Data; +import lombok.ToString; import java.util.List; @Data +@ToString public class DockerHubCatalog { - + private int total; private List results; @Data - public static class Result{ + public static class Result { private String id; private String name; private String slug; @@ -20,31 +22,34 @@ public static class Result{ private String updated_at; private String short_description; private String source; + private int star_count; private List rate_plans; private LogoUrl logo_url; + private boolean extension_reviewed; private List categories; + private boolean archived; } @Data - public static class Publisher{ + public static class Publisher { private String id; private String name; } @Data - public static class LogoUrl{ + public static class LogoUrl { private String large; private String small; } @Data - public static class Category{ + public static class Category { private String name; private String slug; } @Data - public static class RatePlans{ + public static class RatePlans { private String id; private List repositories; private List operating_systems; @@ -52,25 +57,29 @@ public static class RatePlans{ } @Data - public static class Repository{ + public static class Repository { private String name; private String namespace; private String description; private String type; + private String pull_count; + private boolean is_automated; private boolean is_official; + private boolean is_trusted; private String last_pushed_at; + private String last_pulled_at; + private boolean archived; } @Data - public static class OperatingSystem{ + public static class OperatingSystem { private String name; private String label; } @Data - public static class Architecture{ + public static class Architecture { private String name; private String label; } - } diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/CatalogController.java b/src/main/java/kr/co/mcmp/softwarecatalog/CatalogController.java new file mode 100644 index 0000000..8f9abd7 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/CatalogController.java @@ -0,0 +1,195 @@ +package kr.co.mcmp.softwarecatalog; + +import java.util.List; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import kr.co.mcmp.response.ResponseCode; +import kr.co.mcmp.response.ResponseWrapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; + +@Tag(name="software catalog crud", description="software catalog 정보 입력, 수정 외") +@RestController +@Log4j2 +@RequestMapping("/catalog/software") +@RequiredArgsConstructor +public class CatalogController { + + + private final CatalogService catalogService; + + @Operation(summary = "카탈로그 생성") + @PostMapping + public ResponseEntity> createCatalog( + @RequestBody SoftwareCatalogDTO catalogDTO, + @RequestParam(required = false) String username) { + SoftwareCatalogDTO createdCatalog = catalogService.createCatalog(catalogDTO, username); + return ResponseEntity.status(HttpStatus.CREATED).body(new ResponseWrapper<>(createdCatalog)); + } + + @Operation(summary = "카탈로그 조회") + @GetMapping("/{catalogId}") + public ResponseEntity> getCatalog(@PathVariable Long catalogId) { + SoftwareCatalogDTO catalog = catalogService.getCatalog(catalogId); + return ResponseEntity.ok(new ResponseWrapper<>(catalog)); + } + + @Operation(summary = "모든 카탈로그 조회") + @GetMapping + public ResponseEntity>> getAllCatalogs() { + List catalogs = catalogService.getAllCatalogs(); + return ResponseEntity.ok(new ResponseWrapper<>(catalogs)); + } + + @Operation(summary = "카탈로그 업데이트") + @PutMapping("/{catalogId}") + public ResponseEntity> updateCatalog( + @PathVariable Long catalogId, + @RequestBody SoftwareCatalogDTO catalogDTO, + @RequestParam(required = false) String username) { + SoftwareCatalogDTO updatedCatalog = catalogService.updateCatalog(catalogId, catalogDTO, username); + return ResponseEntity.ok(new ResponseWrapper<>(updatedCatalog)); + } + + @Operation(summary = "카탈로그 삭제") + @DeleteMapping("/{catalogId}") + public ResponseEntity> deleteCatalog(@PathVariable Long catalogId) { + catalogService.deleteCatalog(catalogId); + return ResponseEntity.ok(new ResponseWrapper<>(ResponseCode.OK)); + } + + @Operation(summary = "Nexus 정보를 포함한 모든 카탈로그 조회") + @GetMapping("/combined") + public ResponseEntity>> getAllCatalogsWithNexusInfo() { + List combinedCatalogs = catalogService.getAllCatalogsWithNexusInfo(); + return ResponseEntity.ok(new ResponseWrapper<>(combinedCatalogs)); + } + + @Operation(summary = "Nexus 정보를 포함한 특정 카탈로그 조회") + @GetMapping("/{catalogId}/combined") + public ResponseEntity> getCatalogWithNexusInfo(@PathVariable Long catalogId) { + CombinedCatalogDTO combinedCatalog = catalogService.getCatalogWithNexusInfo(catalogId); + return ResponseEntity.ok(new ResponseWrapper<>(combinedCatalog)); + } + +/* + @Operation(summary = "카탈로그 생성") + @PostMapping + public ResponseEntity> createCatalog( + @RequestParam String source, + @RequestBody String jsonData, + @RequestParam String username, + @RequestBody SoftwareCatalogDTO catalogDTO) { + SoftwareCatalogDTO createdCatalog = catalogService.createCatalog(source, jsonData, username, catalogDTO); + return ResponseEntity.status(HttpStatus.CREATED).body(new ResponseWrapper<>(createdCatalog)); + } + + @Operation(summary = "카탈로그 조회") + @GetMapping("/{catalogId}") + public ResponseEntity> getCatalog(@PathVariable Long catalogId) { + SoftwareCatalogDTO catalog = catalogService.getCatalog(catalogId); + return ResponseEntity.ok(new ResponseWrapper<>(catalog)); + } + + @Operation(summary = "모든 카탈로그 조회") + @GetMapping + public ResponseEntity>> getAllCatalogs() { + List catalogs = catalogService.getAllCatalogs(); + return ResponseEntity.ok(new ResponseWrapper<>(catalogs)); + } + + @Operation(summary = "카탈로그 업데이트") + @PutMapping("/{catalogId}") + public ResponseEntity> updateCatalog( + @PathVariable Long catalogId, + @RequestParam String source, + @RequestBody String jsonData, + @RequestParam String username, + @RequestBody SoftwareCatalogDTO catalogDTO) { + SoftwareCatalogDTO updatedCatalog = catalogService.updateCatalog(catalogId, source, jsonData, username, catalogDTO); + return ResponseEntity.ok(new ResponseWrapper<>(updatedCatalog)); + } + + @Operation(summary = "카탈로그 삭제") + @DeleteMapping("/{catalogId}") + public ResponseEntity> deleteCatalog(@PathVariable Long catalogId) { + catalogService.deleteCatalog(catalogId); + return ResponseEntity.ok(new ResponseWrapper<>(ResponseCode.OK)); + } + + @Operation(summary = "Nexus 정보를 포함한 모든 카탈로그 조회") + @GetMapping("/combined") + public ResponseEntity>> getAllCatalogsWithNexusInfo() { + List combinedCatalogs = catalogService.getAllCatalogsWithNexusInfo(); + return ResponseEntity.ok(new ResponseWrapper<>(combinedCatalogs)); + } + + @Operation(summary = "Nexus 정보를 포함한 특정 카탈로그 조회") + @GetMapping("/{catalogId}/combined") + public ResponseEntity> getCatalogWithNexusInfo(@PathVariable Long catalogId) { + CombinedCatalogDTO combinedCatalog = catalogService.getCatalogWithNexusInfo(catalogId); + return ResponseEntity.ok(new ResponseWrapper<>(combinedCatalog)); + } + */ + // @ApiOperation(value="software catalog list(all)", notes="software catalog 리스트 불러오기") + // @Operation(summary = "get software catalog list") + // @GetMapping + // public List getCatalogList(@RequestParam(required = false) String title){ + // if(StringUtils.isEmpty(title)){ + // return catalogService.getCatalogList(); + // }else { + // return catalogService.getCatalogListSearch(title); + // } + // } + + // @Operation(summary = "software catalogd detail(and reference)") + // @ApiOperation(value="software catalog detail", notes="software catalog 내용 확인(연결된 정보들까지)") + // @GetMapping("/{catalogIdx}") + // public SoftwareCatalogDTO getCatalog(@PathVariable Long catalogIdx){ + // return catalogService.getCatalog(catalogIdx); + // } + + // @Operation(summary = "create software catalog", description = "Insert a software catalog with an optional icon file.") + // @ApiOperation(value="software catalog insert", notes="software catalog 등록") + // @PostMapping() + // public SoftwareCatalogDTO createCatalog( + // @RequestPart(value = "catalogDto") SoftwareCatalogDTO catalogDto) + // { + // return catalogService.createCatalog(catalogDto); + // } + + // @Operation(summary = "delete software catalog") + // @ApiOperation(value="software catalog delete", notes="software catalog 삭제") + // @DeleteMapping("/{catalogIdx}") + // public boolean deleteCatalog(@PathVariable Long catalogIdx){ + // return catalogService.deleteCatalog(catalogIdx); + // } + + // // @Operation(summary = "update software catalog") + // // @ApiOperation(value="software catalog update", notes="software catalog 수정") + // // @PutMapping + // // public boolean updateCatalog(@RequestBody CatalogDTO catalogDto, ){ + // // return catalogService.updateCatalog(catalogDto); + // // } + + // @Operation(summary = "update software catalog") + // @ApiOperation(value="software catalog update", notes="software catalog 수정") + // public SoftwareCatalogDTO updateCatalog(@RequestPart("catalogDto") SoftwareCatalogDTO catalogDto){ + // return catalogService.updateCatalog(catalogDto); + // } + + +} diff --git a/src/main/java/kr/co/mcmp/catalog/CatalogInterface.java b/src/main/java/kr/co/mcmp/softwarecatalog/CatalogInterface.java similarity index 52% rename from src/main/java/kr/co/mcmp/catalog/CatalogInterface.java rename to src/main/java/kr/co/mcmp/softwarecatalog/CatalogInterface.java index e659dd2..32dea35 100644 --- a/src/main/java/kr/co/mcmp/catalog/CatalogInterface.java +++ b/src/main/java/kr/co/mcmp/softwarecatalog/CatalogInterface.java @@ -1,4 +1,4 @@ -package kr.co.mcmp.catalog; +package kr.co.mcmp.softwarecatalog; public interface CatalogInterface { } diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/CatalogRepository.java b/src/main/java/kr/co/mcmp/softwarecatalog/CatalogRepository.java new file mode 100644 index 0000000..e66a610 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/CatalogRepository.java @@ -0,0 +1,30 @@ +package kr.co.mcmp.softwarecatalog; + +import java.util.List; +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +@Repository +public interface CatalogRepository extends JpaRepository { + + // void deleteById(Integer catalogIdx); + + // List findByTitleLikeIgnoreCase(String title); + + // Optional findByTitleAndVersion(String title, String version); + + // List findByTitleContainingIgnoreCaseAndVersion(String title, String version); + + @Query("SELECT sc FROM SoftwareCatalog sc LEFT JOIN FETCH sc.catalogRefs") + List findAllWithCatalogRefs(); + + @Query("SELECT sc FROM SoftwareCatalog sc LEFT JOIN FETCH sc.catalogRefs WHERE sc.id = :id") + Optional findByIdWithCatalogRefs(@Param("id") Long id); + + @Query("SELECT sc FROM SoftwareCatalog sc LEFT JOIN FETCH sc.catalogRefs WHERE LOWER(sc.title) LIKE LOWER(CONCAT('%', :keyword, '%'))") + List findByTitleContainingIgnoreCaseWithCatalogRefs(@Param("keyword") String keyword); +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/CatalogService.java b/src/main/java/kr/co/mcmp/softwarecatalog/CatalogService.java new file mode 100644 index 0000000..82a0eb3 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/CatalogService.java @@ -0,0 +1,274 @@ +package kr.co.mcmp.softwarecatalog; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import javax.persistence.EntityNotFoundException; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import kr.co.mcmp.dto.oss.repository.CommonRepository; +import kr.co.mcmp.service.oss.repository.CommonModuleRepositoryService; +import kr.co.mcmp.softwarecatalog.Ref.CatalogRefDTO; +import kr.co.mcmp.softwarecatalog.Ref.CatalogRefEntity; +import kr.co.mcmp.softwarecatalog.Ref.CatalogRefRepository; +import kr.co.mcmp.softwarecatalog.application.dto.HelmChartDTO; +import kr.co.mcmp.softwarecatalog.application.dto.PackageInfoDTO; +import kr.co.mcmp.softwarecatalog.application.model.HelmChart; +import kr.co.mcmp.softwarecatalog.application.model.PackageInfo; +import kr.co.mcmp.softwarecatalog.application.repository.HelmChartRepository; +import kr.co.mcmp.softwarecatalog.application.repository.PackageInfoRepository; +import kr.co.mcmp.softwarecatalog.users.Entity.User; +import kr.co.mcmp.softwarecatalog.users.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; + +@Service +@Log4j2 +@RequiredArgsConstructor +public class CatalogService { + + private final CatalogRepository catalogRepository; + private final CatalogRefRepository catalogRefRepository; + private final PackageInfoRepository packageInfoRepository; + private final HelmChartRepository helmChartRepository; + private final UserRepository userRepository; + private final CommonModuleRepositoryService moduleRepositoryService; + + + @Transactional + public SoftwareCatalogDTO createCatalog(SoftwareCatalogDTO catalogDTO, String username) { + User user = null; + if (StringUtils.isNotBlank(username)) { + user = getUserByUsername(username); + } + + SoftwareCatalog catalog = catalogDTO.toEntity(); + catalog.setRegisteredBy(user); + catalog.setCreatedAt(LocalDateTime.now()); + catalog.setUpdatedAt(LocalDateTime.now()); + + catalog = catalogRepository.save(catalog); + + if (catalogDTO.getCatalogRefs() != null && !catalogDTO.getCatalogRefs().isEmpty()) { + for (CatalogRefDTO refDTO : catalogDTO.getCatalogRefs()) { + CatalogRefEntity refEntity = refDTO.toEntity(); + refEntity.setCatalog(catalog); + catalogRefRepository.save(refEntity); + } + } + + if (catalogDTO.getPackageInfo() != null) { + savePackageInfo(catalog, catalogDTO.getPackageInfo()); + } else if (catalogDTO.getHelmChart() != null) { + saveHelmChart(catalog, catalogDTO.getHelmChart()); + } + + return SoftwareCatalogDTO.fromEntity(catalog); + } + + public SoftwareCatalogDTO getCatalog(Long catalogId) { + SoftwareCatalog catalog = catalogRepository.findById(catalogId) + .orElseThrow(() -> new EntityNotFoundException("Catalog not found")); + + SoftwareCatalogDTO dto = SoftwareCatalogDTO.fromEntity(catalog); + + List refs = catalogRefRepository.findByCatalogId(catalogId); + dto.setCatalogRefs(refs.stream().map(CatalogRefDTO::fromEntity).collect(Collectors.toList())); + + packageInfoRepository.findByCatalogId(catalogId).ifPresent(packageInfo -> dto.setPackageInfo(PackageInfoDTO.fromEntity(packageInfo))); + + helmChartRepository.findByCatalogId(catalogId).ifPresent(helmChart -> dto.setHelmChart(HelmChartDTO.fromEntity(helmChart))); + + return dto; + } + + public List getAllCatalogs() { + List catalogs = catalogRepository.findAll(); + List dtos = new ArrayList<>(); + + for (SoftwareCatalog catalog : catalogs) { + SoftwareCatalogDTO dto = SoftwareCatalogDTO.fromEntity(catalog); + + List refs = catalogRefRepository.findByCatalogId(catalog.getId()); + dto.setCatalogRefs(refs.stream().map(CatalogRefDTO::fromEntity).collect(Collectors.toList())); + + packageInfoRepository.findByCatalogId(catalog.getId()).ifPresent(packageInfo -> dto.setPackageInfo(PackageInfoDTO.fromEntity(packageInfo))); + + helmChartRepository.findByCatalogId(catalog.getId()) + .ifPresent(helmChart -> dto.setHelmChart(HelmChartDTO.fromEntity(helmChart))); + + dtos.add(dto); + } + + return dtos; + } + + @Transactional + public SoftwareCatalogDTO updateCatalog(Long catalogId, SoftwareCatalogDTO catalogDTO, String username) { + SoftwareCatalog catalog = catalogRepository.findById(catalogId) + .orElseThrow(() -> new EntityNotFoundException("Catalog not found")); + + User user = null; + if (StringUtils.isNotBlank(username)) { + user = getUserByUsername(username); + } + + updateCatalogFromDTO(catalog, catalogDTO, user); + catalog = catalogRepository.save(catalog); + + catalogRefRepository.deleteAllByCatalogId(catalogId); + if (catalogDTO.getCatalogRefs() != null && !catalogDTO.getCatalogRefs().isEmpty()) { + for (CatalogRefDTO refDTO : catalogDTO.getCatalogRefs()) { + CatalogRefEntity refEntity = refDTO.toEntity(); + refEntity.setCatalog(catalog); + catalogRefRepository.save(refEntity); + } + } + + if (catalogDTO.getPackageInfo() != null) { + updatePackageInfo(catalog, catalogDTO.getPackageInfo()); + } else if (catalogDTO.getHelmChart() != null) { + updateHelmChart(catalog, catalogDTO.getHelmChart()); + } + + return SoftwareCatalogDTO.fromEntity(catalog); + } + + @Transactional + public void deleteCatalog(Long catalogId) { + SoftwareCatalog catalog = catalogRepository.findById(catalogId) + .orElseThrow(() -> new EntityNotFoundException("Catalog not found")); + + catalogRefRepository.deleteAllByCatalogId(catalogId); + packageInfoRepository.deleteByCatalogId(catalogId); + helmChartRepository.deleteByCatalogId(catalogId); + catalogRepository.delete(catalog); + } + + private void updateCatalogFromDTO(SoftwareCatalog catalog, SoftwareCatalogDTO dto, User user) { + catalog.setTitle(dto.getTitle()); + catalog.setDescription(dto.getDescription()); + catalog.setCategory(dto.getCategory()); + catalog.setSourceType(dto.getSourceType()); + catalog.setLogoUrlLarge(dto.getLogoUrlLarge()); + catalog.setLogoUrlSmall(dto.getLogoUrlSmall()); + catalog.setSummary(dto.getSummary()); + catalog.setRegisteredBy(user); + catalog.setUpdatedAt(LocalDateTime.now()); + catalog.setMinCpu(dto.getMinCpu()); + catalog.setRecommendedCpu(dto.getRecommendedCpu()); + catalog.setMinMemory(dto.getMinMemory()); + catalog.setRecommendedMemory(dto.getRecommendedMemory()); + catalog.setMinDisk(dto.getMinDisk()); + catalog.setRecommendedDisk(dto.getRecommendedDisk()); + catalog.setCpuThreshold(dto.getCpuThreshold()); + catalog.setMemoryThreshold(dto.getMemoryThreshold()); + catalog.setMinReplicas(dto.getMinReplicas()); + catalog.setMaxReplicas(dto.getMaxReplicas()); + } + + private User getUserByUsername(String username) { + return userRepository.findByUsername(username) + .orElseThrow(() -> new EntityNotFoundException("User not found with username: " + username)); + } + + private void savePackageInfo(SoftwareCatalog catalog, PackageInfoDTO packageInfoDTO) { + PackageInfo packageInfo = packageInfoDTO.toEntity(); + packageInfo.setCatalog(catalog); + packageInfoRepository.save(packageInfo); + } + + private void updatePackageInfo(SoftwareCatalog catalog, PackageInfoDTO packageInfoDTO) { + PackageInfo packageInfo = packageInfoRepository.findByCatalogId(catalog.getId()) + .orElse(new PackageInfo()); + packageInfo.updateFromDTO(packageInfoDTO); + packageInfo.setCatalog(catalog); + packageInfoRepository.save(packageInfo); + } + + private void saveHelmChart(SoftwareCatalog catalog, HelmChartDTO helmChartDTO) { + HelmChart helmChart = helmChartDTO.toEntity(); + helmChart.setCatalog(catalog); + helmChartRepository.save(helmChart); + } + + private void updateHelmChart(SoftwareCatalog catalog, HelmChartDTO helmChartDTO) { + HelmChart helmChart = helmChartRepository.findByCatalogId(catalog.getId()) + .orElse(new HelmChart()); + helmChart.updateFromDTO(helmChartDTO); + helmChart.setCatalog(catalog); + helmChartRepository.save(helmChart); + } + + public List getAllCatalogsWithNexusInfo() { + List dbCatalogs = catalogRepository.findAll(); + List nexusRepositories = moduleRepositoryService.getRepositoryList("nexus"); + + Map nexusRepoMap = nexusRepositories.stream() + .collect(Collectors.toMap(CommonRepository.RepositoryDto::getName, Function.identity())); + + log.info("Nexus Repository Map:"); + nexusRepoMap.forEach((key, value) -> { + log.info("Key: {}, Value: {}", key, value.toString()); + }); + + return dbCatalogs.stream() + .map(catalog -> { + CombinedCatalogDTO combinedDTO = new CombinedCatalogDTO(); + combinedDTO.setSoftwareCatalogDTO(getSoftwareCatalogDTO(catalog)); + + CommonRepository.RepositoryDto nexusRepo = nexusRepoMap.get(catalog.getTitle()); + if (nexusRepo != null) { + combinedDTO.setRepositoryDTO(nexusRepo); + } + + return combinedDTO; + }) + .collect(Collectors.toList()); + } + + public CombinedCatalogDTO getCatalogWithNexusInfo(Long catalogId) { + SoftwareCatalog catalog = catalogRepository.findById(catalogId) + .orElseThrow(() -> new EntityNotFoundException("Catalog not found")); + + SoftwareCatalogDTO catalogDTO = getSoftwareCatalogDTO(catalog); + + List nexusRepositories = moduleRepositoryService.getRepositoryList("nexus"); + CommonRepository.RepositoryDto nexusRepo = nexusRepositories.stream() + .filter(repo -> repo.getName().equals(catalog.getTitle())) + .findFirst() + .orElse(null); + + CombinedCatalogDTO combinedDTO = new CombinedCatalogDTO(); + combinedDTO.setSoftwareCatalogDTO(catalogDTO); + combinedDTO.setRepositoryDTO(nexusRepo); + + return combinedDTO; + } + + private SoftwareCatalogDTO getSoftwareCatalogDTO(SoftwareCatalog catalog) { + SoftwareCatalogDTO dto = SoftwareCatalogDTO.fromEntity(catalog); + + List refDTOs = catalogRefRepository.findByCatalogId(catalog.getId()).stream() + .map(CatalogRefDTO::fromEntity) + .collect(Collectors.toList()); + dto.setCatalogRefs(refDTOs); + + packageInfoRepository.findByCatalogId(catalog.getId()) + .ifPresent(packageInfo -> dto.setPackageInfo(PackageInfoDTO.fromEntity(packageInfo))); + + helmChartRepository.findByCatalogId(catalog.getId()) + .ifPresent(helmChart -> dto.setHelmChart(HelmChartDTO.fromEntity(helmChart))); + + return dto; + } + +} + diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/CombinedCatalogDTO.java b/src/main/java/kr/co/mcmp/softwarecatalog/CombinedCatalogDTO.java new file mode 100644 index 0000000..84b65c2 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/CombinedCatalogDTO.java @@ -0,0 +1,13 @@ +package kr.co.mcmp.softwarecatalog; + +import kr.co.mcmp.dto.oss.repository.CommonRepository; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class CombinedCatalogDTO { + + SoftwareCatalogDTO softwareCatalogDTO; + CommonRepository.RepositoryDto repositoryDTO; +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/Ref/CatalogRefController.java b/src/main/java/kr/co/mcmp/softwarecatalog/Ref/CatalogRefController.java new file mode 100644 index 0000000..b189d52 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/Ref/CatalogRefController.java @@ -0,0 +1,58 @@ +package kr.co.mcmp.softwarecatalog.Ref; + +import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Tag(name="software catalog reference crud", description="software catalog 관련정보(workflow, homepage, 기타자료) 입력, 수정 외") +@RestController +@RequestMapping("/catalog/software/ref") +public class CatalogRefController { + + Logger logger = LoggerFactory.getLogger(CatalogRefController.class); + + @Autowired + CatalogRefService catalogRefService; + +// @ApiOperation(value="catalog ref workflow", notes="create workflows reference catalog") +// @Operation(summary = "create catalog reference workflow") +// @PostMapping("/workflow") +// public String createCatalogRefWorkflow(){ +// return null; +// } + + // @Operation(summary = "execute catalog reference workflow") + // @PostMapping("/workflow") + // public String execWorkflow(){ + // return null; + // } + + // @Operation(summary = "delete catalog reference workflow") + // @DeleteMapping("/{catalogIdx}/{catalogRefIdx}") + // public boolean deleteCatalogRefWorkflow(@PathVariable Integer catalogIdx, @PathVariable Integer catalogRefIdx){ + // return false; + // } + + // @Operation(summary = "get catalog reference") + // @GetMapping("/{catalogIdx}") + // public List getCatalogReference(@PathVariable Integer catalogIdx){ + // return null; + // } + + // @Operation(summary = "insert software catalog reference(webpage, workflow, etc...)") + // @ApiOperation(value="software catalog ref insert", notes="software catalog 관련정보 등록(webpage, workflow 등)") + // @PostMapping("/{catalogIdx}") + // public CatalogRefDTO createCatalogRef(CatalogRefDTO crDto){ + // return catalogRefService.createCatalogRef(crDto); + // } + + + +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/Ref/CatalogRefDTO.java b/src/main/java/kr/co/mcmp/softwarecatalog/Ref/CatalogRefDTO.java new file mode 100644 index 0000000..5924010 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/Ref/CatalogRefDTO.java @@ -0,0 +1,38 @@ +package kr.co.mcmp.softwarecatalog.Ref; + +import lombok.*; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CatalogRefDTO { + private Long id; + private Long catalogId; // SoftwareCatalog의 ID를 저장 + private Integer refId; + private String refValue; + private String refDesc; + private String refType; + + public static CatalogRefDTO fromEntity(CatalogRefEntity entity) { + return CatalogRefDTO.builder() + .id(entity.getId()) + .catalogId(entity.getCatalog() != null ? entity.getCatalog().getId() : null) + .refId(entity.getRefId()) + .refValue(entity.getRefValue()) + .refDesc(entity.getRefDesc()) + .refType(entity.getRefType()) + .build(); + } + + public CatalogRefEntity toEntity() { + return CatalogRefEntity.builder() + .id(this.id) + .refId(this.refId) + .refValue(this.refValue) + .refDesc(this.refDesc) + .refType(this.refType) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/Ref/CatalogRefEntity.java b/src/main/java/kr/co/mcmp/softwarecatalog/Ref/CatalogRefEntity.java new file mode 100644 index 0000000..927b8cb --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/Ref/CatalogRefEntity.java @@ -0,0 +1,37 @@ +package kr.co.mcmp.softwarecatalog.Ref; + +import kr.co.mcmp.softwarecatalog.SoftwareCatalog; +import lombok.*; + +import javax.persistence.*; + +@Entity +@Getter +@Setter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +@Builder +@Table(name="SOFTWARE_CATALOG_REF") +public class CatalogRefEntity { + + @Id + @GeneratedValue(strategy= GenerationType.IDENTITY) + @Column(columnDefinition="INT", name="ID") + private Long id; // CatalogRef의 고유 식별자 + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "CATALOG_ID") + private SoftwareCatalog catalog; // 이 CatalogRef가 속한 소프트웨어 카탈로그 + + @Column(columnDefinition="INT DEFAULT 0 NOT NULL", name="REF_IDX") + private Integer refId; // 참조 인덱스 + + @Column(columnDefinition="VARCHAR(200) DEFAULT '' NOT NULL", name="REF_VALUE") + private String refValue; // 참조 값 (URL 등) + + @Column(columnDefinition="VARCHAR(200) DEFAULT ''", name="REF_DESC") + private String refDesc; // 참조 설명 + + @Column(columnDefinition="VARCHAR(10) DEFAULT ''", name="REF_TYPE") + private String refType; // 참조 유형 (예: WORKFLOW, URL 등) +} \ No newline at end of file diff --git a/src/main/java/kr/co/mcmp/catalog/Ref/CatalogRefInterface.java b/src/main/java/kr/co/mcmp/softwarecatalog/Ref/CatalogRefInterface.java similarity index 51% rename from src/main/java/kr/co/mcmp/catalog/Ref/CatalogRefInterface.java rename to src/main/java/kr/co/mcmp/softwarecatalog/Ref/CatalogRefInterface.java index 99cb432..06876ff 100644 --- a/src/main/java/kr/co/mcmp/catalog/Ref/CatalogRefInterface.java +++ b/src/main/java/kr/co/mcmp/softwarecatalog/Ref/CatalogRefInterface.java @@ -1,4 +1,4 @@ -package kr.co.mcmp.catalog.Ref; +package kr.co.mcmp.softwarecatalog.Ref; public interface CatalogRefInterface { } diff --git a/src/main/java/kr/co/mcmp/catalog/Ref/CatalogRefRepository.java b/src/main/java/kr/co/mcmp/softwarecatalog/Ref/CatalogRefRepository.java similarity index 64% rename from src/main/java/kr/co/mcmp/catalog/Ref/CatalogRefRepository.java rename to src/main/java/kr/co/mcmp/softwarecatalog/Ref/CatalogRefRepository.java index ee4e1a4..39f6f3a 100644 --- a/src/main/java/kr/co/mcmp/catalog/Ref/CatalogRefRepository.java +++ b/src/main/java/kr/co/mcmp/softwarecatalog/Ref/CatalogRefRepository.java @@ -1,4 +1,4 @@ -package kr.co.mcmp.catalog.Ref; +package kr.co.mcmp.softwarecatalog.Ref; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @@ -6,11 +6,11 @@ import java.util.List; @Repository -public interface CatalogRefRepository extends JpaRepository { +public interface CatalogRefRepository extends JpaRepository { - List findByCatalogId(Integer catalogId); + List findByCatalogId(Long catalogId); //List findByCatalogIdOrderByReferenceTypeAsc(Integer catalogId); - void deleteAllByCatalogId(Integer catalogIdx); + void deleteAllByCatalogId(Long catalogIdx); } diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/Ref/CatalogRefService.java b/src/main/java/kr/co/mcmp/softwarecatalog/Ref/CatalogRefService.java new file mode 100644 index 0000000..56e1c9e --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/Ref/CatalogRefService.java @@ -0,0 +1,34 @@ +package kr.co.mcmp.softwarecatalog.Ref; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import kr.co.mcmp.softwarecatalog.CatalogRepository; +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class CatalogRefService { + + Logger logger = LoggerFactory.getLogger(CatalogRefService.class); + + private final CatalogRepository catalogRepository; + + private final CatalogRefRepository catalogRefRepository; + + // public CatalogRefDTO createCatalogRef(CatalogRefDTO crDto){ + // CatalogRefEntity crEntity = new CatalogRefEntity(crDto); + // crEntity = catalogRefRepository.save(crEntity); + // crDto.setCatalogRefIdx(crEntity.getId()); + // return crDto; + // } + + // public boolean deleteCatalogRef(CatalogRefDTO crDto){ + // catalogRefRepository.deleteById(crDto.getCatalogRefIdx()); + // return true; + // } + + +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/SoftwareCatalog.java b/src/main/java/kr/co/mcmp/softwarecatalog/SoftwareCatalog.java new file mode 100644 index 0000000..a3f677e --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/SoftwareCatalog.java @@ -0,0 +1,130 @@ +package kr.co.mcmp.softwarecatalog; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.CascadeType; +import javax.persistence.CollectionTable; +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; +import javax.persistence.Table; + +import kr.co.mcmp.softwarecatalog.Ref.CatalogRefEntity; +import kr.co.mcmp.softwarecatalog.application.model.HelmChart; +import kr.co.mcmp.softwarecatalog.application.model.PackageInfo; +import kr.co.mcmp.softwarecatalog.users.Entity.User; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@Table(name="SOFTWARE_CATALOG") +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SoftwareCatalog { + + @Id + @GeneratedValue(strategy= GenerationType.IDENTITY) + @Column(columnDefinition="INT", name="ID") + private Long id; // 소프트웨어 카탈로그 고유 식별자 + + @Column(columnDefinition="VARCHAR(200) NOT NULL DEFAULT ''", name="TITLE") + private String title; // 소프트웨어 이름 + + @Column(columnDefinition="VARCHAR(15) NOT NULL DEFAULT ''", name="CATEGORY") + private String category; // 소프트웨어 카탈로그 (예 : DB, WAS 등) + + @Column(name = "source_type", nullable = true) + private String sourceType; // 소프트웨어의 출처 (예: DOCKERHUB, ARTIFACTHUB) + + @Column(columnDefinition="VARCHAR(5000) NOT NULL DEFAULT ''", name="DESCRIPTION") + private String description; // 상세 설명 + + @Column(name = "default_port") + private Integer defaultPort; + + @Column(name="logo_url_large") + private String logoUrlLarge; // 소프트웨어 로그 큰 이미지 URL + + @Column(name="logo_url_small") + private String logoUrlSmall; // 소프트웨어 로그 작은 이미지 URL + + @Column(columnDefinition="VARCHAR(200) NOT NULL DEFAULT ''", name="SUMMARY") + private String summary; + + @ManyToOne + @JoinColumn(name = "registered_by") + private User registeredBy; // 이 소프트웨어를 등록한 사용자 + + @Column(name = "created_at") + private LocalDateTime createdAt; // 소프트웨어 카탈로그 항목 생성 시간 + + @Column(name = "updated_at") + private LocalDateTime updatedAt; // 소프트웨어 카탈로그 항목 최종 수정 시간 + + @Column(name = "min_cpu") + private Double minCpu; // 최소 CPU 요구사항 + + @Column(name = "recommended_cpu") + private Double recommendedCpu; // 권장 CPU 사양 + + @Column(name = "min_memory") + private Long minMemory; // 최소 메모리 요구사항 + + @Column(name = "recommended_memory") + private Long recommendedMemory; // 권장 메모리 사양 + + @Column(name = "min_disk") + private Long minDisk; // 최소 디스크 요구사항 + + @Column(name = "recommended_disk") + private Long recommendedDisk; // 권장 디스크 사양 + + @Column(name ="hpa_enabled", nullable = true) + private Boolean hpaEnabled; + + @Column(name = "cpu_threshold") + private Double cpuThreshold; // CPU 임계값 + + @Column(name = "memory_threshold") + private Double memoryThreshold; // 메모리 임계값 + + @Column(name = "min_replicas") + private Integer minReplicas; // 최소 복제 수 + + @Column(name = "max_replicas") + private Integer maxReplicas; // 최대 복제 수 + + @OneToMany(mappedBy = "catalog", cascade = CascadeType.ALL, orphanRemoval = true) + private List catalogRefs = new ArrayList<>(); + + @OneToOne(mappedBy = "catalog", cascade = CascadeType.ALL, orphanRemoval = true) + private PackageInfo packageInfo; + + @OneToOne(mappedBy = "catalog", cascade = CascadeType.ALL, orphanRemoval = true) + private HelmChart helmChart; + + public void addCatalogRef(CatalogRefEntity catalogRef) { + this.catalogRefs.add(catalogRef); + catalogRef.setCatalog(this); + } + + public void removeCatalogRef(CatalogRefEntity catalogRef) { + this.catalogRefs.remove(catalogRef); + catalogRef.setCatalog(null); + } +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/SoftwareCatalogDTO.java b/src/main/java/kr/co/mcmp/softwarecatalog/SoftwareCatalogDTO.java new file mode 100644 index 0000000..46c3617 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/SoftwareCatalogDTO.java @@ -0,0 +1,123 @@ +package kr.co.mcmp.softwarecatalog; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +import kr.co.mcmp.softwarecatalog.Ref.CatalogRefDTO; +import kr.co.mcmp.softwarecatalog.application.dto.HelmChartDTO; +import kr.co.mcmp.softwarecatalog.application.dto.PackageInfoDTO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class SoftwareCatalogDTO { + + private Long id; + private String title; + private String description; + private String category; + private String summary; + private String sourceType; + private String logoUrlLarge; + private String logoUrlSmall; + private Long registeredById; + private Boolean hpaEnabled; + private Integer defaultPort; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; + private Double minCpu; + private Double recommendedCpu; + private Long minMemory; + private Long recommendedMemory; + private Long minDisk; + private Long recommendedDisk; + private Double cpuThreshold; + private Double memoryThreshold; + private Integer minReplicas; + private Integer maxReplicas; + private List catalogRefs; + private PackageInfoDTO packageInfo; + private HelmChartDTO helmChart; + + public static SoftwareCatalogDTO fromEntity(SoftwareCatalog entity) { + SoftwareCatalogDTO.SoftwareCatalogDTOBuilder builder = SoftwareCatalogDTO.builder() + .id(entity.getId()) + .title(entity.getTitle()) + .description(entity.getDescription()) + .category(entity.getCategory()) + .defaultPort(entity.getDefaultPort()) + .sourceType(entity.getSourceType()) + .logoUrlLarge(entity.getLogoUrlLarge()) + .logoUrlSmall(entity.getLogoUrlSmall()) + // .registeredById(entity.getRegisteredBy().getId()) + .createdAt(entity.getCreatedAt()) + .updatedAt(entity.getUpdatedAt()) + .summary(entity.getSummary()) + .hpaEnabled(entity.getHpaEnabled()) + .minCpu(entity.getMinCpu()) + .recommendedCpu(entity.getRecommendedCpu()) + .minMemory(entity.getMinMemory()) + .recommendedMemory(entity.getRecommendedMemory()) + .minDisk(entity.getMinDisk()) + .recommendedDisk(entity.getRecommendedDisk()) + .cpuThreshold(entity.getCpuThreshold()) + .memoryThreshold(entity.getMemoryThreshold()) + .minReplicas(entity.getMinReplicas()) + .maxReplicas(entity.getMaxReplicas()); + + if (entity.getRegisteredBy() != null) { + builder.registeredById(entity.getRegisteredBy().getId()); + } + + SoftwareCatalogDTO dto = builder.build(); + if (entity.getCatalogRefs() != null) { + dto.setCatalogRefs(entity.getCatalogRefs().stream() + .map(CatalogRefDTO::fromEntity) + .collect(Collectors.toList())); + } + return dto; + } + + public SoftwareCatalog toEntity() { + SoftwareCatalog entity = SoftwareCatalog.builder() + .id(this.id) + .title(this.title) + .description(this.description) + .category(this.category) + .defaultPort(this.defaultPort) + .sourceType(this.sourceType) + .logoUrlLarge(this.logoUrlLarge) + .logoUrlSmall(this.logoUrlSmall) + .createdAt(this.createdAt) + .updatedAt(this.updatedAt) + .summary(this.summary) + .minCpu(this.minCpu) + .hpaEnabled(this.hpaEnabled) + .recommendedCpu(this.recommendedCpu) + .minMemory(this.minMemory) + .recommendedMemory(this.recommendedMemory) + .minDisk(this.minDisk) + .recommendedDisk(this.recommendedDisk) + .cpuThreshold(this.cpuThreshold) + .memoryThreshold(this.memoryThreshold) + .minReplicas(this.minReplicas) + .maxReplicas(this.maxReplicas) + .build(); + if (this.catalogRefs != null) { + entity.setCatalogRefs(this.catalogRefs.stream() + .map(CatalogRefDTO::toEntity) + .collect(Collectors.toList())); + } + + return entity; + } + +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/constants/ActionType.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/constants/ActionType.java new file mode 100644 index 0000000..f6374f5 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/constants/ActionType.java @@ -0,0 +1,5 @@ +package kr.co.mcmp.softwarecatalog.application.constants; + +public enum ActionType { + INSTALL, UNINSTALL, RUN, RESTART, STOP +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/constants/DeploymentType.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/constants/DeploymentType.java new file mode 100644 index 0000000..31a2f9a --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/constants/DeploymentType.java @@ -0,0 +1,5 @@ +package kr.co.mcmp.softwarecatalog.application.constants; + +public enum DeploymentType { + K8S, VM, DOCKER, BAREMETAL, CLOUD +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/constants/EnvironmentType.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/constants/EnvironmentType.java new file mode 100644 index 0000000..ce95748 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/constants/EnvironmentType.java @@ -0,0 +1,5 @@ +package kr.co.mcmp.softwarecatalog.application.constants; + +public enum EnvironmentType { + K8s, VM +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/constants/JobType.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/constants/JobType.java new file mode 100644 index 0000000..53d5847 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/constants/JobType.java @@ -0,0 +1,5 @@ +package kr.co.mcmp.softwarecatalog.application.constants; + +public enum JobType { + INSTALL, UNINSTALL, RUN, RESTART, STOP +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/constants/LogType.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/constants/LogType.java new file mode 100644 index 0000000..83bfd7f --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/constants/LogType.java @@ -0,0 +1,5 @@ +package kr.co.mcmp.softwarecatalog.application.constants; + +public enum LogType { + INFO, WARNING, ERROR, CRITICAL, RESOURCE_THRESHOLD +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/constants/PackageType.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/constants/PackageType.java new file mode 100644 index 0000000..74c24e0 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/constants/PackageType.java @@ -0,0 +1,5 @@ +package kr.co.mcmp.softwarecatalog.application.constants; + +public enum PackageType { + JAR, WAR, DOCKER, HELM +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/constants/ScriptFormat.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/constants/ScriptFormat.java new file mode 100644 index 0000000..5f748e8 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/constants/ScriptFormat.java @@ -0,0 +1,5 @@ +package kr.co.mcmp.softwarecatalog.application.constants; + +public enum ScriptFormat { + XML, SHELL, GROOVY +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/constants/ScriptType.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/constants/ScriptType.java new file mode 100644 index 0000000..95b5929 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/constants/ScriptType.java @@ -0,0 +1,5 @@ +package kr.co.mcmp.softwarecatalog.application.constants; + +public enum ScriptType { + INSTALL, UNINSTALL, RUN, RESTART, STOP +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/controller/ApplicationController.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/controller/ApplicationController.java new file mode 100644 index 0000000..583e7a0 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/controller/ApplicationController.java @@ -0,0 +1,108 @@ +package kr.co.mcmp.softwarecatalog.application.controller; + +import java.util.List; +import java.util.Map; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import kr.co.mcmp.response.ResponseWrapper; +import kr.co.mcmp.softwarecatalog.application.constants.ActionType; +import kr.co.mcmp.softwarecatalog.application.dto.ApplicationStatusDto; +import kr.co.mcmp.softwarecatalog.application.model.DeploymentHistory; +import kr.co.mcmp.softwarecatalog.application.model.DeploymentLog; +import kr.co.mcmp.softwarecatalog.application.service.ApplicationService; +import lombok.RequiredArgsConstructor; + +@RestController +@RequestMapping("/applications") +@Tag(name="Installed application ", description = "VM 및 K8s 환경의 애플리케이션 관리 API") +@RequiredArgsConstructor +public class ApplicationController { + + private final ApplicationService applicationService; + + @Operation(summary = "VM에 애플리케이션 배포", description = "특정 VM에 애플리케이션을 배포합니다.") + @GetMapping("/vm/deploy") + public ResponseEntity> deployVmApplication( + @RequestParam String namespace,@RequestParam String mciId,@RequestParam String vmId,@RequestParam Long catalogId,@RequestParam Integer servicePort,@RequestParam(required = false) String username) { + DeploymentHistory result = applicationService.deployApplication(namespace, mciId, vmId, catalogId, servicePort, username); + return ResponseEntity.ok(new ResponseWrapper<>(result)); + } + + @Operation(summary = "K8s 클러스터에 애플리케이션 배포", description = "특정 K8s 클러스터에 애플리케이션을 배포합니다.") + @PostMapping("/k8s/deploy") + public ResponseEntity> deployK8sApplication( + @RequestParam String namespace, + @RequestParam String clusterName, + @RequestParam Long catalogId, + @RequestParam(required = false) String username) { + // DeploymentHistory result = applicationService.deployApplicationToK8s(namespace, clusterName, catalogId, username); + // return ResponseEntity.ok(new ResponseWrapper<>(result)); + return null; + } + + @Operation(summary = "VM 리소스 체크", description = "VM에 애플리케이션을 배포하기 위한 리소스가 충분한지 확인합니다.") + @GetMapping("/vm/check") + public ResponseEntity> checkVmSpec( + @RequestParam String namespace, + @RequestParam String mciId, + @RequestParam String vmId, + @RequestParam Long catalogId) { + boolean result = applicationService.checkSpecForVm(namespace, mciId, vmId, catalogId); + return ResponseEntity.ok(new ResponseWrapper<>(result)); + } + + @Operation(summary = "K8s 클러스터 리소스 체크", description = "K8s 클러스터에 애플리케이션을 배포하기 위한 리소스가 충분한지 확인합니다.") + @GetMapping("/k8s/check") + public ResponseEntity> checkK8sSpec( + @RequestParam String namespace, + @RequestParam String clusterName, + @RequestParam Long catalogId) { + boolean result = applicationService.checkSpecForK8s(namespace, clusterName, catalogId); + return ResponseEntity.ok(new ResponseWrapper<>(result)); + } + + @Operation(summary = "배포 이력 조회", description = "특정 카탈로그 ID에 대한 배포 이력을 조회합니다.") + @GetMapping("/history") + public ResponseEntity>> getDeploymentHistories(@RequestParam Long catalogId, @RequestParam(required = false) String username) { + List histories = applicationService.getDeploymentHistories(catalogId, username); + return ResponseEntity.ok(new ResponseWrapper<>(histories)); + } + + @Operation(summary = "배포 로그 조회", description = "특정 배포에 대한 로그를 조회합니다.") + @GetMapping("/logs") + public ResponseEntity>> getDeploymentLogs(@RequestParam Long deploymentId, @RequestParam(required = false) String username) { + List logs = applicationService.getDeploymentLogs(deploymentId, username); + return ResponseEntity.ok(new ResponseWrapper<>(logs)); + } + + @Operation(summary = "애플리케이션 상태 조회", description = "특정 카탈로그 ID에 대한 애플리케이션 상태를 조회합니다.") + @GetMapping("/status") + public ResponseEntity> getLatestApplicationStatus(@RequestParam(required = false) String username) { + ApplicationStatusDto status = applicationService.getLatestApplicationStatus(username); + return ResponseEntity.ok(new ResponseWrapper<>(status)); + } + + @Operation(summary = "VM 어플리케이션 상태 조회", description = "VM의 어플리케이션 상태를 조회 합니다.") + @GetMapping("/vm/groups") + public ResponseEntity>> getApplicationGroups() { + List list = applicationService.getApplicationGroups(); + return ResponseEntity.ok(new ResponseWrapper<>(list)); + } + + @Operation(summary = "VM 어플리케이션 동작", description = "어플리케이션 동작") + @GetMapping("/vm/action") + public ResponseEntity>> performDockerOperation(@RequestParam ActionType operation,@RequestParam Long applicationStatusId) throws Exception { + Map result = applicationService.performDockerOperation(operation, applicationStatusId); + return ResponseEntity.ok(new ResponseWrapper<>(result)); + } + + +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/dto/ApplicationStatusDto.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/dto/ApplicationStatusDto.java new file mode 100644 index 0000000..3820768 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/dto/ApplicationStatusDto.java @@ -0,0 +1,101 @@ +package kr.co.mcmp.softwarecatalog.application.dto; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.Column; + +import kr.co.mcmp.softwarecatalog.SoftwareCatalog; +import kr.co.mcmp.softwarecatalog.application.constants.DeploymentType; +import kr.co.mcmp.softwarecatalog.application.model.ApplicationStatus; +import kr.co.mcmp.softwarecatalog.users.Entity.User; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ApplicationStatusDto { + private Long id; + private Long catalogId; + private String applicationName; + private DeploymentType deploymentType; + private String namespace; + private String mciId; + private String vmId; + private String clusterName; + private String status; + private Double cpuUsage; + private Double memoryUsage; + private Double networkIn; + private Boolean isPortAccessible; + private Boolean isHealthCheck; + private String publicIp; + private Double networkOut; + private Integer servicePort; + private String podStatus; + private LocalDateTime checkedAt; + private Long executedById; + private List errorLogs; + + public static ApplicationStatusDto fromEntity(ApplicationStatus entity) { + return ApplicationStatusDto.builder() + .id(entity.getId()) + .catalogId(entity.getCatalog() != null ? entity.getCatalog().getId() : null) + .applicationName(entity.getCatalog() != null ? entity.getCatalog().getTitle() : null) + .deploymentType(entity.getDeploymentType()) + .namespace(entity.getNamespace()) + .mciId(entity.getMciId()) + .vmId(entity.getVmId()) + .clusterName(entity.getClusterName()) + .isPortAccessible(entity.getIsPortAccessible()) + .isHealthCheck(entity.getIsHealthCheck()) + .status(entity.getStatus()) + .cpuUsage(entity.getCpuUsage()) + .memoryUsage(entity.getMemoryUsage()) + .networkIn(entity.getNetworkIn()) + .publicIp(entity.getPublicIp()) + .networkOut(entity.getNetworkOut()) + .servicePort(entity.getServicePort()) + .podStatus(entity.getPodStatus()) + .checkedAt(entity.getCheckedAt()) + .executedById(entity.getExecutedBy() != null ? entity.getExecutedBy().getId() : null) + .errorLogs(new ArrayList<>(entity.getErrorLogs())) + .build(); + } + + public ApplicationStatus toEntity() { + ApplicationStatus entity = new ApplicationStatus(); + entity.setId(this.id); + entity.setDeploymentType(this.deploymentType); + entity.setStatus(this.status); + entity.setCpuUsage(this.cpuUsage); + entity.setMemoryUsage(this.memoryUsage); + entity.setNetworkIn(this.networkIn); + entity.setPublicIp(this.publicIp); + entity.setNetworkOut(this.networkOut); + entity.setServicePort(this.servicePort); + entity.setPodStatus(this.podStatus); + entity.setCheckedAt(this.checkedAt); + entity.setErrorLogs(new ArrayList<>(this.errorLogs)); + + if (this.catalogId != null) { + SoftwareCatalog catalog = new SoftwareCatalog(); + catalog.setId(this.catalogId); + entity.setCatalog(catalog); + } + if (this.executedById != null) { + User executedBy = new User(); + executedBy.setId(this.executedById); + entity.setExecutedBy(executedBy); + } + + return entity; + } +} \ No newline at end of file diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/dto/DeploymentHistoryDTO.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/dto/DeploymentHistoryDTO.java new file mode 100644 index 0000000..4a92849 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/dto/DeploymentHistoryDTO.java @@ -0,0 +1,51 @@ +package kr.co.mcmp.softwarecatalog.application.dto; + +import java.time.LocalDateTime; +import java.util.List; + +import kr.co.mcmp.softwarecatalog.application.constants.ActionType; +import kr.co.mcmp.softwarecatalog.application.constants.DeploymentType; +import kr.co.mcmp.softwarecatalog.application.model.DeploymentHistory; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +public class DeploymentHistoryDTO { + + private Long id; + private Long catalogId; + private DeploymentType deploymentType; + private String namespace; + private String mciId; + private String vmId; + private String clusterName; + private ActionType actionType; + private String status; + private LocalDateTime executedAt; + private Long executedById; + private String cloudProvider; + private String cloudRegion; + private Integer servicePort; + private String podStatus; + + public DeploymentHistoryDTO(DeploymentHistory entity) { + this.id = entity.getId(); + this.catalogId = entity.getCatalog().getId(); + this.deploymentType = entity.getDeploymentType(); + this.namespace = entity.getNamespace(); + this.mciId = entity.getMciId(); + this.vmId = entity.getVmId(); + this.clusterName = entity.getClusterName(); + this.actionType = entity.getActionType(); + this.status = entity.getStatus(); + this.executedAt = entity.getExecutedAt(); + this.executedById = entity.getExecutedBy().getId(); + this.cloudProvider = entity.getCloudProvider(); + this.cloudRegion = entity.getCloudRegion(); + this.servicePort = entity.getServicePort(); + this.podStatus = entity.getPodStatus(); + } +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/dto/HelmChartDTO.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/dto/HelmChartDTO.java new file mode 100644 index 0000000..6df8da1 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/dto/HelmChartDTO.java @@ -0,0 +1,56 @@ +package kr.co.mcmp.softwarecatalog.application.dto; + +import kr.co.mcmp.softwarecatalog.application.model.HelmChart; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class HelmChartDTO { + private Long id; + private Long catalogId; + private String chartName; + private String chartVersion; + private String chartRepositoryUrl; + private String valuesFile; + private String packageId; + private String normalizedName; + private Boolean hasValuesSchema; + private String repositoryName; + private Boolean repositoryOfficial; + private String repositoryDisplayName; + + public HelmChart toEntity() { + return HelmChart.builder() + .chartName(this.chartName) + .chartVersion(this.chartVersion) + .chartRepositoryUrl(this.chartRepositoryUrl) + .valuesFile(this.valuesFile) + .hasValuesSchema(this.hasValuesSchema) + .repositoryName(this.repositoryName) + .repositoryOfficial(this.repositoryOfficial) + .repositoryDisplayName(this.repositoryDisplayName) + .build(); + } + + public static HelmChartDTO fromEntity(HelmChart helmChart) { + return HelmChartDTO.builder() + .id(helmChart.getId()) + .catalogId(helmChart.getCatalog() != null ? helmChart.getCatalog().getId() : null) + .chartName(helmChart.getChartName()) + .chartVersion(helmChart.getChartVersion()) + .chartRepositoryUrl(helmChart.getChartRepositoryUrl()) + .valuesFile(helmChart.getValuesFile()) + .hasValuesSchema(helmChart.getHasValuesSchema()) + .repositoryName(helmChart.getRepositoryName()) + .repositoryOfficial(helmChart.getRepositoryOfficial()) + .repositoryDisplayName(helmChart.getRepositoryDisplayName()) + .build(); + } +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/dto/K8sApplicationHistoryDTO.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/dto/K8sApplicationHistoryDTO.java new file mode 100644 index 0000000..b55ee37 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/dto/K8sApplicationHistoryDTO.java @@ -0,0 +1,29 @@ +package kr.co.mcmp.softwarecatalog.application.dto; + +// @Data +// @Builder +public class K8sApplicationHistoryDTO { + // private Integer id; + // private String namespace; + // private String clusterName; + // private Integer catalogId; + // private String catalogName; + // private ApplicationStatus status; + // private LocalDateTime installedAt; + // private LocalDateTime uninstalledAt; + // private LocalDateTime updatedAt; + + // public static K8sApplicationHistoryDTO fromEntity(K8sApplicationHistory entity) { + // return K8sApplicationHistoryDTO.builder() + // .id(entity.getId()) + // .namespace(entity.getNamespace()) + // .clusterName(entity.getClusterName()) + // .catalogId(entity.getCatalog().getId()) + // .catalogName(entity.getCatalog().getTitle()) + // .status(entity.getStatus()) + // .installedAt(entity.getInstalledAt()) + // .uninstalledAt(entity.getUninstalledAt()) + // .updatedAt(entity.getUpdatedAt()) + // .build(); + // } +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/dto/PackageInfoDTO.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/dto/PackageInfoDTO.java new file mode 100644 index 0000000..1f7cc1e --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/dto/PackageInfoDTO.java @@ -0,0 +1,90 @@ +package kr.co.mcmp.softwarecatalog.application.dto; + +import java.time.LocalDateTime; + + +import kr.co.mcmp.softwarecatalog.application.constants.PackageType; +import kr.co.mcmp.softwarecatalog.application.model.PackageInfo; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class PackageInfoDTO { + private Long id; + private Long catalogId; + private PackageType packageType; + private String packageName; + private String packageVersion; + private String repositoryUrl; + private String dockerImageId; + private String dockerPublisher; + private LocalDateTime dockerCreatedAt; + private LocalDateTime dockerUpdatedAt; + private String dockerShortDescription; + private String dockerSource; + private Integer starCount; + private String pullCount; + private Boolean isOfficial; + private Boolean isAutomated; + private LocalDateTime lastPulledAt; + private Boolean isArchived; + private String operatingSystems; + private String architectures; + private String categories; + + public PackageInfo toEntity() { + return PackageInfo.builder() + .packageType(this.packageType) + .packageName(this.packageName) + .packageVersion(this.packageVersion) + .repositoryUrl(this.repositoryUrl) + .dockerImageId(this.dockerImageId) + .dockerPublisher(this.dockerPublisher) + .dockerCreatedAt(this.dockerCreatedAt) + .dockerUpdatedAt(this.dockerUpdatedAt) + .dockerShortDescription(this.dockerShortDescription) + .dockerSource(this.dockerSource) + .starCount(this.starCount) + .pullCount(this.pullCount) + .isOfficial(this.isOfficial) + .isAutomated(this.isAutomated) + .lastPulledAt(this.lastPulledAt) + .isArchived(this.isArchived) + .operatingSystems(this.operatingSystems) + .architectures(this.architectures) + .categories(this.categories) + .build(); + } + + public static PackageInfoDTO fromEntity(PackageInfo packageInfo) { + return PackageInfoDTO.builder() + .id(packageInfo.getId()) + .catalogId(packageInfo.getCatalog() != null ? packageInfo.getCatalog().getId() : null) + .packageType(packageInfo.getPackageType()) + .packageName(packageInfo.getPackageName()) + .packageVersion(packageInfo.getPackageVersion()) + .repositoryUrl(packageInfo.getRepositoryUrl()) + .dockerImageId(packageInfo.getDockerImageId()) + .dockerPublisher(packageInfo.getDockerPublisher()) + .dockerCreatedAt(packageInfo.getDockerCreatedAt()) + .dockerUpdatedAt(packageInfo.getDockerUpdatedAt()) + .dockerShortDescription(packageInfo.getDockerShortDescription()) + .dockerSource(packageInfo.getDockerSource()) + .starCount(packageInfo.getStarCount()) + .pullCount(packageInfo.getPullCount()) + .isOfficial(packageInfo.getIsOfficial()) + .isAutomated(packageInfo.getIsAutomated()) + .lastPulledAt(packageInfo.getLastPulledAt()) + .isArchived(packageInfo.getIsArchived()) + .operatingSystems(packageInfo.getOperatingSystems()) + .architectures(packageInfo.getArchitectures()) + .categories(packageInfo.getCategories()) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/dto/ScriptDefinitionDTO.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/dto/ScriptDefinitionDTO.java new file mode 100644 index 0000000..38279d5 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/dto/ScriptDefinitionDTO.java @@ -0,0 +1,27 @@ +package kr.co.mcmp.softwarecatalog.application.dto; + +import kr.co.mcmp.softwarecatalog.application.constants.ScriptFormat; +import kr.co.mcmp.softwarecatalog.application.constants.ScriptType; +import kr.co.mcmp.softwarecatalog.application.model.ScriptDefinition; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +public class ScriptDefinitionDTO { + private Long id; + private Long catalogId; + private ScriptType scriptType; + private String scriptContent; + private ScriptFormat scriptFormat; + + public ScriptDefinitionDTO(ScriptDefinition entity) { + this.id = entity.getId(); + this.catalogId = entity.getCatalog().getId(); + this.scriptType = entity.getScriptType(); + this.scriptContent = entity.getScriptContent(); + this.scriptFormat = entity.getScriptFormat(); + } +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/dto/VmApplicationHistoryDTO.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/dto/VmApplicationHistoryDTO.java new file mode 100644 index 0000000..0c8d0f7 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/dto/VmApplicationHistoryDTO.java @@ -0,0 +1,34 @@ +package kr.co.mcmp.softwarecatalog.application.dto; + +// @Data +// @Builder +// @NoArgsConstructor +// @AllArgsConstructor +public class VmApplicationHistoryDTO { + + // private Integer id; + // private String namespace; + // private String mciName; + // private String vmName; + // private Integer catalogId; + // private String catalogName; + // private ApplicationStatus status; + // private LocalDateTime installedAt; + // private LocalDateTime uninstalledAt; + // private LocalDateTime updatedAt; + + // public static VmApplicationHistoryDTO fromEntity(VmApplicationHistory entity) { + // return VmApplicationHistoryDTO.builder() + // .id(entity.getId()) + // .namespace(entity.getNamespace()) + // .mciName(entity.getMciName()) + // .vmName(entity.getVmName()) + // .catalogId(entity.getCatalog().getId()) + // .catalogName(entity.getCatalog().getTitle()) + // .status(entity.getStatus()) + // .installedAt(entity.getInstalledAt()) + // .uninstalledAt(entity.getUninstalledAt()) + // .updatedAt(entity.getUpdatedAt()) + // .build(); + // } +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/dto/VmGroupDto.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/dto/VmGroupDto.java new file mode 100644 index 0000000..7f42cc7 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/dto/VmGroupDto.java @@ -0,0 +1,11 @@ +package kr.co.mcmp.softwarecatalog.application.dto; + +import lombok.Data; + +@Data +public class VmGroupDto { + + private String namespace; + private String mciId; + private String vmId; +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/exception/ApplicationException.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/exception/ApplicationException.java new file mode 100644 index 0000000..8c64ffb --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/exception/ApplicationException.java @@ -0,0 +1,35 @@ +package kr.co.mcmp.softwarecatalog.application.exception; + +import org.springframework.http.HttpStatus; + +import lombok.Getter; + +@Getter +public class ApplicationException extends RuntimeException{ + + private int code; + private String message; + private String detail; + + public ApplicationException(String message){ + this.message = message; + } + + public ApplicationException(int code, String message){ + this.code = code; + this.message = message; + } + + public ApplicationException(int code, String message, String detail){ + this(code, message); + this.detail = detail; + } + + public ApplicationException(HttpStatus httpStatus){ + this(httpStatus.value(), httpStatus.getReasonPhrase()); + } + + public ApplicationException(HttpStatus httpStatus, String detail){ + this(httpStatus.value(), httpStatus.getReasonPhrase(), detail); + } +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/model/ApplicationStatus.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/model/ApplicationStatus.java new file mode 100644 index 0000000..6c46d24 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/model/ApplicationStatus.java @@ -0,0 +1,106 @@ +package kr.co.mcmp.softwarecatalog.application.model; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.CollectionTable; +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +import kr.co.mcmp.softwarecatalog.SoftwareCatalog; +import kr.co.mcmp.softwarecatalog.application.constants.DeploymentType; +import kr.co.mcmp.softwarecatalog.users.Entity.User; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@Table(name = "APPLICATION_STATUS") +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ApplicationStatus { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "namespace") + private String namespace; + + @Column(name = "mci_id") + private String mciId; + + @Column(name = "cluster_name") + private String clusterName; + + @Column(name ="vm_id") + private String vmId; + + @ManyToOne + @JoinColumn(name = "catalog_id") + private SoftwareCatalog catalog; + + @Enumerated(EnumType.STRING) + @Column(name = "deployment_type") + private DeploymentType deploymentType; // VM or K8S + + @Column(name = "service_port") + private Integer servicePort; + + @Column(name="is_port_accessible") + private Boolean isPortAccessible; + + @Column(name = "is_health_check") + private Boolean isHealthCheck; + + + @Column(name = "status") + private String status; + + @Column(name = "cpu_usage") + private Double cpuUsage; + + @Column(name = "memory_usage") + private Double memoryUsage; + + @Column(name = "network_in") + private Double networkIn; + + @Column(name="public_ip") + private String publicIp; + + @Column(name = "network_out") + private Double networkOut; + + @Column(name = "pod_status") + private String podStatus; // For K8S deployments + + @Column(name = "checked_at") + private LocalDateTime checkedAt; + + @ManyToOne + @JoinColumn(name = "executed_by") + private User executedBy; + + @ElementCollection + @CollectionTable(name = "APPLICATION_ERROR_LOGS", joinColumns = @JoinColumn(name = "application_status_id")) + @Column(name = "error_log") + private List errorLogs = new ArrayList<>(); + + +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/model/DeploymentHistory.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/model/DeploymentHistory.java new file mode 100644 index 0000000..3e87f3e --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/model/DeploymentHistory.java @@ -0,0 +1,91 @@ +package kr.co.mcmp.softwarecatalog.application.model; + +import java.time.LocalDateTime; +import java.util.List; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +import kr.co.mcmp.softwarecatalog.SoftwareCatalog; +import kr.co.mcmp.softwarecatalog.application.constants.ActionType; +import kr.co.mcmp.softwarecatalog.application.constants.DeploymentType; +import kr.co.mcmp.softwarecatalog.users.Entity.User; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@Table(name = "DEPLOYMENT_HISTORY") +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class DeploymentHistory { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; // 배포 이력의 고유 식별자 + + @ManyToOne + @JoinColumn(name = "catalog_id") + private SoftwareCatalog catalog; // 배포된 소프트웨어 카탈로그 + + @Enumerated(EnumType.STRING) + @Column(name = "deployment_type", nullable = false) + private DeploymentType deploymentType; // 배포 유형 (예: K8S, VM) + + @Column(name="namespace") + private String namespace; + + @Column(name = "mci_id") + private String mciId; // VM 배포에 사용 + + @Column(name = "vm_id") + private String vmId; // VM 배포에 사용 + + @Column(name = "cluster_name") + private String clusterName; // K8s 배포에 사용 + + @Column(name = "public_ip") + private String publicIp; + + @Enumerated(EnumType.STRING) + @Column(name = "action_type", nullable = false) + private ActionType actionType; // 수행된 작업 유형 (예: INSTALL, UNINSTALL, RUN, RESTART, STOP) + + @Column(nullable = false) + private String status; // 배포 상태 (예: 성공, 실패, 진행 중) + + @Column(name = "executed_at", nullable = false) + private LocalDateTime executedAt; // 배포 작업 실행 시간 + + @ManyToOne + @JoinColumn(name = "executed_by") + private User executedBy; // 배포 작업을 실행한 사용자 + + @Column(name = "cloud_provider") + private String cloudProvider; // 클라우드 제공자 + + @Column(name= "uid") + private String uid; // uid; + + @Column(name = "cloud_region") + private String cloudRegion; // 클라우드 리전 + + @Column(name = "service_port") + private Integer servicePort; // 서비스 포트 (VM 전용) + + @Column(name = "pod_status") + private String podStatus; // Pod 상태 (K8S 전용) +} \ No newline at end of file diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/model/DeploymentLog.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/model/DeploymentLog.java new file mode 100644 index 0000000..857306e --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/model/DeploymentLog.java @@ -0,0 +1,49 @@ +package kr.co.mcmp.softwarecatalog.application.model; + +import java.time.LocalDateTime; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +import kr.co.mcmp.softwarecatalog.application.constants.LogType; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@Table(name = "DEPLOYMENT_LOG") +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class DeploymentLog { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; // 배포 로그의 고유 식별자 + + @ManyToOne + @JoinColumn(name = "deployment_id") + private DeploymentHistory deployment; // 이 로그가 속한 배포 이력 + + @Enumerated(EnumType.STRING) + @Column(name = "log_type", nullable = false) + private LogType logType; // 로그 유형 (예: INFO, WARNING, ERROR) + + @Column(name = "log_message", columnDefinition = "TEXT") + private String logMessage; // 로그 메시지 내용 + + @Column(name = "logged_at") + private LocalDateTime loggedAt; // 로그 기록 시간 + +} \ No newline at end of file diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/model/HelmChart.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/model/HelmChart.java new file mode 100644 index 0000000..3860a16 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/model/HelmChart.java @@ -0,0 +1,80 @@ +package kr.co.mcmp.softwarecatalog.application.model; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToOne; +import javax.persistence.Table; + +import kr.co.mcmp.softwarecatalog.SoftwareCatalog; +import kr.co.mcmp.softwarecatalog.application.dto.HelmChartDTO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@Table(name = "HELM_CHART") +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class HelmChart { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; // Helm 차트 정보의 고유 식별자 + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "catalog_id", unique = true) + private SoftwareCatalog catalog; // 이 Helm 차트가 속한 소프트웨어 카탈로그 + + @Column(name = "chart_name", nullable = false) + private String chartName; // Helm 차트의 이름 + + @Column(name = "chart_version") + private String chartVersion; // Helm 차트의 버전 + + @Column(name = "chart_repository_url") + private String chartRepositoryUrl; // Helm 차트가 저장된 저장소의 URL + + @Column(name = "values_file", columnDefinition = "TEXT") + private String valuesFile; // Helm 차트의 values.yaml 파일 내용 + + @Column(name = "package_id") + private String packageId; // ArtifactHub 패키지 ID (ArtifactHub 전용) + + @Column(name = "normalized_name") + private String normalizedName; // ArtifactHub 정규화된 이름 (ArtifactHub 전용) + + @Column(name = "has_values_schema") + private Boolean hasValuesSchema; // ArtifactHub values 스키마 존재 여부 (ArtifactHub 전용) + + @Column(name = "repository_name") + private String repositoryName; // ArtifactHub 저장소 이름 (ArtifactHub 전용) + + @Column(name = "repository_official") + private Boolean repositoryOfficial; // ArtifactHub 공식 저장소 여부 (ArtifactHub 전용) + + @Column(name = "repository_display_name") + private String repositoryDisplayName; // ArtifactHub 저장소 표시 이름 (ArtifactHub 전용) + + + + public void updateFromDTO(HelmChartDTO helmChart) { + helmChart.setChartName(this.chartName); + helmChart.setChartVersion(this.chartVersion); + helmChart.setChartRepositoryUrl(this.chartRepositoryUrl); + helmChart.setValuesFile(this.valuesFile); + helmChart.setHasValuesSchema(this.hasValuesSchema); + helmChart.setRepositoryName(this.repositoryName); + helmChart.setRepositoryOfficial(this.repositoryOfficial); + helmChart.setRepositoryDisplayName(this.repositoryDisplayName); + } +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/model/PackageInfo.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/model/PackageInfo.java new file mode 100644 index 0000000..153aec3 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/model/PackageInfo.java @@ -0,0 +1,124 @@ +package kr.co.mcmp.softwarecatalog.application.model; + +import java.time.LocalDateTime; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToOne; +import javax.persistence.Table; + +import kr.co.mcmp.softwarecatalog.SoftwareCatalog; +import kr.co.mcmp.softwarecatalog.application.constants.PackageType; +import kr.co.mcmp.softwarecatalog.application.dto.PackageInfoDTO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +@Entity +@Table(name = "PACKAGE_INFO") +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PackageInfo { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "catalog_id", unique = true) + private SoftwareCatalog catalog; + + @Enumerated(EnumType.STRING) + @Column(name = "package_type", nullable = false) + private PackageType packageType; + + @Column(name = "package_name") + private String packageName; + + @Column(name = "package_version") + private String packageVersion; + + @Column(name = "repository_url") + private String repositoryUrl; + + @Column(name = "docker_image_id") + private String dockerImageId; + + @Column(name = "docker_publisher") + private String dockerPublisher; + + @Column(name = "docker_created_at") + private LocalDateTime dockerCreatedAt; + + @Column(name = "docker_updated_at") + private LocalDateTime dockerUpdatedAt; + + @Column(name = "docker_short_description") + private String dockerShortDescription; + + @Column(name = "docker_source") + private String dockerSource; + + @Column(name = "star_count") + private Integer starCount; + + @Column(name = "pull_count") + private String pullCount; + + @Column(name = "is_official") + private Boolean isOfficial; + + @Column(name = "is_automated") + private Boolean isAutomated; + + @Column(name = "last_pulled_at") + private LocalDateTime lastPulledAt; + + @Column(name = "is_archived") + private Boolean isArchived; + + @Column(name = "operating_systems") + private String operatingSystems; + + @Column(name = "architectures") + private String architectures; + + @Column(name = "categories") + private String categories; + + public void updateFromDTO(PackageInfoDTO dto) { + // 기존 필드 업데이트 + this.packageType = dto.getPackageType(); + this.packageName = dto.getPackageName(); + this.packageVersion = dto.getPackageVersion(); + this.repositoryUrl = dto.getRepositoryUrl(); + this.dockerImageId = dto.getDockerImageId(); + this.dockerPublisher = dto.getDockerPublisher(); + this.dockerCreatedAt = dto.getDockerCreatedAt(); + this.dockerUpdatedAt = dto.getDockerUpdatedAt(); + this.dockerShortDescription = dto.getDockerShortDescription(); + this.dockerSource = dto.getDockerSource(); + + // 새로운 필드 업데이트 + this.starCount = dto.getStarCount(); + this.pullCount = dto.getPullCount(); + this.isOfficial = dto.getIsOfficial(); + this.isAutomated = dto.getIsAutomated(); + this.lastPulledAt = dto.getLastPulledAt(); + this.isArchived = dto.getIsArchived(); + this.operatingSystems = dto.getOperatingSystems(); + this.architectures = dto.getArchitectures(); + this.categories = dto.getCategories(); + } +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/model/ScriptDefinition.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/model/ScriptDefinition.java new file mode 100644 index 0000000..0bb1b20 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/model/ScriptDefinition.java @@ -0,0 +1,44 @@ +package kr.co.mcmp.softwarecatalog.application.model; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +import kr.co.mcmp.softwarecatalog.SoftwareCatalog; +import kr.co.mcmp.softwarecatalog.application.constants.ScriptFormat; +import kr.co.mcmp.softwarecatalog.application.constants.ScriptType; +import lombok.Getter; +import lombok.Setter; + +@Entity +@Table(name = "SCRIPT_DEFINITION") +@Getter +@Setter +public class ScriptDefinition { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; // 스크립트 정의의 고유 식별자 + + @ManyToOne + @JoinColumn(name = "catalog_id") + private SoftwareCatalog catalog; // 이 스크립트가 속한 소프트웨어 카탈로그 + + @Enumerated(EnumType.STRING) + @Column(name = "script_type", nullable = false) + private ScriptType scriptType; // 스크립트의 유형 (예: INSTALL, UNINSTALL, RUN, RESTART, STOP) + + @Column(name = "script_content", columnDefinition = "TEXT") + private String scriptContent; // 실제 스크립트 내용 + + @Enumerated(EnumType.STRING) + @Column(name = "script_format", nullable = false) + private ScriptFormat scriptFormat; // 스크립트의 형식 (예: XML, SHELL, GROOVY) + +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/repository/ApplicationStatusRepository.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/repository/ApplicationStatusRepository.java new file mode 100644 index 0000000..9e2e591 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/repository/ApplicationStatusRepository.java @@ -0,0 +1,27 @@ +package kr.co.mcmp.softwarecatalog.application.repository; + +import java.util.List; +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import kr.co.mcmp.softwarecatalog.SoftwareCatalog; +import kr.co.mcmp.softwarecatalog.application.dto.VmGroupDto; +import kr.co.mcmp.softwarecatalog.application.model.ApplicationStatus; +import kr.co.mcmp.softwarecatalog.users.Entity.User; + +@Repository +public interface ApplicationStatusRepository extends JpaRepository { + Optional findByCatalog(SoftwareCatalog catalog); + Optional findByCatalogId(Long catalogId); + ApplicationStatus findTopByCatalogOrderByCheckedAtDesc(SoftwareCatalog catalog); + Optional findByCatalogIdAndExecutedBy(Long catalogId, User user); + Optional findTopByExecutedByOrderByCheckedAtDesc(User executedBy); + + @Query("SELECT DISTINCT a.namespace, a.mciId, a.vmId FROM ApplicationStatus a") + List findDistinctVmGroups(); + + List findByNamespaceAndMciIdAndVmId(String namespace, String mciId, String vmId); +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/repository/DeploymentHistoryRepository.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/repository/DeploymentHistoryRepository.java new file mode 100644 index 0000000..773ea2d --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/repository/DeploymentHistoryRepository.java @@ -0,0 +1,37 @@ +package kr.co.mcmp.softwarecatalog.application.repository; + +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import kr.co.mcmp.softwarecatalog.SoftwareCatalog; +import kr.co.mcmp.softwarecatalog.application.constants.ActionType; +import kr.co.mcmp.softwarecatalog.application.model.DeploymentHistory; +import kr.co.mcmp.softwarecatalog.users.Entity.User; + + +@Repository +public interface DeploymentHistoryRepository extends JpaRepository { + List findByCatalog(SoftwareCatalog catalog); + List findByExecutedBy(User user); + // List findByNamespaceAndMciIdAndVmIdAndStatusNot(String namespace, String mciId, String vmId, String status); + // List findByNamespaceAndClusterNameAndStatusNot(String namespace, String clusterName, String status); + List findByNamespaceAndMciIdAndVmIdAndActionTypeNotAndStatus( + String namespace, + String mciId, + String vmId, + ActionType actionType, + String status + ); + List findByNamespaceAndClusterNameAndActionTypeNotAndStatus( + String namespace, + String clusterName, + ActionType actionType, + String status + ); + + List findByCatalogIdOrderByExecutedAtDesc(Long catalogId); + List findByCatalogIdAndExecutedByOrderByExecutedAtDesc(Long catalogId, User user); + +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/repository/DeploymentLogRepository.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/repository/DeploymentLogRepository.java new file mode 100644 index 0000000..f65ee06 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/repository/DeploymentLogRepository.java @@ -0,0 +1,17 @@ +package kr.co.mcmp.softwarecatalog.application.repository; + +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import kr.co.mcmp.softwarecatalog.application.model.DeploymentHistory; +import kr.co.mcmp.softwarecatalog.application.model.DeploymentLog; +import kr.co.mcmp.softwarecatalog.users.Entity.User; + +@Repository +public interface DeploymentLogRepository extends JpaRepository { + List findByDeployment(DeploymentHistory deployment); + List findByDeploymentIdOrderByLoggedAtDesc(Long deploymentId); + List findByDeploymentIdAndDeployment_ExecutedByOrderByLoggedAtDesc(Long deploymentId, User user); +} \ No newline at end of file diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/repository/HelmChartRepository.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/repository/HelmChartRepository.java new file mode 100644 index 0000000..80c943a --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/repository/HelmChartRepository.java @@ -0,0 +1,18 @@ +package kr.co.mcmp.softwarecatalog.application.repository; + +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import kr.co.mcmp.softwarecatalog.SoftwareCatalog; +import kr.co.mcmp.softwarecatalog.application.model.HelmChart; + +@Repository +public interface HelmChartRepository extends JpaRepository { + + Optional findByCatalog(SoftwareCatalog catalog); + Optional findByCatalogId(Long catalogId); + void deleteByCatalog(SoftwareCatalog catalog); + void deleteByCatalogId(Long catalogId); +} \ No newline at end of file diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/repository/PackageInfoRepository.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/repository/PackageInfoRepository.java new file mode 100644 index 0000000..62e4100 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/repository/PackageInfoRepository.java @@ -0,0 +1,17 @@ +package kr.co.mcmp.softwarecatalog.application.repository; + +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import kr.co.mcmp.softwarecatalog.SoftwareCatalog; +import kr.co.mcmp.softwarecatalog.application.model.PackageInfo; + +@Repository +public interface PackageInfoRepository extends JpaRepository { + Optional findByCatalog(SoftwareCatalog catalog); + Optional findByCatalogId(Long catalogId); + void deleteByCatalog(SoftwareCatalog catalog); + void deleteByCatalogId(Long catalogId); +} \ No newline at end of file diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/repository/ScriptDefinitionRepository.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/repository/ScriptDefinitionRepository.java new file mode 100644 index 0000000..78698b9 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/repository/ScriptDefinitionRepository.java @@ -0,0 +1,18 @@ +package kr.co.mcmp.softwarecatalog.application.repository; + +import java.util.List; +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import kr.co.mcmp.softwarecatalog.SoftwareCatalog; +import kr.co.mcmp.softwarecatalog.application.constants.ScriptType; +import kr.co.mcmp.softwarecatalog.application.model.ScriptDefinition; + +@Repository +public interface ScriptDefinitionRepository extends JpaRepository { + List findByCatalog(SoftwareCatalog catalog); + void deleteByCatalog(SoftwareCatalog catalog); + Optional findByCatalogAndScriptType(SoftwareCatalog catalog, ScriptType scriptType); +} \ No newline at end of file diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/application/service/ApplicationService.java b/src/main/java/kr/co/mcmp/softwarecatalog/application/service/ApplicationService.java new file mode 100644 index 0000000..1336908 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/application/service/ApplicationService.java @@ -0,0 +1,597 @@ +package kr.co.mcmp.softwarecatalog.application.service; + +import java.net.MalformedURLException; +import java.net.URL; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import javax.persistence.EntityNotFoundException; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.github.dockerjava.api.DockerClient; + +import kr.co.mcmp.ape.cbtumblebug.api.CbtumblebugRestApi; +import kr.co.mcmp.ape.cbtumblebug.dto.K8sClusterDto; +import kr.co.mcmp.ape.cbtumblebug.dto.K8sSpec; +import kr.co.mcmp.ape.cbtumblebug.dto.Spec; +import kr.co.mcmp.ape.cbtumblebug.dto.VmAccessInfo; +import kr.co.mcmp.softwarecatalog.CatalogService; +import kr.co.mcmp.softwarecatalog.SoftwareCatalogDTO; +import kr.co.mcmp.softwarecatalog.application.constants.ActionType; +import kr.co.mcmp.softwarecatalog.application.constants.DeploymentType; +import kr.co.mcmp.softwarecatalog.application.constants.LogType; +import kr.co.mcmp.softwarecatalog.application.dto.ApplicationStatusDto; +import kr.co.mcmp.softwarecatalog.application.dto.PackageInfoDTO; +import kr.co.mcmp.softwarecatalog.application.exception.ApplicationException; +import kr.co.mcmp.softwarecatalog.application.model.ApplicationStatus; +import kr.co.mcmp.softwarecatalog.application.model.DeploymentHistory; +import kr.co.mcmp.softwarecatalog.application.model.DeploymentLog; +import kr.co.mcmp.softwarecatalog.application.repository.ApplicationStatusRepository; +import kr.co.mcmp.softwarecatalog.application.repository.DeploymentHistoryRepository; +import kr.co.mcmp.softwarecatalog.application.repository.DeploymentLogRepository; +import kr.co.mcmp.softwarecatalog.docker.model.ContainerDeployResult; +import kr.co.mcmp.softwarecatalog.docker.service.ContainerStatsCollector; +import kr.co.mcmp.softwarecatalog.docker.service.DockerClientFactory; +import kr.co.mcmp.softwarecatalog.docker.service.DockerOperationService; +import kr.co.mcmp.softwarecatalog.docker.service.DockerSetupService; +import kr.co.mcmp.softwarecatalog.users.Entity.User; +import kr.co.mcmp.softwarecatalog.users.service.UserService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Service +@Transactional +@Slf4j +@RequiredArgsConstructor +public class ApplicationService { + + private final CatalogService catalogService; + private final ApplicationStatusRepository applicationStatusRepository; + private final DeploymentHistoryRepository deploymentHistoryRepository; + private final DeploymentLogRepository deploymentLogRepository; + private final UserService userService; + private final DockerSetupService dockerSetupService; + private final DockerOperationService dockerOperationService; + private final CbtumblebugRestApi cbtumblebugRestApi; + private final DockerClientFactory dockerClientFactory; + private final ContainerStatsCollector containerStatsCollector; + + public Map performDockerOperation(ActionType operation, Long applicationStatusId) throws Exception { + ApplicationStatus applicationStatus = applicationStatusRepository.findById(applicationStatusId) + .orElseThrow(() -> new EntityNotFoundException("ApplicationStatus not found with id: " + applicationStatusId)); + + String host = applicationStatus.getPublicIp(); + DockerClient dockerClient = dockerClientFactory.getDockerClient(host); + String containerName = applicationStatus.getCatalog().getTitle().toLowerCase().replaceAll("\\s+", "-"); + String containerId = containerStatsCollector.getContainerId(dockerClient, containerName); + + if (containerId == null) { + throw new IllegalStateException("Container ID is not available for application status: " + applicationStatusId); + } + + Map result = new HashMap<>(); + result.put("operation", operation); + result.put("applicationStatusId", applicationStatusId); + + try { + switch (operation.toString().toLowerCase()) { + case "status": + String status = dockerOperationService.getDockerContainerStatus(host, containerId); + result.put("status", status); + break; + case "stop": + String stopResult = dockerOperationService.stopDockerContainer(host, containerId); + result.put("result", stopResult); + break; + case "uninstall": + String removeResult = dockerOperationService.removeDockerContainer(host, containerId); + result.put("result", removeResult); + break; + case "restart": + String restartResult = dockerOperationService.restartDockerContainer(host, containerId); + result.put("result", restartResult); + break; + case "isrunning": + boolean isRunning = dockerOperationService.isContainerRunning(host, containerId); + result.put("isRunning", isRunning); + break; + default: + throw new IllegalArgumentException("Unknown operation: " + operation); + } + + // 작업 결과에 따라 ApplicationStatus 업데이트 + updateApplicationStatus(applicationStatus, operation, result); + + } catch (Exception e) { + log.error("Error performing Docker operation: {} on application status: {}", operation, applicationStatusId, e); + result.put("error", e.getMessage()); + } + + return result; + } + + private void updateApplicationStatus(ApplicationStatus applicationStatus, ActionType operation, Map result) { + switch (operation.toString().toLowerCase()) { + case "status": + applicationStatus.setStatus((String) result.get("status")); + break; + case "stop": + applicationStatus.setStatus(ActionType.STOP.name()); + break; + case "remove": + applicationStatus.setStatus(ActionType.UNINSTALL.name()); + break; + case "restart": + applicationStatus.setStatus(ActionType.RESTART.name()); + break; + case "isrunning": + applicationStatus.setStatus((Boolean) result.get("isRunning") ? ActionType.RUN.name() : ActionType.STOP.name()); + break; + } + applicationStatus.setCheckedAt(LocalDateTime.now()); + applicationStatusRepository.save(applicationStatus); + } + + @Transactional + public DeploymentHistory deployApplication(String namespace, String mciId, String vmId, Long catalogId, Integer servicePort, String username) { + SoftwareCatalogDTO catalog = catalogService.getCatalog(catalogId); + User user = getUserOrNull(username); + DeploymentHistory history = createDeploymentHistory(namespace, mciId, vmId, catalog, servicePort, user); + + try { + // Docker 설치 확인 및 설치 + dockerSetupService.checkAndInstallDocker(namespace, mciId, vmId); + + // 애플리케이션 배포 + // String deployCommand = buildDeployCommand(catalog, servicePort); + Map deployParams = buildDeployParameters(catalog, servicePort); + VmAccessInfo vmAccessInfo = cbtumblebugRestApi.getVmInfo(namespace, mciId, vmId); + // ContainerDeployResult deployResult = dockerOperationService.runDockerContainer(namespace, mciId, vmId, null, deployCommand); + // ContainerDeployResult deployResult = dockerOperationService.runDockerContainer(vmAccessInfo.getPublicIP(), deployCommand); + ContainerDeployResult deployResult = dockerOperationService.runDockerContainer(vmAccessInfo.getPublicIP(), deployParams); + + String containerId = deployResult.getContainerId(); + String result = deployResult.getDeploymentResult(); + + log.info("Deployment result: {}", result); + log.info("Container ID: {}", containerId); + + if (containerId != null && !containerId.isEmpty()) { + // boolean isRunning = dockerOperationService.isContainerRunning(namespace, mciId, vmId, null, containerId); + boolean isRunning = dockerOperationService.isContainerRunning(vmAccessInfo.getPublicIP(), containerId); + if (isRunning) { + log.info("Container is running"); + history.setStatus("SUCCESS"); + updateApplicationStatus(history, "RUNNING", user); + addDeploymentLog(history, LogType.INFO, "Deployment successful and container is running. Container ID: " + containerId); + } else { + log.warn("Container is not running"); + throw new ApplicationException("Deployment failed: Container is not running"); + } + } else { + throw new ApplicationException("Deployment failed: Could not retrieve container ID"); + } + } catch (Exception e) { + log.error("Deployment failed", e); + history.setStatus("FAILED"); + updateApplicationStatus(history, "FAILED", user); + addDeploymentLog(history, LogType.ERROR, "Deployment failed: " + e.getMessage()); + } + + return deploymentHistoryRepository.save(history); + } + + public Map buildDeployParameters(SoftwareCatalogDTO catalog, Integer servicePort) { + PackageInfoDTO packageInfo = catalog.getPackageInfo(); + if (packageInfo == null) { + throw new IllegalArgumentException("PackageInfo is not available for deployment"); + } + Integer containerPort = catalog.getDefaultPort() != null ? catalog.getDefaultPort() : servicePort; + Map params = new HashMap<>(); + params.put("name", catalog.getTitle().toLowerCase().replaceAll("\\s+", "-")); + params.put("image", packageInfo.getPackageName().toLowerCase() + ":" + packageInfo.getPackageVersion().toLowerCase()); + params.put("portBindings", servicePort + ":" + containerPort); + + return params; + } + + /* + public String buildDeployCommand(SoftwareCatalogDTO catalog, Integer servicePorts) { + PackageInfoDTO packageInfo = catalog.getPackageInfo(); + if (packageInfo == null) { + throw new IllegalArgumentException("PackageInfo is not available for deployment"); + } + + StringBuilder command = new StringBuilder("docker run -d"); + + // 컨테이너 이름 설정 + String containerName = catalog.getTitle().toLowerCase().replaceAll("\\s+", "-"); + command.append(String.format(" --name %s", containerName)); + + // 포트 매핑 + // List defaultPorts = catalog.getDefaultPort(); + // for (int i = 0; i < Math.min(servicePorts.size(), defaultPorts.size()); i++) { + // command.append(String.format(" -p %d:%d", servicePorts.get(i), defaultPorts.get(i))); + // } + + // 포트 매핑 + + command.append(String.format(" -p %d:%d", servicePorts, servicePorts)); + + // 리소스 제한 설정 + // if (catalog.getMinCpu() != null) { + // command.append(String.format(" --cpus=%f", catalog.getMinCpu())); + // } + // if (catalog.getMinMemory() != null) { + // command.append(String.format(" --memory=%dM", catalog.getMinMemory())); + // } + + // 이미지 지정 + String imageName = packageInfo.getPackageName().toLowerCase(); + String imageTag = packageInfo.getPackageVersion().toLowerCase(); + command.append(String.format(" %s:%s", imageName, imageTag)); + + log.info("Generated Docker command: {}", command); + return command.toString(); + } + + private int getDefaultPort(String packageName) { + switch (packageName.toLowerCase()) { + case "nginx": + case "httpd": + return 80; + case "tomcat": + return 8080; + case "redis": + return 6379; + case "mariadb": + case "mysql": + return 3306; + case "nexus repository": + return 8081; // Nexus Repository의 기본 웹 인터페이스 포트 + case "grafana": + return 3000; + case "prometheus": + return 9090; + case "mongodb": + return 27017; + case "postgresql": + return 5432; + case "elasticsearch": + return 9200; + case "rabbitmq": + return 5672; // AMQP 포트, 관리 인터페이스는 15672 + case "jenkins": + return 8080; + case "zookeeper": + return 2181; + case "cassandra": + return 9042; + case "kafka": + return 9092; + case "memcached": + return 11211; + case "haproxy": + return 80; // 기본 HTTP 포트, 관리 인터페이스는 다를 수 있음 + default: + return 0; // 기본값 + } + } + + private Map getEnvironmentVariables(String packageName) { + Map envVars = new HashMap<>(); + switch (packageName.toLowerCase()) { + case "mariadb": + case "mysql": + envVars.put("MYSQL_ROOT_PASSWORD", "changeme"); + break; + case "redis": + envVars.put("REDIS_PASSWORD", "changeme"); + break; + // 다른 패키지에 대한 환경 변수 추가 + } + return envVars; + } + + private String getVolumeMount(String packageName) { + switch (packageName.toLowerCase()) { + case "mariadb": + case "mysql": + return " -v mysql_data:/var/lib/mysql"; + case "redis": + return " -v redis_data:/data"; + // 다른 패키지에 대한 볼륨 마운트 추가 + default: + return null; + } + } + + private String parseRegistryFromUrl(String url) { + if (url == null || url.isEmpty()) { + return ""; + } + if (url.contains("docker.io") || url.contains("hub.docker.com")) { + return ""; // Docker Hub의 경우 레지스트리 주소 생략 + } + // 다른 레지스트리의 경우, URL에서 레지스트리 주소 추출 + try { + URL parsedUrl = new URL(url); + return parsedUrl.getHost() + "/"; + } catch (MalformedURLException e) { + return ""; + } + } +*/ + public List getApplicationGroups() { + List vmGroups = applicationStatusRepository.findDistinctVmGroups(); + + return vmGroups.stream() + .flatMap(group -> { + String namespace = (String) group[0]; + String mciId = (String) group[1]; + String vmId = (String) group[2]; + List applications = applicationStatusRepository.findByNamespaceAndMciIdAndVmId( + namespace, mciId, vmId); + + return applications.stream() + .map(ApplicationStatusDto::fromEntity); + }) + .collect(Collectors.toList()); + } + + + /** + * 배포 이력을 생성합니다. + * + * @param namespace 네임스페이스 + * @param mciId MCI ID + * @param vmId VM ID + * @param catalog 소프트웨어 카탈로그 + * @param user 사용자 + * @return 배포 이력 + */ + private DeploymentHistory createDeploymentHistory(String namespace, String mciId, String vmId, SoftwareCatalogDTO catalog, Integer servicePort, User user) { + VmAccessInfo vmInfo = cbtumblebugRestApi.getVmInfo(namespace, mciId, vmId); + String[] parts = vmInfo.getConnectionName().split("-"); + return DeploymentHistory.builder() + .catalog(catalog.toEntity()) + .deploymentType(DeploymentType.VM) + .cloudProvider(parts.length > 0 ? parts[0] : "") // 예: "aws-ap-northeast-2" -> "aws" + .cloudRegion(vmInfo.getRegion().getRegion()) + .namespace(namespace) + .mciId(mciId) + .vmId(vmId) + .publicIp(vmInfo.getPublicIP()) + .actionType(ActionType.INSTALL) + .status("IN_PROGRESS") + .servicePort(servicePort) + .executedAt(LocalDateTime.now()) + .executedBy(user) + .build(); + } + + /** + * 애플리케이션 상태를 업데이트합니다. + * + * @param history 배포 이력 + * @param status 상태 + * @param user 사용자 + */ + private void updateApplicationStatus(DeploymentHistory history, String status, User user) { + ApplicationStatus appStatus = applicationStatusRepository.findByCatalogId(history.getCatalog().getId()) + .orElse(new ApplicationStatus()); + + appStatus.setCatalog(history.getCatalog()); + appStatus.setStatus(status); + appStatus.setDeploymentType(history.getDeploymentType()); + appStatus.setCheckedAt(LocalDateTime.now()); + + applicationStatusRepository.save(appStatus); + } + + /** + * 배포 로그를 추가합니다. + * + * @param history 배포 이력 + * @param logType 로그 타입 + * @param message 로그 메시지 + */ + private void addDeploymentLog(DeploymentHistory history, LogType logType, String message) { + DeploymentLog log = DeploymentLog.builder() + .deployment(history) + .logType(logType) + .logMessage(message) + .loggedAt(LocalDateTime.now()) + .build(); + deploymentLogRepository.save(log); + } + + /** + * 사용자 이름으로 사용자를 조회합니다. + * + * @param username 사용자 이름 + * @return 사용자 또는 null + */ + private User getUserOrNull(String username) { + return StringUtils.isNotBlank(username) ? userService.findUserByUsername(username).orElse(null) : null; + } + + /** + * 배포 이력 목록을 조회합니다. + * + * @param catalogId 카탈로그 ID + * @param username 사용자 이름 + * @return 배포 이력 목록 + */ + public List getDeploymentHistories(Long catalogId, String username) { + if (StringUtils.isBlank(username)) { + return deploymentHistoryRepository.findByCatalogIdOrderByExecutedAtDesc(catalogId); + } else { + User user = getUserOrNull(username); + return user != null ? + deploymentHistoryRepository.findByCatalogIdAndExecutedByOrderByExecutedAtDesc(catalogId, user) : + List.of(); + } + } + + /** + * 배포 로그 목록을 조회합니다. + * + * @param deploymentId 배포 ID + * @param username 사용자 이름 + * @return 배포 로그 목록 + */ + public List getDeploymentLogs(Long deploymentId, String username) { + if (StringUtils.isBlank(username)) { + return deploymentLogRepository.findByDeploymentIdOrderByLoggedAtDesc(deploymentId); + } else { + User user = getUserOrNull(username); + return user != null ? + deploymentLogRepository.findByDeploymentIdAndDeployment_ExecutedByOrderByLoggedAtDesc(deploymentId, user) : + List.of(); + } + } + + /** + * 애플리케이션 상태를 조회합니다. + * + * @param catalogId 카탈로그 ID + * @param username 사용자 이름 + * @return 애플리케이션 상태 + */ + public ApplicationStatusDto getLatestApplicationStatus(String username) { + if (StringUtils.isBlank(username)) { + throw new IllegalArgumentException("Username cannot be blank"); + } + + User user = getUserOrNull(username); + if (user == null) { + throw new EntityNotFoundException("User not found with username: " + username); + } + + ApplicationStatus status = applicationStatusRepository.findTopByExecutedByOrderByCheckedAtDesc(user) + .orElseThrow(() -> new EntityNotFoundException("Application status not found for user: " + username)); + + return ApplicationStatusDto.fromEntity(status); + } + + /*** + * Vm의 스펙 정보와 현재 설치된 어플리케이션의 스펙 합을 비교 합니다. + * @param namespace + * @param mciId + * @param vmId + * @param catalogId + * @return true : 여유, false : 부족 + */ + public boolean checkSpecForVm(String namespace, String mciId, String vmId, Long catalogId) { + SoftwareCatalogDTO catalog = catalogService.getCatalog(catalogId); + Spec vmSpec = getSpecForVm(namespace, mciId, vmId); + + List activeDeployments = deploymentHistoryRepository.findByNamespaceAndMciIdAndVmIdAndActionTypeNotAndStatus( + namespace, mciId, vmId, ActionType.UNINSTALL, "SUCCESS" + ); + + double usedCpu = activeDeployments.stream().mapToDouble(d -> d.getCatalog().getRecommendedCpu()).sum(); + double usedMemory = activeDeployments.stream().mapToDouble(d -> d.getCatalog().getRecommendedMemory()).sum(); + + double availableCpu = vmSpec.getVCPU() - usedCpu; + double availableMemory = vmSpec.getMemoryGiB() - usedMemory; + + log.info("VM Spec Check - Available vCPU: {}, Required vCPU: {}", availableCpu, catalog.getRecommendedCpu()); + log.info("VM Spec Check - Available Memory: {} GiB, Required Memory: {} GiB", availableMemory, catalog.getRecommendedMemory()); + + return availableCpu >= catalog.getRecommendedCpu() && availableMemory >= catalog.getRecommendedMemory(); + } + + /*** + * K8s의 스펙 정보와 현재 설치된 어플리케이션의 스펙 합을 비교합니다. + * @param namespace + * @param clusterName + * @param catalogId + * @return true : 여유, false : 부족 + */ + public boolean checkSpecForK8s(String namespace, String clusterName, Long catalogId) { + SoftwareCatalogDTO catalog = catalogService.getCatalog(catalogId); + K8sSpec nodeSpec = getSpecForK8s(namespace, clusterName); + + List activeDeployments = deploymentHistoryRepository.findByNamespaceAndClusterNameAndActionTypeNotAndStatus( + namespace, clusterName, ActionType.UNINSTALL, "SUCCESS" + ); + + double usedCpu = activeDeployments.stream().mapToDouble(d -> d.getCatalog().getRecommendedCpu()).sum(); + double usedMemory = activeDeployments.stream().mapToDouble(d -> d.getCatalog().getRecommendedMemory()).sum(); + + double availableCpu = Double.parseDouble(nodeSpec.getVCpu().getCount()) - usedCpu; + double availableMemory = Double.parseDouble(nodeSpec.getMem()) - usedMemory; + + log.info("K8s Node Spec Check - Available vCPU: {}, Required vCPU: {}", availableCpu, catalog.getRecommendedCpu()); + log.info("K8s Node Spec Check - Available Memory: {} GiB, Required Memory: {} GiB", availableMemory, catalog.getRecommendedMemory()); + + return availableCpu >= catalog.getRecommendedCpu() && availableMemory >= catalog.getRecommendedMemory(); + } + + /** + * VM의 스펙 정보를 조회합니다. + * + * @param namespace 네임스페이스 + * @param mciId MCI ID + * @param vmId VM ID + * @return VM의 스펙 정보 + */ + public Spec getSpecForVm(String namespace, String mciId, String vmId) { + log.info("Retrieving spec for VM: namespace={}, mciId={}, vmId={}", namespace, mciId, vmId); + try { + VmAccessInfo vmInfo = cbtumblebugRestApi.getVmInfo(namespace, mciId, vmId); + if (vmInfo == null || StringUtils.isBlank(vmInfo.getSpecId())) { + throw new ApplicationException("Failed to retrieve VM info or spec ID is blank"); + } + Spec spec = cbtumblebugRestApi.getSpecBySpecId(namespace, vmInfo.getSpecId()); + log.info("Retrieved spec for VM: {}", spec); + return spec; + } catch (Exception e) { + log.error("Error retrieving spec for VM: {}", e.getMessage()); + throw new ApplicationException("Failed to retrieve spec for VM : " + e.getMessage()); + } + } + + /** + * K8s 클러스터의 노드 스펙 정보를 조회합니다. + * + * @param namespace 네임스페이스 + * @param clusterName 클러스터 이름 + * @return K8s 노드의 스펙 정보 + */ + public K8sSpec getSpecForK8s(String namespace, String clusterName) { + log.info("Retrieving spec for K8s cluster: namespace={}, clusterName={}", namespace, clusterName); + try { + K8sClusterDto clusterInfo = cbtumblebugRestApi.getK8sClusterByName(namespace, clusterName); + if (clusterInfo == null || clusterInfo.getCspViewK8sClusterDetail() == null) { + throw new ApplicationException("Failed to retrieve K8s cluster info"); + } + + List nodeGroups = clusterInfo.getCspViewK8sClusterDetail().getNodeGroupList(); + if (nodeGroups == null || nodeGroups.isEmpty()) { + throw new ApplicationException("No node groups found for K8s cluster: " + clusterName); + } + + K8sClusterDto.NodeGroup firstNodeGroup = nodeGroups.get(0); + if (StringUtils.isBlank(firstNodeGroup.getVmSpecName())) { + throw new ApplicationException("VM spec name is blank for the first node group"); + } + + K8sSpec spec = cbtumblebugRestApi.lookupSpec(clusterInfo.getConnectionName(), firstNodeGroup.getVmSpecName()); + log.info("Retrieved spec for K8s cluster: {}", spec); + return spec; + } catch (Exception e) { + log.error("Error retrieving spec for K8s cluster: {}", e.getMessage()); + throw new ApplicationException("Failed to retrieve spec for K8s cluster : " + e.getMessage()); + } + } + +} \ No newline at end of file diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/docker/model/ContainerDeployResult.java b/src/main/java/kr/co/mcmp/softwarecatalog/docker/model/ContainerDeployResult.java new file mode 100644 index 0000000..c9415b2 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/docker/model/ContainerDeployResult.java @@ -0,0 +1,16 @@ +package kr.co.mcmp.softwarecatalog.docker.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ContainerDeployResult { + + private String containerId; + private String deploymentResult; + private boolean success; + +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/docker/model/ContainerHealthInfo.java b/src/main/java/kr/co/mcmp/softwarecatalog/docker/model/ContainerHealthInfo.java new file mode 100644 index 0000000..6d31500 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/docker/model/ContainerHealthInfo.java @@ -0,0 +1,19 @@ +package kr.co.mcmp.softwarecatalog.docker.model; + +import java.util.List; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class ContainerHealthInfo { + private String status; + private Integer servicePorts; + private Boolean isPortAccess; + private Double cpuUsage; + private Double memoryUsage; + private Double networkIn; + private Double networkOut; + private Boolean isHealthCheck; +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/docker/service/ContainerLogCollector.java b/src/main/java/kr/co/mcmp/softwarecatalog/docker/service/ContainerLogCollector.java new file mode 100644 index 0000000..bcfbe70 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/docker/service/ContainerLogCollector.java @@ -0,0 +1,63 @@ +package kr.co.mcmp.softwarecatalog.docker.service; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.springframework.stereotype.Component; + +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.model.Frame; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component +public class ContainerLogCollector { + + public List collectErrorLogs(DockerClient dockerClient, String containerId) throws InterruptedException { + return collectLogs(dockerClient, containerId, true); + } + + public List collectLogs(DockerClient dockerClient, String containerId) throws InterruptedException { + return collectLogs(dockerClient, containerId, false); + } + + private List collectLogs(DockerClient dockerClient, String containerId, boolean onlyErrors) throws InterruptedException { + List logs = new ArrayList<>(); + try (LogContainerCallback logsCallback = new LogContainerCallback(onlyErrors)) { + dockerClient.logContainerCmd(containerId) + .withStdErr(true) + .withStdOut(true) + .withTail(100) + .exec(logsCallback); + logsCallback.awaitCompletion(30, TimeUnit.SECONDS); + logs = logsCallback.getLogs(); + } catch (Exception e) { + log.error("Error fetching container logs", e); + } + return logs; + } + + private static class LogContainerCallback extends ResultCallback.Adapter { + private final List logs = new ArrayList<>(); + private final boolean onlyErrors; + + public LogContainerCallback(boolean onlyErrors) { + this.onlyErrors = onlyErrors; + } + + @Override + public void onNext(Frame item) { + String logLine = new String(item.getPayload()).trim(); + if (!onlyErrors || logLine.toLowerCase().contains("error") || logLine.toLowerCase().contains("exception")) { + logs.add(logLine); + } + } + + public List getLogs() { + return logs; + } + } +} \ No newline at end of file diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/docker/service/ContainerStatsCollector.java b/src/main/java/kr/co/mcmp/softwarecatalog/docker/service/ContainerStatsCollector.java new file mode 100644 index 0000000..53b8814 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/docker/service/ContainerStatsCollector.java @@ -0,0 +1,276 @@ +package kr.co.mcmp.softwarecatalog.docker.service; + +import java.net.InetSocketAddress; +import java.net.Socket; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.springframework.stereotype.Component; + +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.command.HealthState; +import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.model.Container; +import com.github.dockerjava.api.model.ContainerNetwork; +import com.github.dockerjava.api.model.CpuStatsConfig; +import com.github.dockerjava.api.model.CpuUsageConfig; +import com.github.dockerjava.api.model.ExposedPort; +import com.github.dockerjava.api.model.Ports; +import com.github.dockerjava.api.model.Statistics; + +import kr.co.mcmp.softwarecatalog.docker.model.ContainerHealthInfo; +import lombok.extern.slf4j.Slf4j; +@Slf4j +@Component +public class ContainerStatsCollector { + + public String getContainerId(DockerClient dockerClient, String containerName) { + try { + List containers = dockerClient.listContainersCmd().withShowAll(true).exec(); + return containers.stream() + .filter(container -> Arrays.asList(container.getNames()).contains("/" + containerName)) + .findFirst() + .map(Container::getId) + .orElse(null); + } catch (Exception e) { + log.error("Error getting container ID for {}", containerName, e); + return null; + } + } + + public ContainerHealthInfo collectContainerStats(DockerClient dockerClient, String containerId) { + try { + InspectContainerResponse containerInfo = dockerClient.inspectContainerCmd(containerId).exec(); + Statistics stats = collectStatistics(dockerClient, containerId); + Integer servicePort = getServicePort(containerInfo); + String ipAddress = getContainerIpAddress(containerInfo); + // List portAccessibilities = servicePorts.stream().map(port -> isPortAccessible(ipAddress, port)).collect(Collectors.toList()); + Boolean isPortAccessible = servicePort != null && ipAddress != null && isPortAccessible(ipAddress, servicePort); + Boolean isHealthCheck = isContainerHealthy(containerInfo); + + Double cpuUsage = calculateCpuUsage(stats); + Double memoryUsage = calculateMemoryUsage(stats); + Double networkIn = calculateNetworkIn(stats); + Double networkOut = calculateNetworkOut(stats); + + return ContainerHealthInfo.builder() + .status(mapContainerStatus(containerInfo.getState().getStatus())) + .servicePorts(servicePort) + .cpuUsage(cpuUsage) + .memoryUsage(memoryUsage) + .isPortAccess(isPortAccessible) + .isHealthCheck(isHealthCheck) + .networkIn(networkIn) + .networkOut(networkOut) + .build(); + } catch (Exception e) { + log.error("Error collecting container stats for {}", containerId, e); + return ContainerHealthInfo.builder() + .status("ERROR") + .build(); + } + } + + private String getContainerIpAddress(InspectContainerResponse containerInfo) { + try { + Map networks = containerInfo.getNetworkSettings().getNetworks(); + if (networks != null && !networks.isEmpty()) { + return networks.values().iterator().next().getIpAddress(); + } + } catch (Exception e) { + log.error("Error getting container IP address", e); + } + return null; + } + + private Statistics collectStatistics(DockerClient dockerClient, String containerId) { + try (StatsCallback statsCallback = new StatsCallback()) { + dockerClient.statsCmd(containerId).exec(statsCallback); + statsCallback.awaitCompletion(5, TimeUnit.SECONDS); + return statsCallback.getStats(); + } catch (Exception e) { + log.error("Error collecting statistics for {}", containerId, e); + return null; + } + } + + private boolean isContainerHealthy(InspectContainerResponse containerInfo) { + try { + InspectContainerResponse.ContainerState state = containerInfo.getState(); + if (state == null) { + return false; + } + HealthState health = state.getHealth(); + if (health == null) { + return "running".equalsIgnoreCase(state.getStatus()); + } + return "healthy".equalsIgnoreCase(health.getStatus()); + } catch (Exception e) { + log.error("Error checking container health", e); + return false; + } + } + + private Boolean isPortAccessible(String host, int port) { + try (Socket socket = new Socket()) { + socket.connect(new InetSocketAddress(host, port), 1000); + return true; + } catch (Exception e) { + log.debug("Port {} is not accessible on host {}", port, host); + return false; + } + } + /* + private List getServicePorts(InspectContainerResponse containerInfo) { + Ports ports = containerInfo.getNetworkSettings().getPorts(); + if (ports == null) { + return Collections.emptyList(); + } + + return ports.getBindings().entrySet().stream() + .flatMap(entry -> Arrays.stream(entry.getValue())) + .map(binding -> Integer.parseInt(binding.getHostPortSpec())) + .collect(Collectors.toList()); + } */ + + private Integer getServicePort(InspectContainerResponse containerInfo) { + try { + Ports ports = containerInfo.getNetworkSettings().getPorts(); + if (ports == null) { + return null; + } + + Map bindings = ports.getBindings(); + if (bindings == null || bindings.isEmpty()) { + return null; + } + + return bindings.entrySet().stream() + .flatMap(entry -> { + ExposedPort exposedPort = entry.getKey(); + Ports.Binding[] bindingsArray = entry.getValue(); + return bindingsArray != null ? Arrays.stream(bindingsArray) : Stream.empty(); + }) + .filter(Objects::nonNull) + .map(Ports.Binding::getHostPortSpec) + .filter(Objects::nonNull) + .map(Integer::parseInt) + .findFirst() + .orElse(null); + } catch (Exception e) { + log.error("Error getting service port", e); + return null; + } + } + + private String mapContainerStatus(String containerStatus) { + if (containerStatus == null) { + return "UNKNOWN"; + } + switch (containerStatus.toLowerCase()) { + case "running": + return "RUNNING"; + case "exited": + return "STOPPED"; + case "restarting": + return "RESTARTING"; + default: + return "UNKNOWN"; + } + } + + private Double calculateCpuUsage(Statistics stats) { + if (stats == null || stats.getCpuStats() == null || stats.getPreCpuStats() == null) { + return null; + } + try { + CpuStatsConfig cpuStats = stats.getCpuStats(); + CpuStatsConfig preCpuStats = stats.getPreCpuStats(); + CpuUsageConfig cpuUsage = cpuStats.getCpuUsage(); + CpuUsageConfig preCpuUsage = preCpuStats.getCpuUsage(); + + if (cpuUsage == null || preCpuUsage == null || + cpuUsage.getTotalUsage() == null || preCpuUsage.getTotalUsage() == null || + cpuStats.getSystemCpuUsage() == null || preCpuStats.getSystemCpuUsage() == null || + cpuStats.getOnlineCpus() == null) { + return null; + } + + Long cpuDelta = cpuUsage.getTotalUsage() - preCpuUsage.getTotalUsage(); + Long systemDelta = cpuStats.getSystemCpuUsage() - preCpuStats.getSystemCpuUsage(); + Long cpuCount = cpuStats.getOnlineCpus(); + + if (systemDelta > 0 && cpuCount > 0) { + double cpuUsagePercent = (cpuDelta.doubleValue() / systemDelta.doubleValue()) * cpuCount * 100.0; + return Math.round(cpuUsagePercent * 100.0) / 100.0; + } + } catch (Exception e) { + log.error("Error calculating CPU usage", e); + } + return null; + } + + private Double calculateMemoryUsage(Statistics stats) { + if (stats == null || stats.getMemoryStats() == null) { + return null; + } + try { + Long usedMemory = stats.getMemoryStats().getUsage(); + Long totalMemory = stats.getMemoryStats().getLimit(); + if (usedMemory != null && totalMemory != null && totalMemory > 0) { + double memoryUsage = (usedMemory.doubleValue() / totalMemory.doubleValue()) * 100.0; + return Math.round(memoryUsage * 100.0) / 100.0; + } + } catch (Exception e) { + log.error("Error calculating memory usage", e); + } + return null; + } + + private Double calculateNetworkIn(Statistics stats) { + if (stats == null || stats.getNetworks() == null) { + return null; + } + try { + return stats.getNetworks().values().stream() + .mapToDouble(net -> net.getRxBytes() != null ? net.getRxBytes().doubleValue() : 0.0) + .sum(); + } catch (Exception e) { + log.error("Error calculating network in", e); + return null; + } + } + + private Double calculateNetworkOut(Statistics stats) { + if (stats == null || stats.getNetworks() == null) { + return null; + } + try { + return stats.getNetworks().values().stream() + .mapToDouble(net -> net.getTxBytes() != null ? net.getTxBytes().doubleValue() : 0.0) + .sum(); + } catch (Exception e) { + log.error("Error calculating network out", e); + return null; + } + } + + private static class StatsCallback extends ResultCallback.Adapter { + private Statistics stats; + + @Override + public void onNext(Statistics stats) { + this.stats = stats; + } + + public Statistics getStats() { + return stats; + } + } +} \ No newline at end of file diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/docker/service/DockerClientFactory.java b/src/main/java/kr/co/mcmp/softwarecatalog/docker/service/DockerClientFactory.java new file mode 100644 index 0000000..ee4bc44 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/docker/service/DockerClientFactory.java @@ -0,0 +1,34 @@ +package kr.co.mcmp.softwarecatalog.docker.service; + +import java.time.Duration; + +import org.springframework.stereotype.Component; + +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.core.DefaultDockerClientConfig; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.core.DockerClientImpl; +import com.github.dockerjava.httpclient5.ApacheDockerHttpClient; +import com.github.dockerjava.transport.DockerHttpClient; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class DockerClientFactory { + + public DockerClient getDockerClient(String host) { + String dockerHost = "tcp://" + host + ":2375"; + DockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder() + .withDockerHost(dockerHost) + .build(); + DockerHttpClient httpClient = new ApacheDockerHttpClient.Builder() + .dockerHost(config.getDockerHost()) + .maxConnections(100) + .connectionTimeout(Duration.ofSeconds(30)) + .responseTimeout(Duration.ofSeconds(45)) + .build(); + return DockerClientImpl.getInstance(config, httpClient); + } + +} \ No newline at end of file diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/docker/service/DockerMonitoringService.java b/src/main/java/kr/co/mcmp/softwarecatalog/docker/service/DockerMonitoringService.java new file mode 100644 index 0000000..127246c --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/docker/service/DockerMonitoringService.java @@ -0,0 +1,132 @@ +package kr.co.mcmp.softwarecatalog.docker.service; + +import java.time.LocalDateTime; +import java.util.Comparator; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.github.dockerjava.api.DockerClient; + +import kr.co.mcmp.ape.cbtumblebug.api.CbtumblebugRestApi; +import kr.co.mcmp.softwarecatalog.SoftwareCatalog; +import kr.co.mcmp.softwarecatalog.application.model.ApplicationStatus; +import kr.co.mcmp.softwarecatalog.application.model.DeploymentHistory; +import kr.co.mcmp.softwarecatalog.application.repository.ApplicationStatusRepository; +import kr.co.mcmp.softwarecatalog.application.repository.DeploymentHistoryRepository; +import kr.co.mcmp.softwarecatalog.docker.model.ContainerHealthInfo; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Service +@Slf4j +@RequiredArgsConstructor +public class DockerMonitoringService { + + private final ApplicationStatusRepository applicationStatusRepository; + private final DeploymentHistoryRepository deploymentHistoryRepository; + private final DockerClientFactory dockerClientFactory; + private final ContainerStatsCollector containerStatsCollector; + private final ContainerLogCollector containerLogCollector; + private final CbtumblebugRestApi cbtumblebugRestApi; + + @Value("${docker.monitoring.interval:60000}") + private long monitoringInterval; + + @Scheduled(fixedRateString = "${docker.monitoring.interval:60000}") + @Transactional + public void monitorContainerHealth() { + log.info("Starting container health monitoring"); + List activeDeployments = getActiveDeployments(); + + for (DeploymentHistory deployment : activeDeployments) { + try { + updateContainerHealth(deployment); + } catch (Exception e) { + log.error("Error monitoring container for deployment: {}", deployment.getId(), e); + } + } + log.info("Container health monitoring completed"); + } + + private List getActiveDeployments() { + return deploymentHistoryRepository.findAll().stream() + .collect(Collectors.groupingBy(d -> d.getVmId() != null ? d.getVmId() : d.getClusterName())) + .values().stream() + .flatMap(deployments -> deployments.stream() + .collect(Collectors.groupingBy(DeploymentHistory::getCatalog)) + .values().stream() + .map(catalogDeployments -> catalogDeployments.stream() + .max(Comparator.comparing(DeploymentHistory::getExecutedAt)) + .orElse(null))) + .filter(Objects::nonNull) + .filter(d -> ("RUN".equalsIgnoreCase(d.getActionType().name()) || "INSTALL".equalsIgnoreCase(d.getActionType().name())) + && "SUCCESS".equalsIgnoreCase(d.getStatus())) + .collect(Collectors.toList()); + } + + + private void updateContainerHealth(DeploymentHistory deployment) { + ApplicationStatus status = applicationStatusRepository.findByCatalogId(deployment.getCatalog().getId()) + .orElse(new ApplicationStatus()); + + try (var dockerClient = dockerClientFactory.getDockerClient(deployment.getPublicIp())) { + String catalogTitle = deployment.getCatalog().getTitle().toLowerCase().replaceAll("\\s+", "-"); + String containerId = containerStatsCollector.getContainerId(dockerClient, catalogTitle); + log.debug("containerId: {}", containerId); + + if (containerId == null) { + status.setStatus("NOT_FOUND"); + applicationStatusRepository.save(status); + return; + } + + ContainerHealthInfo healthInfo = containerStatsCollector.collectContainerStats(dockerClient, containerId); + updateApplicationStatus(status, deployment, healthInfo); + if (isThresholdExceeded(deployment.getCatalog(), healthInfo)) { + List errorLogs = containerLogCollector.collectErrorLogs(dockerClient, containerId); + status.setErrorLogs(errorLogs); + } + + applicationStatusRepository.save(status); + } catch (Exception e) { + log.error("Failed to update container health for deployment: {}", deployment.getId(), e); + status.setStatus("ERROR"); + applicationStatusRepository.save(status); + } + } + + private boolean isThresholdExceeded(SoftwareCatalog catalog, ContainerHealthInfo healthInfo) { + if(healthInfo.getCpuUsage() != null && healthInfo.getMemoryUsage() != null){ + boolean cpuExceeded = catalog.getCpuThreshold() != null && healthInfo.getCpuUsage() > catalog.getCpuThreshold(); + boolean memoryExceeded = catalog.getMemoryThreshold() != null && healthInfo.getMemoryUsage() > catalog.getMemoryThreshold(); + return cpuExceeded || memoryExceeded; + } + return false; + } + + private void updateApplicationStatus(ApplicationStatus status, DeploymentHistory deployment, ContainerHealthInfo healthInfo) { + status.setCatalog(deployment.getCatalog()); + status.setStatus(healthInfo.getStatus()); + status.setDeploymentType(deployment.getDeploymentType()); + status.setNamespace(deployment.getNamespace()); + status.setMciId(deployment.getMciId()); + status.setIsPortAccessible(healthInfo.getIsPortAccess()); + status.setIsHealthCheck(healthInfo.getIsHealthCheck()); + status.setVmId(deployment.getVmId()); + status.setClusterName(deployment.getClusterName()); + status.setCheckedAt(LocalDateTime.now()); + status.setServicePort(healthInfo.getServicePorts()); + status.setPublicIp(deployment.getPublicIp()); + status.setCpuUsage(healthInfo.getCpuUsage()); + status.setMemoryUsage(healthInfo.getMemoryUsage()); + status.setNetworkIn(healthInfo.getNetworkIn()); + status.setNetworkOut(healthInfo.getNetworkOut()); + status.setExecutedBy(deployment.getExecutedBy() != null ? deployment.getExecutedBy() : null); + } +} \ No newline at end of file diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/docker/service/DockerOperationService.java b/src/main/java/kr/co/mcmp/softwarecatalog/docker/service/DockerOperationService.java new file mode 100644 index 0000000..9ceb92b --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/docker/service/DockerOperationService.java @@ -0,0 +1,175 @@ +package kr.co.mcmp.softwarecatalog.docker.service; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.springframework.stereotype.Service; + +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.command.CreateContainerCmd; +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.command.PullImageResultCallback; +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.api.model.Container; +import com.github.dockerjava.api.model.ExposedPort; +import com.github.dockerjava.api.model.HostConfig; +import com.github.dockerjava.api.model.PortBinding; +import com.github.dockerjava.api.model.Ports; + +import kr.co.mcmp.softwarecatalog.docker.model.ContainerDeployResult; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Service +@Slf4j +@RequiredArgsConstructor +public class DockerOperationService { + + private final DockerClientFactory dockerClientFactory; + + public ContainerDeployResult runDockerContainer(String host, Map deployParams) { + try (DockerClient dockerClient = dockerClientFactory.getDockerClient(host)) { + log.info("Docker client created successfully"); + String imageName = deployParams.get("image"); + log.info("Image name: {}", imageName); + + // 이미지 존재 여부 확인 및 pull + boolean imageExists = checkImageExists(dockerClient, imageName); + log.info("Image exists: {}", imageExists); + if (!imageExists) { + log.info("Pulling image: {}", imageName); + pullImage(dockerClient, imageName); + log.info("Image pulled successfully"); + } + + // 포트 바인딩 설정 + String[] portMapping = deployParams.get("portBindings").split(":"); + int hostPort = Integer.parseInt(portMapping[0]); + int containerPort = Integer.parseInt(portMapping[1]); + ExposedPort exposedPort = ExposedPort.tcp(containerPort); + Ports portBindings = new Ports(); + portBindings.bind(exposedPort, Ports.Binding.bindPort(hostPort)); + + // HostConfig 생성 + HostConfig hostConfig = HostConfig.newHostConfig().withPortBindings(portBindings); + + // 컨테이너 생성 + CreateContainerResponse container = dockerClient.createContainerCmd(imageName) + .withName(deployParams.get("name")) + .withHostConfig(hostConfig) + .withExposedPorts(exposedPort) + .exec(); + + String containerId = container.getId(); + log.info("Container created with ID: {}", containerId); + + // 컨테이너 시작 + dockerClient.startContainerCmd(containerId).exec(); + log.info("Container started: {}", containerId); + + boolean isRunning = waitForContainerToStart(dockerClient, containerId); + log.info("Container running status: {}", isRunning); + + return new ContainerDeployResult(containerId, "Container started", isRunning); + } catch (Exception e) { + log.error("Error running Docker container", e); + return new ContainerDeployResult(null, e.getMessage(), false); + } + } + + + + private boolean checkImageExists(DockerClient dockerClient, String imageName) { + try { + dockerClient.inspectImageCmd(imageName).exec(); + return true; + } catch (NotFoundException e) { + return false; + } + } + + private void pullImage(DockerClient dockerClient, String imageName) throws InterruptedException { + try { + dockerClient.pullImageCmd(imageName) + .exec(new PullImageResultCallback()) + .awaitCompletion(5, TimeUnit.MINUTES); + } catch (NotFoundException e) { + log.error("Image not found: {}", imageName); + throw e; + } + } + private boolean waitForContainerToStart(DockerClient dockerClient, String containerId) throws InterruptedException { + for (int i = 0; i < 30; i++) { + InspectContainerResponse containerInfo = dockerClient.inspectContainerCmd(containerId).exec(); + if (containerInfo.getState().getRunning()) { + return true; + } + Thread.sleep(1000); + } + return false; + } + + public String getDockerContainerStatus(String host, String containerId) { + try (DockerClient dockerClient = dockerClientFactory.getDockerClient(host)) { + return dockerClient.inspectContainerCmd(containerId) + .exec() + .getState() + .getStatus(); + } catch (Exception e) { + log.error("Error getting Docker container status", e); + return "ERROR"; + } + } + + public String stopDockerContainer(String host, String containerId) { + try (DockerClient dockerClient = dockerClientFactory.getDockerClient(host)) { + dockerClient.stopContainerCmd(containerId).exec(); + return "Container stopped successfully"; + } catch (Exception e) { + log.error("Error stopping Docker container", e); + return "Error: " + e.getMessage(); + } + } + + public String removeDockerContainer(String host, String containerId) { + try (DockerClient dockerClient = dockerClientFactory.getDockerClient(host)) { + dockerClient.removeContainerCmd(containerId) + .withForce(true) + .withRemoveVolumes(true) + .exec(); + return "Container removed successfully"; + } catch (Exception e) { + log.error("Error removing Docker container", e); + return "Error: " + e.getMessage(); + } + } + + public String restartDockerContainer(String host, String containerId) { + try (DockerClient dockerClient = dockerClientFactory.getDockerClient(host)) { + dockerClient.restartContainerCmd(containerId).exec(); + return "Container restarted successfully"; + } catch (Exception e) { + log.error("Error restarting Docker container", e); + return "Error: " + e.getMessage(); + } + } + + public boolean isContainerRunning(String host, String containerId) { + try (DockerClient dockerClient = dockerClientFactory.getDockerClient(host)) { + return isContainerRunning(dockerClient, containerId); + } catch (Exception e) { + log.error("Error checking if container is running", e); + return false; + } + } + + private boolean isContainerRunning(DockerClient dockerClient, String containerId) { + List containers = dockerClient.listContainersCmd() + .withShowAll(true) + .exec(); + return containers.stream() + .anyMatch(container -> container.getId().equals(containerId) && "running".equalsIgnoreCase(container.getState())); + } +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/docker/service/DockerSetupService.java b/src/main/java/kr/co/mcmp/softwarecatalog/docker/service/DockerSetupService.java new file mode 100644 index 0000000..cb64a98 --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/docker/service/DockerSetupService.java @@ -0,0 +1,115 @@ +package kr.co.mcmp.softwarecatalog.docker.service; + +import org.springframework.stereotype.Service; +import kr.co.mcmp.ape.cbtumblebug.api.CbtumblebugRestApi; +import kr.co.mcmp.softwarecatalog.application.exception.ApplicationException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Service +@Slf4j +@RequiredArgsConstructor +public class DockerSetupService { + + private final CbtumblebugRestApi cbtumblebugRestApi; + + public void checkAndInstallDocker(String namespace, String mciId, String vmId) throws ApplicationException { + log.info("Checking Docker installation for namespace: {}, mciId: {}, vmId: {}", namespace, mciId, vmId); + String checkDockerCommand = "docker --version && ps aux | grep dockerd | grep -q -- '-H tcp://0.0.0.0:2375' && echo 'Remote API enabled' || echo 'Remote API not enabled'"; + try { + String result = cbtumblebugRestApi.executeMciCommand(namespace, mciId, checkDockerCommand, null, vmId); + log.info("Docker check result: {}", result); + if (!result.contains("Docker version") || !result.contains("Remote API enabled")) { + log.warn("Docker is not installed or remote API is not enabled. Installing/configuring Docker..."); + installAndConfigureDockerOnVM(namespace, mciId, vmId); + } else { + log.info("Docker is already installed and configured for remote access on VM: {}", vmId); + } + } catch (Exception e) { + log.error("Error checking Docker installation", e); + throw new ApplicationException("Failed to check Docker installation: " + e.getMessage()); + } + } + + private void installAndConfigureDockerOnVM(String namespace, String mciId, String vmId) throws ApplicationException { + log.info("Starting Docker installation and configuration for namespace: {}, mciId: {}, vmId: {}", namespace, mciId, vmId); + try { + installDocker(namespace, mciId, vmId); + configureDockerForRemoteAccess(namespace, mciId, vmId); + setDockerPermissions(namespace, mciId, vmId); + enableBridgeNfCallIptables(namespace, mciId, vmId); + configureSSHForDockerAccess(namespace, mciId, vmId); + restartDocker(namespace, mciId, vmId); + verifyDockerConfiguration(namespace, mciId, vmId); + } catch (Exception e) { + log.error("Error installing or configuring Docker", e); + throw new ApplicationException("Failed to install or configure Docker: " + e.getMessage()); + } + } + + + private void installDocker(String namespace, String mciId, String vmId) throws Exception { + String installDockerCommand = + "curl -fsSL https://get.docker.com -o get-docker.sh && " + + "sudo sh get-docker.sh && " + + "sudo usermod -aG docker $USER && " + + "sudo systemctl enable docker"; + + String result = cbtumblebugRestApi.executeMciCommand(namespace, mciId, installDockerCommand, null, vmId); + log.info("Docker installation result: {}", result); + } + + private void configureDockerForRemoteAccess(String namespace, String mciId, String vmId) throws Exception { + String configureDockerCommand = + "sudo mkdir -p /etc/systemd/system/docker.service.d && " + + "echo '[Service]' | sudo tee /etc/systemd/system/docker.service.d/override.conf && " + + "echo 'ExecStart=' | sudo tee -a /etc/systemd/system/docker.service.d/override.conf && " + + "echo 'ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock' | sudo tee -a /etc/systemd/system/docker.service.d/override.conf && " + + "sudo systemctl daemon-reload"; + + String result = cbtumblebugRestApi.executeMciCommand(namespace, mciId, configureDockerCommand, null, vmId); + log.info("Docker remote access configuration result: {}", result); + } + + private void configureSSHForDockerAccess(String namespace, String mciId, String vmId) throws Exception { + String configureSSHCommand = + "sudo sed -i 's/^#*PubkeyAcceptedAlgorithms.*/PubkeyAcceptedAlgorithms=+ssh-rsa/' /etc/ssh/sshd_config && " + + "sudo systemctl restart sshd"; + + String result = cbtumblebugRestApi.executeMciCommand(namespace, mciId, configureSSHCommand, null, vmId); + log.info("SSH configuration for Docker access result: {}", result); + } + + private void setDockerPermissions(String namespace, String mciId, String vmId) throws Exception { + String setPermissionsCommand = "sudo chmod 666 /var/run/docker.sock"; + String result = cbtumblebugRestApi.executeMciCommand(namespace, mciId, setPermissionsCommand, null, vmId); + log.info("Docker permissions setting result: {}", result); + } + + private void enableBridgeNfCallIptables(String namespace, String mciId, String vmId) throws Exception { + String command = + "echo 'net.bridge.bridge-nf-call-iptables = 1' | sudo tee -a /etc/sysctl.conf && " + + "echo 'net.bridge.bridge-nf-call-ip6tables = 1' | sudo tee -a /etc/sysctl.conf && " + + "sudo sysctl -p"; + + String result = cbtumblebugRestApi.executeMciCommand(namespace, mciId, command, null, vmId); + log.info("Bridge-nf-call-iptables configuration result: {}", result); + } + + private void restartDocker(String namespace, String mciId, String vmId) throws Exception { + String restartCommand = "sudo systemctl restart docker"; + String result = cbtumblebugRestApi.executeMciCommand(namespace, mciId, restartCommand, null, vmId); + log.info("Docker restart result: {}", result); + } + + private void verifyDockerConfiguration(String namespace, String mciId, String vmId) throws Exception { + String verifyCommand = "ps aux | grep dockerd | grep -q -- '-H tcp://0.0.0.0:2375' && echo 'Remote API enabled' || echo 'Remote API not enabled'"; + String result = cbtumblebugRestApi.executeMciCommand(namespace, mciId, verifyCommand, null, vmId); + + if (!result.contains("Remote API enabled")) { + throw new ApplicationException("Failed to configure Docker for remote access"); + } + + log.info("Docker configuration verified successfully"); + } +} \ No newline at end of file diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/users/Entity/User.java b/src/main/java/kr/co/mcmp/softwarecatalog/users/Entity/User.java new file mode 100644 index 0000000..6ea868b --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/users/Entity/User.java @@ -0,0 +1,64 @@ +package kr.co.mcmp.softwarecatalog.users.Entity; + +import java.time.LocalDateTime; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.PrePersist; +import javax.persistence.PreUpdate; +import javax.persistence.Table; + +import lombok.Getter; +import lombok.Setter; + +@Entity +@Table(name = "USERS") +@Getter +@Setter +public class User { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; // 사용자의 고유 식별자 + + @Column(nullable = false, unique = true) + private String username; // 사용자 이름 (로그인 ID) + + // @Column(name = "phone_number") + // private String phoneNumber; // 전화번호 + + // @Enumerated(EnumType.STRING) + // @Column(nullable = false) + // private UserRole role; // 사용자 역할 (예: ADMIN, USER, MANAGER 등) + + // @Column(name = "is_active", nullable = false) + // private boolean isActive; // 계정 활성화 상태 + + // @Column(name = "last_login") + // private LocalDateTime lastLogin; // 마지막 로그인 시간 + + // @Column(name = "created_at", nullable = false) + // private LocalDateTime createdAt; // 계정 생성 시간 + + // @Column(name = "updated_at") + // private LocalDateTime updatedAt; // 계정 정보 최종 수정 시간 + + // @PrePersist + // protected void onCreate() { + // createdAt = LocalDateTime.now(); + // } + + // @PreUpdate + // protected void onUpdate() { + // updatedAt = LocalDateTime.now(); + // } + +} + +// public enum UserRole { +// ADMIN, USER, MANAGER +// } \ No newline at end of file diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/users/dto/UserDTO.java b/src/main/java/kr/co/mcmp/softwarecatalog/users/dto/UserDTO.java new file mode 100644 index 0000000..a2a181a --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/users/dto/UserDTO.java @@ -0,0 +1,39 @@ +package kr.co.mcmp.softwarecatalog.users.dto; + +import java.time.LocalDateTime; + +import kr.co.mcmp.softwarecatalog.users.Entity.User; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +public class UserDTO { + private Long id; + private String username; + // private String email; + // private String firstName; + // private String lastName; + // private String phoneNumber; + // private UserRole role; + // private boolean isActive; + // private LocalDateTime lastLogin; + // private LocalDateTime createdAt; + // private LocalDateTime updatedAt; + + public UserDTO(User entity) { + this.id = entity.getId(); + this.username = entity.getUsername(); + // this.email = entity.getEmail(); + // this.firstName = entity.getFirstName(); + // this.lastName = entity.getLastName(); + // this.phoneNumber = entity.getPhoneNumber(); + // this.role = entity.getRole(); + // this.isActive = entity.isActive(); + // this.lastLogin = entity.getLastLogin(); + // this.createdAt = entity.getCreatedAt(); + // this.updatedAt = entity.getUpdatedAt(); + } +} \ No newline at end of file diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/users/repository/UserRepository.java b/src/main/java/kr/co/mcmp/softwarecatalog/users/repository/UserRepository.java new file mode 100644 index 0000000..26bf9bf --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/users/repository/UserRepository.java @@ -0,0 +1,11 @@ +package kr.co.mcmp.softwarecatalog.users.repository; + +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; + +import kr.co.mcmp.softwarecatalog.users.Entity.User; + +public interface UserRepository extends JpaRepository { + Optional findByUsername(String username); +} diff --git a/src/main/java/kr/co/mcmp/softwarecatalog/users/service/UserService.java b/src/main/java/kr/co/mcmp/softwarecatalog/users/service/UserService.java new file mode 100644 index 0000000..0c4cffd --- /dev/null +++ b/src/main/java/kr/co/mcmp/softwarecatalog/users/service/UserService.java @@ -0,0 +1,105 @@ +package kr.co.mcmp.softwarecatalog.users.service; + +import java.util.Optional; + +import javax.persistence.EntityNotFoundException; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import kr.co.mcmp.softwarecatalog.users.Entity.User; +import kr.co.mcmp.softwarecatalog.users.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Service +@RequiredArgsConstructor +@Slf4j +public class UserService { + + + private final UserRepository userRepository; + + @Transactional(readOnly = true) + public User getUserByUsername(String username) { + if (username == null || username.trim().isEmpty()) { + throw new IllegalArgumentException("Username cannot be null or empty"); + } + + try { + Optional userOpt = userRepository.findByUsername(username); + return userOpt.orElseThrow(() -> { + return new EntityNotFoundException("User not found with username: " + username); + }); + } catch (Exception e) { + throw new IllegalArgumentException("Error occurred while fetching user", e); + } + } + + @Transactional(readOnly = true) + public Optional findUserByUsername(String username) { + if (username == null || username.trim().isEmpty()) { + return Optional.empty(); + } + + try { + return userRepository.findByUsername(username); + } catch (Exception e) { + throw new IllegalArgumentException("Error occurred while finding user", e); + } + } + + @Transactional + public User createUser(User user) { + if (user == null) { + throw new IllegalArgumentException("User cannot be null"); + } + + try { + if (userRepository.findByUsername(user.getUsername()).isPresent()) { + throw new IllegalArgumentException("User already exists with username: " + user.getUsername()); + } + return userRepository.save(user); + } catch (Exception e) { + throw new IllegalArgumentException("Error occurred while creating user", e); + } + } + + @Transactional + public User updateUser(User user) { + if (user == null || user.getId() == null) { + throw new IllegalArgumentException("User and user ID cannot be null"); + } + + try { + Optional existingUserOpt = userRepository.findById(user.getId()); + if (existingUserOpt.isPresent()) { + User existingUser = existingUserOpt.get(); + existingUser.setUsername(user.getUsername()); + return userRepository.save(existingUser); + } else { + throw new EntityNotFoundException("User not found with ID: " + user.getId()); + } + } catch (Exception e) { + throw new IllegalArgumentException("Error occurred while updating user", e); + } + } + + @Transactional + public void deleteUser(Long userId) { + if (userId == null) { + throw new IllegalArgumentException("User ID cannot be null"); + } + + try { + if (userRepository.existsById(userId)) { + userRepository.deleteById(userId); + } else { + throw new EntityNotFoundException("User not found with ID: " + userId); + } + } catch (Exception e) { + throw new IllegalArgumentException("Error occurred while deleting user", e); + } + } + +} diff --git a/src/main/java/kr/co/mcmp/tablehistory/TableHistoryDto.java b/src/main/java/kr/co/mcmp/tablehistory/TableHistoryDto.java deleted file mode 100644 index 1c642da..0000000 --- a/src/main/java/kr/co/mcmp/tablehistory/TableHistoryDto.java +++ /dev/null @@ -1,30 +0,0 @@ -package kr.co.mcmp.tablehistory; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.Setter; - -import java.util.List; -import java.util.stream.Collectors; - -@Getter -@Setter -@Builder -@AllArgsConstructor -public class TableHistoryDto { - - private String tablename; - - private String action; - - private String actionDate; - - private String user; - - public List setLisEntityToListDto(List historyEntity){ - return historyEntity.stream().map(TableHistoryEntity::toDto).collect(Collectors.toList()); - } - - -} diff --git a/src/main/java/kr/co/mcmp/tablehistory/TableHistoryEntity.java b/src/main/java/kr/co/mcmp/tablehistory/TableHistoryEntity.java deleted file mode 100644 index 4b094a3..0000000 --- a/src/main/java/kr/co/mcmp/tablehistory/TableHistoryEntity.java +++ /dev/null @@ -1,45 +0,0 @@ -package kr.co.mcmp.tablehistory; - -import lombok.*; - -import javax.persistence.*; - -@Entity -@Getter -@Setter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@Table(name="ACTION_HISTORY") -//@ToString(exclude = {"TABLE_HISTORY"}) -public class TableHistoryEntity { - - @Id - @GeneratedValue(strategy= GenerationType.IDENTITY) - @Column(columnDefinition="INT", name="ID") - private Integer id; - - @Column(columnDefinition="VARCHAR(30) NOT NULL", name="TABLENAME") - private String tablename; - - @Column(columnDefinition="VARCHAR(10) NOT NULL", name="ACTION") - private String action; - - @Column(columnDefinition="DATETIME NOT NULL DEFAULT NOW()", name="ACTION_DATE") - private String actionDate; - - @Column(columnDefinition="VARCHAR(50)", name="USER") - private String user; - - @Builder - public TableHistoryEntity(TableHistoryDto dto){ - this.tablename = dto.getTablename(); - this.action = dto.getAction(); - this.actionDate = dto.getActionDate(); - this.user = dto.getUser(); - } - - public TableHistoryDto toDto(){ - return new TableHistoryDto(tablename, action, actionDate, user); - } - - -} diff --git a/src/main/java/kr/co/mcmp/tablehistory/TableHistoryRepository.java b/src/main/java/kr/co/mcmp/tablehistory/TableHistoryRepository.java deleted file mode 100644 index 8323322..0000000 --- a/src/main/java/kr/co/mcmp/tablehistory/TableHistoryRepository.java +++ /dev/null @@ -1,13 +0,0 @@ -package kr.co.mcmp.tablehistory; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -import java.util.List; - -@Repository -public interface TableHistoryRepository extends JpaRepository { - - List findByTablename(String tablename); - -} diff --git a/src/main/java/kr/co/mcmp/tablehistory/TableHistoryService.java b/src/main/java/kr/co/mcmp/tablehistory/TableHistoryService.java deleted file mode 100644 index ec2f2ff..0000000 --- a/src/main/java/kr/co/mcmp/tablehistory/TableHistoryService.java +++ /dev/null @@ -1,39 +0,0 @@ -package kr.co.mcmp.tablehistory; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.ArrayList; -import java.util.List; - -@Service -public class TableHistoryService { - - @Autowired - TableHistoryRepository tableRepo; - - public void setHistory(TableHistoryDto tableHistoryDto){ - TableHistoryEntity tblEntity = new TableHistoryEntity(tableHistoryDto); - tableRepo.save(tblEntity); - } - - public List getHistory(TableHistoryDto tableHistoryDto){ - - List historyEntityList = tableRepo.findByTablename(tableHistoryDto.getTablename()); - List tableHistoryDtoList = new ArrayList<>(); - - for(TableHistoryEntity e : historyEntityList){ - TableHistoryDto d = TableHistoryDto.builder() - .tablename(e.getTablename()) - .action(e.getAction()) - .actionDate(e.getActionDate()) - .user(e.getUser()).build(); - tableHistoryDtoList.add(d); - } - - return tableHistoryDtoList; - - } - - -} diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index dca13ca..a147c18 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -28,6 +28,7 @@ spring: generate-ddl: true hibernate: ddl-auto: ${DDL_AUTO:update} # ${DDL_AUTO:none} + # ddl-auto: create # 실행할 때에 테이블을 자동으로 생성시킬것인지 #create-drop, update, validate, none # create : SessionFactory 시작시 스키마를 삭제하고 다시 생성 # create-drop : SessionFactory 종료 시 스키마를 삭제 @@ -39,7 +40,7 @@ spring: hibernate: dialect: org.hibernate.dialect.H2Dialect format_sql: true - show_sql: true + show_sql: false hbm2ddl: # 처음에 더미데이터등을 넣기위해 sql을 실행 #import_files: ./data.sql # 확인필요 import_files: @@ -65,14 +66,18 @@ aes: key: fb1755281b0ca6184a0ee644e6477ee7 cbtumblebug: - url: ${TUMBLEBUG_URL:3.38.179.21} + url: ${TUMBLEBUG_URL:210.217.178.130} port: ${TUMBLEBUG_PORT:1323} id: ${TUMBLEBUG_ID:default} pass: ${TUMBLEBUG_PASSWORD:default} +docker: + monitoring: + interval: 60000 # 밀리초 단위, 기본값은 60000 (1분) + file: upload: path: windows: C:/mcmp/uploads/ linux: /home/mcmp/uploads/ - allowed-extensions: jpg,jpeg,png,gif \ No newline at end of file + allowed-extensions: jpg,jpeg,png,gif diff --git a/src/main/resources/import.sql b/src/main/resources/import.sql index 8263e6d..a6f19b1 100644 --- a/src/main/resources/import.sql +++ b/src/main/resources/import.sql @@ -1,102 +1,329 @@ -INSERT INTO SOFTWARE_CATALOG(TITLE, DESCRIPTION, SUMMARY, ICON, CATEGORY, RECOMMENDED_CPU, RECOMMENDED_MEMORY , RECOMMENDED_DISK, ENABLE_HPA, HPA_CPU_UTILIZATION, HPA_MAX_REPLICAS, HPA_MEMORY_UTILIZATION, HPA_MIN_REPLICAS ) -VALUES - ('APACHE TOMCAT', 'The Apache Tomcat software is an open source implementation of the Jakarta Servlet, Jakarta Pages, Jakarta Expression Language, Jakarta WebSocket, Jakarta Annotations and Jakarta Authentication specifications. These specifications are part of the Jakarta EE platform.\n\nThe Jakarta EE platform is the evolution of the Java EE platform. Tomcat 10 and later implement specifications developed as part of Jakarta EE. Tomcat 9 and earlier implement specifications developed as part of Java EE.\n\nThe Apache Tomcat software is developed in an open and participatory environment and released under the Apache License version 2. The Apache Tomcat project is intended to be a collaboration of the best-of-breed developers from around the world. We invite you to participate in this open development project. To learn more about getting involved, click here.\n\nApache Tomcat software powers numerous large-scale, mission-critical web applications across a diverse range of industries and organizations. Some of these users and their stories are listed on the PoweredBy wiki page.\n\nApache Tomcat, Tomcat, Apache, the Apache feather, and the Apache Tomcat project logo are trademarks of the Apache Software Foundation.', 'open source java web application server', '/images/tomcat.png', 'WAS', 1, 2, 5, false, null, null, null, null); -INSERT INTO SOFTWARE_CATALOG(TITLE, DESCRIPTION, SUMMARY, ICON, CATEGORY, RECOMMENDED_CPU, RECOMMENDED_MEMORY , RECOMMENDED_DISK, ENABLE_HPA, HPA_CPU_UTILIZATION, HPA_MAX_REPLICAS, HPA_MEMORY_UTILIZATION, HPA_MIN_REPLICAS ) -VALUES - ('REDIS', 'Redis is an in-memory data store used by millions of developers as a cache, vector database, document database, streaming engine, and message broker. Redis has built-in replication and different levels of on-disk persistence. It supports complex data types (for example, strings, hashes, lists, sets, sorted sets, and JSON), with atomic operations defined on those data types.\n\nYou can install Redis from source, from an executable for your OS, or bundled with Redis Stack and Redis Insight which include popular features and monitoring.', 'in memory db', '/images/redis.png', 'DB',1, 2, 5, false, null, null, null, null); -INSERT INTO SOFTWARE_CATALOG(TITLE, DESCRIPTION, SUMMARY, ICON, CATEGORY, RECOMMENDED_CPU, RECOMMENDED_MEMORY , RECOMMENDED_DISK, ENABLE_HPA, HPA_CPU_UTILIZATION, HPA_MAX_REPLICAS, HPA_MEMORY_UTILIZATION, HPA_MIN_REPLICAS ) -VALUES - ('NGINX', 'nginx [engine x] is an HTTP and reverse proxy server, a mail proxy server, and a generic TCP/UDP proxy server, originally written by Igor Sysoev. For a long time, it has been running on many heavily loaded Russian sites including Yandex, Mail.Ru, VK, and Rambler. Here are some of the success stories: Dropbox, Netflix, FastMail.FM.\n\nThe sources and documentation are distributed under the 2-clause BSD-like license.\n\nCommercial support is available from F5, Inc.', 'web/proxy server', '/images/nginx.png', 'WEB SERVER',1, 2, 5, false, null, null, null, null); -INSERT INTO SOFTWARE_CATALOG(TITLE, DESCRIPTION, SUMMARY, ICON, CATEGORY, RECOMMENDED_CPU, RECOMMENDED_MEMORY , RECOMMENDED_DISK, ENABLE_HPA, HPA_CPU_UTILIZATION, HPA_MAX_REPLICAS, HPA_MEMORY_UTILIZATION, HPA_MIN_REPLICAS ) -VALUES - ('APACHE', 'The Apache HTTP Server Project is an effort to develop and maintain an open-source HTTP server for modern operating systems including UNIX and Windows. The goal of this project is to provide a secure, efficient and extensible server that provides HTTP services in sync with the current HTTP standards.\n\nThe Apache HTTP Server ("httpd") was launched in 1995 and it has been the most popular web server on the Internet since April 1996. It has celebrated its 25th birthday as a project in February 2020.\n\nThe Apache HTTP Server is a project of The Apache Software Foundation.', 'web server', '/images/apache.png', 'WEB SERVER',1, 2, 5, false,null, null, null, null); -INSERT INTO SOFTWARE_CATALOG(TITLE, DESCRIPTION, SUMMARY, ICON, CATEGORY, RECOMMENDED_CPU, RECOMMENDED_MEMORY , RECOMMENDED_DISK, ENABLE_HPA, HPA_CPU_UTILIZATION, HPA_MAX_REPLICAS, HPA_MEMORY_UTILIZATION, HPA_MIN_REPLICAS ) -VALUES - ('NEXUS', 'Build fast with the world''s leading artifact repository manager\n\nCentralize\nGive your teams a single source of truth for every component.\n\nStore\nOptimize build performance and storage costs by caching artifacts.\n\nDevelop\nSupport up to 18 package formats in a single deployment.\n\nScale\nDeploy highly available clusters, edge nodes, and test servers freely without per-node charges.\n', 'repository', '/images/nexus.png', 'WEB SERVER', false,1, 2, 5, null, null, null, null); -INSERT INTO SOFTWARE_CATALOG(TITLE, DESCRIPTION, SUMMARY, ICON, CATEGORY, RECOMMENDED_CPU, RECOMMENDED_MEMORY , RECOMMENDED_DISK, ENABLE_HPA, HPA_CPU_UTILIZATION, HPA_MAX_REPLICAS, HPA_MEMORY_UTILIZATION, HPA_MIN_REPLICAS ) -VALUES - ('MARIA DB', 'MariaDB Server is one of the most popular open source relational databases. It''s made by the original developers of MySQL and guaranteed to stay open source. It is part of most cloud offerings and the default in most Linux distributions.\n\nIt is built upon the values of performance, stability, and openness, and MariaDB Foundation ensures contributions will be accepted on technical merit. Recent new functionality includes advanced clustering with Galera Cluster 4, compatibility features with Oracle Database and Temporal Data Tables, allowing one to query the data as it stood at any point in the past.', 'database', '/images/mariadb.png', 'RDBMS',1, 2, 5, false,null, null, null, null); -INSERT INTO SOFTWARE_CATALOG(TITLE, DESCRIPTION, SUMMARY, ICON, CATEGORY, RECOMMENDED_CPU, RECOMMENDED_MEMORY , RECOMMENDED_DISK, ENABLE_HPA, HPA_CPU_UTILIZATION, HPA_MAX_REPLICAS, HPA_MEMORY_UTILIZATION, HPA_MIN_REPLICAS ) -VALUES - ('GRAFANA', 'Your observability stack, faster and easier\n\nWith Grafana Cloud, enable observability - from operational dashboards to a fully centralized system and everything in between - without the overhead of building and maintaining your own stack.', 'observability', '/images/grafana.jpg', 'OBSERVABILITY',1, 2, 5, false, null, null, null, null); +-- SoftwareCatalog 데이터 +INSERT INTO SOFTWARE_CATALOG (TITLE, DESCRIPTION, SUMMARY, CATEGORY, SOURCE_TYPE, LOGO_URL_LARGE, LOGO_URL_SMALL, MIN_CPU, RECOMMENDED_CPU, MIN_MEMORY, RECOMMENDED_MEMORY, MIN_DISK, RECOMMENDED_DISK, CPU_THRESHOLD, MEMORY_THRESHOLD, MIN_REPLICAS, MAX_REPLICAS, HPA_ENABLED, CREATED_AT, UPDATED_AT) VALUES +('Apache Tomcat', 'Apache Tomcat is an open-source implementation of the Java Servlet, JavaServer Pages, Java Expression Language and Java WebSocket technologies.', 'Open-source Java web application server', 'WAS', 'DOCKERHUB', 'https://djeqr6to3dedg.cloudfront.net/repo-logos/library/tomcat/live/logo-1720462300603.png', 'https://djeqr6to3dedg.cloudfront.net/repo-logos/library/tomcat/live/logo-1720462300603.png', 1, 2, 256, 512, 1, 2, 80.0, 80.0, 1, 5, false, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), +('Redis', 'Redis is an open source, in-memory data structure store, used as a database, cache, and message broker.', 'In-memory data structure store', 'DB', 'DOCKERHUB', 'https://djeqr6to3dedg.cloudfront.net/repo-logos/library/redis/live/logo-1720462263103.png', 'https://djeqr6to3dedg.cloudfront.net/repo-logos/library/redis/live/logo-1720462263103.png', 2, 2, 512, 4096, 0.5, 1, 80.0, 80.0, 1, 5, false, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), +('Nginx', 'NGINX is a free, open-source, high-performance HTTP server and reverse proxy, as well as an IMAP/POP3 proxy server.', 'High-performance HTTP server', 'WEB SERVER', 'DOCKERHUB', 'https://djeqr6to3dedg.cloudfront.net/repo-logos/library/nginx/live/logo-1720462242584.png', 'https://djeqr6to3dedg.cloudfront.net/repo-logos/library/nginx/live/logo-1720462242584.png', 1, 2, 128, 256, 0.5, 1, 80.0, 80.0, 1, 5, false, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), +('Apache HTTP Server', 'The Apache HTTP Server is a powerful, flexible, HTTP/1.1 compliant web server.', 'Popular web server', 'WEB SERVER', 'DOCKERHUB', 'https://www.gravatar.com/avatar/d57617e2eca42ca07dfc380b85585d64?s=80&r=g&d=mm', 'https://www.gravatar.com/avatar/d57617e2eca42ca07dfc380b85585d64?s=80&r=g&d=mm', 1, 2, 256, 512, 0.5, 1, 80.0, 80.0, 1, 5, false, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), +('Nexus Repository', 'Nexus Repository OSS is an open source repository that supports many artifact formats.', 'Artifact repository manager', 'REPOSITORY', 'DOCKERHUB', 'https://www.gravatar.com/avatar/614e0f6491dbb293e540190b02b3024e?s=80&r=g&d=mm', 'https://www.gravatar.com/avatar/614e0f6491dbb293e540190b02b3024e?s=80&r=g&d=mm', 4, 8, 4096, 8192, 2, 4, 80.0, 80.0, 1, 3, true, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), +('MariaDB', 'MariaDB is a community-developed, commercially supported fork of the MySQL relational database management system.', 'Open-source relational database', 'RDBMS', 'DOCKERHUB', 'https://djeqr6to3dedg.cloudfront.net/repo-logos/library/mariadb/live/logo-1720462226239.png', 'https://djeqr6to3dedg.cloudfront.net/repo-logos/library/mariadb/live/logo-1720462226239.png', 1, 4, 1024, 4096, 2, 4, 80.0, 80.0, 1, 3, false, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), +('Grafana', 'Grafana is an open-source platform for monitoring and observability.', 'Monitoring and visualization platform', 'OBSERVABILITY', 'ARTIFACTHUB', 'https://www.gravatar.com/avatar/31cea69afa424609b2d83621b4d47f1d?s=80&r=g&d=mm', 'https://www.gravatar.com/avatar/31cea69afa424609b2d83621b4d47f1d?s=80&r=g&d=mm', 2, 4, 2048, 4096, 1, 2, 80.0, 80.0, 1, 3, true, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), +('Prometheus', 'Prometheus is an open-source systems monitoring and alerting toolkit.', 'Monitoring and alerting toolkit', 'MONITORING', 'DOCKERHUB', 'https://www.gravatar.com/avatar/85bcf547a6bf62b855df2c682af81a4e?s=80&r=g&d=mm', 'https://www.gravatar.com/avatar/85bcf547a6bf62b855df2c682af81a4e?s=80&r=g&d=mm', 2, 4, 2048, 4096, 1, 2, 80.0, 80.0, 1, 3, true, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +-- PackageInfo 데이터 (DockerHub 기반) +INSERT INTO PACKAGE_INFO ( + CATALOG_ID, + PACKAGE_TYPE, + PACKAGE_NAME, + PACKAGE_VERSION, + REPOSITORY_URL, + DOCKER_IMAGE_ID, + DOCKER_PUBLISHER, + DOCKER_CREATED_AT, + DOCKER_UPDATED_AT, + DOCKER_SHORT_DESCRIPTION, + DOCKER_SOURCE, + ARCHITECTURES, + CATEGORIES, + IS_ARCHIVED, + IS_AUTOMATED, + IS_OFFICIAL, + LAST_PULLED_AT, + OPERATING_SYSTEMS, + PULL_COUNT, + STAR_COUNT +) VALUES +((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'Apache Tomcat'), + 'DOCKER', 'tomcat', 'latest', 'https://hub.docker.com/_/tomcat', + NULL, 'library', '2014-10-27 17:28:47.715247', '2024-11-16 12:33:35.309136', + 'Apache Tomcat is an open source implementation of the Java Servlet and JavaServer Pages technologies', + 'store', + 'arm,arm64,ppc64le,riscv64,s390x,386,amd64', + 'Web Servers', + false, false, true, + '2024-11-17 00:00:52.66311', + 'linux', + '500M+', 3703), + +((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'Redis'), + 'DOCKER', 'redis', 'latest', 'https://hub.docker.com/_/redis', + NULL, 'library', '2014-06-05 20:04:50', '2024-11-13 05:06:01.750358', + 'Redis is the world''s fastest data platform for caching, vector search, and NoSQL databases.', + 'store', + 's390x,arm64,mips64le,arm,ppc64le,riscv64,386,amd64', + 'Databases & Storage', + false, false, true, + '2024-11-16 23:59:52.43899', + 'unknown,linux,windows', + '1B+', 13089), + +((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'Nginx'), + 'DOCKER', 'nginx', 'latest', 'https://hub.docker.com/_/nginx', + NULL, 'library', '2014-06-05 19:14:45', '2024-11-13 18:54:10.381375', + 'Official build of Nginx.', + 'store', + 'mips64le,ppc64le,s390x,386,amd64,arm,arm64', + 'Web Servers', + false, false, true, + '2024-11-16 23:59:52.411318', + 'linux', + '1B+', 20371), + +((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'Apache HTTP Server'), + 'DOCKER', 'httpd', 'latest', 'https://hub.docker.com/_/httpd', + NULL, 'library', '2014-11-03 20:13:35.098911', '2024-11-12 06:53:14.008833', + 'The Apache HTTP Server Project', + 'store', + '386,s390x,arm64,mips64le,ppc64le,riscv64,amd64,arm', + 'Web Servers', + false, false, true, + '2024-11-16 23:59:52.416276', + 'linux', + '1B+', 4811), + +((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'Nexus Repository'), + 'DOCKER', 'sonatype/nexus', 'latest', 'https://hub.docker.com/r/sonatype/nexus', + NULL, 'sonatype', '2014-11-30 00:48:42.277735', '2024-11-13 23:30:59.187382', + 'Sonatype Nexus', + 'community', + 'amd64', + NULL, + false, true, false, + '2024-11-17 00:00:53.742239', + 'linux', + '10M+', 454), + +((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'MariaDB'), + 'DOCKER', 'mariadb', 'latest', 'https://hub.docker.com/_/mariadb', + NULL, 'library', '2014-11-25 23:08:03.441528', '2024-11-16 07:36:49.596577', + 'MariaDB Server is a high performing open source relational database, forked from MySQL.', + 'store', + 'ppc64le,s390x,386,amd64,arm64', + 'Databases & Storage', + false, false, true, + '2024-11-16 23:59:52.448539', + 'unknown,linux', + '1B+', 5880), + +((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'Grafana'), + 'DOCKER', 'grafana/grafana', 'latest', 'https://hub.docker.com/r/grafana/grafana', + NULL, 'Grafana Labs', '2015-02-06 09:29:43.405876', '2024-11-16 14:04:58.225375', + 'The official Grafana docker container', + 'verified_publisher', + 'amd64,arm,arm64', + 'Internet of Things,Monitoring & Observability,Security', + false, false, false, + '2024-11-17 00:00:54.128838', + 'linux', + '1B+', 3210), + +((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'Prometheus'), + 'DOCKER', 'bitnami/prometheus', 'latest', 'https://hub.docker.com/r/bitnami/prometheus', + NULL, 'VMware', '2018-04-04 14:36:04.576861', '2024-11-09 23:50:22.097247', + 'Bitnami container image for Prometheus', + 'verified_publisher', + 'amd64,arm64', + 'Integration & Delivery,Monitoring & Observability,Security', + false, true, false, + '2024-11-17 00:14:24.131874', + 'linux', + '50M+', 235); + +-- HelmChart 데이터 (ArtifactHub 기반) +INSERT INTO HELM_CHART (CATALOG_ID, CHART_NAME, CHART_VERSION, CHART_REPOSITORY_URL, VALUES_FILE, HAS_VALUES_SCHEMA, REPOSITORY_NAME, REPOSITORY_OFFICIAL, REPOSITORY_DISPLAY_NAME) VALUES +((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'Grafana'), 'grafana', '6.17.0', 'https://grafana.github.io/helm-charts', 'https://artifacthub.io/packages/helm/grafana/grafana/values.yaml', true, 'grafana', true, 'Grafana'); + +-- SOFTWARE_CATALOG_REF 데이터 +-- SOFTWARE_CATALOG_REF 데이터 삽입 INSERT INTO SOFTWARE_CATALOG_REF(CATALOG_ID, REF_IDX, REF_VALUE, REF_DESC, REF_TYPE) -VALUES - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'APACHE TOMCAT'), 0, 'https://tomcat.apache.org/', '', 'HOMEPAGE'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'APACHE TOMCAT'), 0, 'apache', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'APACHE TOMCAT'), 0, 'oss', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'APACHE TOMCAT'), 0, 'server', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'APACHE TOMCAT'), 0, 'vm_application_install', '', 'workflow'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'APACHE TOMCAT'), 0, 'vm_application_uninstall', '', 'workflow'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'APACHE TOMCAT'), 0, 'helm_application_install', '', 'workflow'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'APACHE TOMCAT'), 0, 'helm_application_uninstall', '', 'workflow'); -INSERT INTO SOFTWARE_CATALOG_REF(CATALOG_ID, REF_IDX, REF_VALUE, REF_DESC, REF_TYPE) -VALUES - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'REDIS'), 0, 'https://redis.io/', '', 'HOMEPAGE'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'REDIS'), 0, 'NoSQL', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'REDIS'), 0, 'oss', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'REDIS'), 0, 'inMemoryDB', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'REDIS'), 0, 'vm_application_install', '', 'workflow'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'REDIS'), 0, 'vm_application_uninstall', '', 'workflow'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'REDIS'), 0, 'helm_application_install', '', 'workflow'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'REDIS'), 0, 'helm_application_uninstall', '', 'workflow'); +SELECT SC.ID, 0, 'https://tomcat.apache.org/', '', 'HOMEPAGE' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Apache Tomcat' +UNION ALL +SELECT SC.ID, 1, 'apache', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Apache Tomcat' +UNION ALL +SELECT SC.ID, 2, 'oss', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Apache Tomcat' +UNION ALL +SELECT SC.ID, 3, 'server', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Apache Tomcat' +UNION ALL +SELECT SC.ID, 4, 'vm_application_install', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Apache Tomcat' +UNION ALL +SELECT SC.ID, 5, 'vm_application_uninstall', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Apache Tomcat' +UNION ALL +SELECT SC.ID, 6, 'helm_application_install', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Apache Tomcat' +UNION ALL +SELECT SC.ID, 7, 'helm_application_uninstall', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Apache Tomcat'; + INSERT INTO SOFTWARE_CATALOG_REF(CATALOG_ID, REF_IDX, REF_VALUE, REF_DESC, REF_TYPE) -VALUES - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'NGINX'), 0, 'https://nginx.org/en/', '', 'HOMEPAGE'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'NGINX'), 0, 'apache', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'NGINX'), 0, 'oss', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'NGINX'), 0, 'proxy', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'NGINX'), 0, 'web', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'NGINX'), 0, 'frontend', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'NGINX'), 0, 'server', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'NGINX'), 0, 'vm_application_install', '', 'workflow'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'NGINX'), 0, 'vm_application_uninstall', '', 'workflow'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'NGINX'), 0, 'helm_application_install', '', 'workflow'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'NGINX'), 0, 'helm_application_uninstall', '', 'workflow'); +SELECT SC.ID, 0, 'https://redis.io/', '', 'HOMEPAGE' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Redis' +UNION ALL +SELECT SC.ID, 1, 'NoSQL', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Redis' +UNION ALL +SELECT SC.ID, 2, 'oss', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Redis' +UNION ALL +SELECT SC.ID, 3, 'inMemoryDB', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Redis' +UNION ALL +SELECT SC.ID, 4, 'vm_application_install', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Redis' +UNION ALL +SELECT SC.ID, 5, 'vm_application_uninstall', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Redis' +UNION ALL +SELECT SC.ID, 6, 'helm_application_install', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Redis' +UNION ALL +SELECT SC.ID, 7, 'helm_application_uninstall', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Redis'; + INSERT INTO SOFTWARE_CATALOG_REF(CATALOG_ID, REF_IDX, REF_VALUE, REF_DESC, REF_TYPE) -VALUES - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'APACHE'), 0, 'https://httpd.apache.org/', '', 'HOMEPAGE'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'APACHE'), 0, 'web', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'APACHE'), 0, 'oss', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'APACHE'), 0, 'frontend', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'APACHE'), 0, 'webserver', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'APACHE'), 0, 'httpd', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'APACHE'), 0, 'vm_application_install', '', 'workflow'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'APACHE'), 0, 'vm_application_uninstall', '', 'workflow'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'APACHE'), 0, 'helm_application_install', '', 'workflow'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'APACHE'), 0, 'helm_application_uninstall', '', 'workflow'); +SELECT SC.ID, 0, 'https://nginx.org/en/', '', 'HOMEPAGE' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Nginx' +UNION ALL +SELECT SC.ID, 1, 'apache', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Nginx' +UNION ALL +SELECT SC.ID, 2, 'oss', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Nginx' +UNION ALL +SELECT SC.ID, 3, 'proxy', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Nginx' +UNION ALL +SELECT SC.ID, 4, 'web', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Nginx' +UNION ALL +SELECT SC.ID, 5, 'frontend', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Nginx' +UNION ALL +SELECT SC.ID, 6, 'server', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Nginx' +UNION ALL +SELECT SC.ID, 7, 'vm_application_install', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Nginx' +UNION ALL +SELECT SC.ID, 8, 'vm_application_uninstall', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Nginx' +UNION ALL +SELECT SC.ID, 9, 'helm_application_install', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Nginx' +UNION ALL +SELECT SC.ID, 10, 'helm_application_uninstall', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Nginx'; + INSERT INTO SOFTWARE_CATALOG_REF(CATALOG_ID, REF_IDX, REF_VALUE, REF_DESC, REF_TYPE) -VALUES - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'NEXUS'), 0, 'https://www.sonatype.com/products/sonatype-nexus-repository', '', 'HOMEPAGE'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'NEXUS'), 0, 'repository', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'NEXUS'), 0, 'oss', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'NEXUS'), 0, 'license', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'NEXUS'), 0, 'vm_application_install', '', 'workflow'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'NEXUS'), 0, 'vm_application_uninstall', '', 'workflow'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'NEXUS'), 0, 'helm_application_install', '', 'workflow'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'NEXUS'), 0, 'helm_application_uninstall', '', 'workflow'); +SELECT SC.ID, 0, 'https://httpd.apache.org/', '', 'HOMEPAGE' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Apache HTTP Server' +UNION ALL +SELECT SC.ID, 1, 'web', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Apache HTTP Server' +UNION ALL +SELECT SC.ID, 2, 'oss', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Apache HTTP Server' +UNION ALL +SELECT SC.ID, 3, 'frontend', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Apache HTTP Server' +UNION ALL +SELECT SC.ID, 4, 'webserver', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Apache HTTP Server' +UNION ALL +SELECT SC.ID, 5, 'httpd', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Apache HTTP Server' +UNION ALL +SELECT SC.ID, 6, 'vm_application_install', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Apache HTTP Server' +UNION ALL +SELECT SC.ID, 7, 'vm_application_uninstall', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Apache HTTP Server' +UNION ALL +SELECT SC.ID, 8, 'helm_application_install', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Apache HTTP Server' +UNION ALL +SELECT SC.ID, 9, 'helm_application_uninstall', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Apache HTTP Server'; + INSERT INTO SOFTWARE_CATALOG_REF(CATALOG_ID, REF_IDX, REF_VALUE, REF_DESC, REF_TYPE) -VALUES - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'MARIA DB'), 0, 'https://mariadb.org/', '', 'HOMEPAGE'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'MARIA DB'), 0, 'RDBMS', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'MARIA DB'), 0, 'oss', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'MARIA DB'), 0, 'database', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'MARIA DB'), 0, 'vm_application_install', '', 'workflow'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'MARIA DB'), 0, 'vm_application_uninstall', '', 'workflow'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'MARIA DB'), 0, 'helm_application_install', '', 'workflow'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'MARIA DB'), 0, 'helm_application_uninstall', '', 'workflow'); +SELECT SC.ID, 0, 'https://www.sonatype.com/products/sonatype-nexus-repository', '', 'HOMEPAGE' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Nexus Repository' +UNION ALL +SELECT SC.ID, 1, 'repository', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Nexus Repository' +UNION ALL +SELECT SC.ID, 2, 'oss', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Nexus Repository' +UNION ALL +SELECT SC.ID, 3, 'license', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Nexus Repository' +UNION ALL +SELECT SC.ID, 4, 'vm_application_install', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Nexus Repository' +UNION ALL +SELECT SC.ID, 5, 'vm_application_uninstall', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Nexus Repository' +UNION ALL +SELECT SC.ID, 6, 'helm_application_install', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Nexus Repository' +UNION ALL +SELECT SC.ID, 7, 'helm_application_uninstall', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Nexus Repository'; + INSERT INTO SOFTWARE_CATALOG_REF(CATALOG_ID, REF_IDX, REF_VALUE, REF_DESC, REF_TYPE) -VALUES - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'GRAFANA'), 0, 'https://grafana.com/', '', 'HOMEPAGE'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'GRAFANA'), 0, 'view', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'GRAFANA'), 0, 'observer', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'GRAFANA'), 0, 'oss', '', 'TAG'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'GRAFANA'), 0, 'vm_application_install', '', 'workflow'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'GRAFANA'), 0, 'vm_application_uninstall', '', 'workflow'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'GRAFANA'), 0, 'helm_application_install', '', 'workflow'), - ((SELECT ID FROM SOFTWARE_CATALOG WHERE TITLE = 'GRAFANA'), 0, 'helm_application_uninstall', '', 'workflow'); +SELECT SC.ID, 0, 'https://mariadb.org/', '', 'HOMEPAGE' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'MariaDB' +UNION ALL +SELECT SC.ID, 1, 'RDBMS', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'MariaDB' +UNION ALL +SELECT SC.ID, 2, 'oss', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'MariaDB' +UNION ALL +SELECT SC.ID, 3, 'database', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'MariaDB' +UNION ALL +SELECT SC.ID, 4, 'vm_application_install', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'MariaDB' +UNION ALL +SELECT SC.ID, 5, 'vm_application_uninstall', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'MariaDB' +UNION ALL +SELECT SC.ID, 6, 'helm_application_install', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'MariaDB' +UNION ALL +SELECT SC.ID, 7, 'helm_application_uninstall', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'MariaDB'; +INSERT INTO SOFTWARE_CATALOG_REF(CATALOG_ID, REF_IDX, REF_VALUE, REF_DESC, REF_TYPE) +SELECT SC.ID, 0, 'https://grafana.com/', '', 'HOMEPAGE' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Grafana' +UNION ALL +SELECT SC.ID, 1, 'view', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Grafana' +UNION ALL +SELECT SC.ID, 2, 'observer', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Grafana' +UNION ALL +SELECT SC.ID, 3, 'oss', '', 'TAG' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Grafana' +UNION ALL +SELECT SC.ID, 4, 'vm_application_install', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Grafana' +UNION ALL +SELECT SC.ID, 5, 'vm_application_uninstall', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Grafana' +UNION ALL +SELECT SC.ID, 6, 'helm_application_install', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Grafana' +UNION ALL +SELECT SC.ID, 7, 'helm_application_uninstall', '', 'workflow' +FROM SOFTWARE_CATALOG SC WHERE SC.TITLE = 'Grafana'; -- Insert into oss_type diff --git a/src/main/resources/jenkins/kubernetes_helm_install_pipeline.xml b/src/main/resources/jenkins/kubernetes_helm_install_pipeline.xml index 2bf4e5c..e383508 100644 --- a/src/main/resources/jenkins/kubernetes_helm_install_pipeline.xml +++ b/src/main/resources/jenkins/kubernetes_helm_install_pipeline.xml @@ -7,7 +7,7 @@ - TUMBLEBUG_URI + CB_TUMBLEBUG_URI Tumblebug API URL http://52.78.129.10:1323/tumblebug true diff --git a/src/main/resources/jenkins/kubernetes_helm_uninstall_pipeline.xml b/src/main/resources/jenkins/kubernetes_helm_uninstall_pipeline.xml index 8898bcb..aac107b 100644 --- a/src/main/resources/jenkins/kubernetes_helm_uninstall_pipeline.xml +++ b/src/main/resources/jenkins/kubernetes_helm_uninstall_pipeline.xml @@ -7,7 +7,7 @@ - TUMBLEBUG_URI + CB_TUMBLEBUG_URI Tumblebug API URL http://52.78.129.10:1323/tumblebug true