diff --git a/Dockerfile b/Dockerfile index ffe2f6a..48c8bec 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,3 @@ -FROM openjdk:17-slim +FROM openjdk:17-slim AS prod COPY ./build/libs/am.jar am.jar ENTRYPOINT ["java", "-jar","am.jar"] diff --git a/README.md b/README.md index 747e1a1..c3718a6 100755 --- a/README.md +++ b/README.md @@ -12,18 +12,15 @@ v0.2.0(2024.08) - 애플리케이션 카탈로그 등록 및 내/외부(artifactHub, dockerHub등) 환경에서의 키워드검색 - workflow-manager를 연동한 멀티 클라우드 인프라에 애플리케이션 배포 기능(to VM) - workflow-manager를 연동한 배포 외 기타 기능 - - v.0.3.0(2024.10) - workflow-manager를 연동한 멀티 클라우드 인프라에 애플리케이션 배포 기능(to k8s) - k8s에 배포 시 필요한 일부 yaml generate 기능(deployment, service, pod, configmap 등) - repository 관련 제어(nexus 등) -- 기타 ## 목차 -1. [mc-application-manager 실행 및 개발 환경] +1. [mc-application-manager 실행 및 개발 환경] 2. [mc-application-manager실행 방법] 3. [mc-application-manager 소스 빌드 및 실행 방법 상세] 4. [mc-application-manager 기여 방법] diff --git a/build.gradle b/build.gradle index c1dc4f6..423c36f 100755 --- a/build.gradle +++ b/build.gradle @@ -33,6 +33,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.session:spring-session-core' implementation 'com.squareup.okhttp3:okhttp:4.10.0' + implementation 'org.springframework.boot:spring-boot-starter-validation' // https://mvnrepository.com/artifact/com.h2database/h2 // 시작 시 drop TABLE관련 버그로 1.4.200 -> 1.4.199 @@ -90,6 +91,15 @@ dependencies { testImplementation(platform("org.junit:junit-bom:5.9.1")) testImplementation("org.junit.jupiter:junit-jupiter") + + implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.12.0' + implementation 'org.apache.commons:commons-compress' + implementation 'io.kubernetes:client-java' + implementation 'io.kubernetes:client-java-api' + implementation 'io.kubernetes:client-java-api' + implementation 'io.kubernetes:client-java-extended' + + } tasks.test { diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..2d9308e --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,85 @@ +# temp docker-compose +networks: + internal_network: + internal: true + external_network: + driver: bridge + + # jenkins - for workflow manager + jenkins: + image: jenkins/jenkins:jdk17 + container_name: jenkins + platform: linux/amd64 + networks: + - internal_network + - external_network + ports: + - target: 8080 + published: 9800 + protocol: tcp + volumes: + - ~/:/var/jenkins_home # -v $HOME/mcmp/oss/jenkins:/var/jenkins_home + - /var/run/docker.sock:/var/run/docker.sock + - /usr/bin/docker:/usr/bin/docker # -v $(which docker):/usr/bin/docker + environment: + - PROJECT=mcmp + healthcheck: # for application-manager + test: [ "CMD", "curl", "-f", "http://localhost:1024/catalog/software" ] + interval: 1m + timeout: 5s + retries: 3 + start_period: 10s + + # sonatype nexus - for application manager + sonatype-nexus: + image: sonatype/nexus3:latest + container_name: nexus-repository + platform: linux/amd64 + networks: + - internal_network + - external_network + ports: + - target: 8081 + published: 8081 + protocol: tcp + - target: 5000 # container-repository + published: 5000 + protocol: tcp + volumes: + - ~/:/nexus-data/blobs/ + environment: + - PROJECT=mcmp + healthcheck: # for application-manager + test: [ "CMD", "curl", "-f", "http://localhost:1024/catalog/software" ] + interval: 1m + timeout: 5s + retries: 3 + start_period: 10s + + # application-manager + mc-application-manager: + image: pbccc/devops:0.2.5 + container_name: cb-mapui + build: + context: ./ + dockerfile: Dockerfile + networks: + - external_network + - external_network + ports: + - target: 18084 + published: 18084 + protocol: tcp + volumes: + - ~/:/nexus-data/blobs/ + environment: + - DDL_AUTO=create-drop + - DB_USER=application + - DB_PASS=application!23 + - SQL_DATA_INIT=always + healthcheck: # for cb-application-manager + test: ["CMD", "nc", "-vz", "localhost", "1324"] + interval: 1m + timeout: 5s + retries: 3 + start_period: 10s diff --git a/docker-run.sh b/docker-run.sh index e42aed5..37edc14 100644 --- a/docker-run.sh +++ b/docker-run.sh @@ -1,7 +1,5 @@ #!/bin/sh -#test - nowdate=$(date '+%Y%m%d%H%M%S') echo $nowdate @@ -46,3 +44,5 @@ docker run -d -p 18084:18084 \ echo "docker build image delete" docker rmi -f $APP_NAME + + diff --git a/docs/func_tree.xlsx b/docs/func_tree.xlsx new file mode 100644 index 0000000..2b0ff14 Binary files /dev/null and b/docs/func_tree.xlsx differ diff --git a/src/main/java/kr/co/mcmp/ApplicationManagerApplication.java b/src/main/java/kr/co/mcmp/ApplicationManagerApplication.java index dcb7e89..40d92c3 100644 --- a/src/main/java/kr/co/mcmp/ApplicationManagerApplication.java +++ b/src/main/java/kr/co/mcmp/ApplicationManagerApplication.java @@ -2,6 +2,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.openfeign.EnableFeignClients; import springfox.documentation.swagger2.annotations.EnableSwagger2; import java.io.UnsupportedEncodingException; @@ -9,6 +10,7 @@ @EnableSwagger2 @SpringBootApplication +@EnableFeignClients public class ApplicationManagerApplication { public static void main(String[] args) throws GeneralSecurityException, UnsupportedEncodingException { diff --git a/src/main/java/kr/co/mcmp/api/oss/component/CommonComponentController.java b/src/main/java/kr/co/mcmp/api/oss/component/CommonComponentController.java new file mode 100644 index 0000000..c2ec997 --- /dev/null +++ b/src/main/java/kr/co/mcmp/api/oss/component/CommonComponentController.java @@ -0,0 +1,62 @@ +package kr.co.mcmp.api.oss.component; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import kr.co.mcmp.dto.oss.component.CommonComponent; +import kr.co.mcmp.response.ResponseWrapper; +import kr.co.mcmp.service.oss.component.CommonModuleComponentService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +@Tag(name = "CommonComponentController - 컴포넌트 API 관련") +@RequestMapping("/oss/v1/components") +@RestController +@RequiredArgsConstructor +public class CommonComponentController { + + private final CommonModuleComponentService moduleComponentService; + + @Operation(summary = "컴포넌트 목록 조회") + @GetMapping("/{module}/list/{name}") + public ResponseEntity>> getComponentList( + @Parameter(description = "모듈 타입", required = true, example = "nexus") @PathVariable("module") String module, + @Parameter(description = "레포지토리 이름", required = true) @PathVariable("name") String name) { + List componentList = moduleComponentService.getComponentList(module, name); + return ResponseEntity.ok(new ResponseWrapper<>(componentList)); + } + + @Operation(summary = "컴포넌트 상세 조회") + @GetMapping("/{module}/detail/{id}") + public ResponseEntity> getComponentDetailByName( + @Parameter(description = "모듈 타입", required = true, example = "nexus") @PathVariable("module") String module, + @Parameter(description = "컴포넌트 식별자", required = true) @PathVariable("id") String id) { + CommonComponent.ComponentDto componentDetailByName = moduleComponentService.getComponentDetailByName(module, id); + return ResponseEntity.ok(new ResponseWrapper<>(componentDetailByName)); + } + + @Operation(summary = "컴포넌트 삭제") + @DeleteMapping("/{module}/delete/{id}") + public ResponseEntity> deleteComponent( + @Parameter(description = "모듈 타입", required = true, example = "nexus") @PathVariable("module") String module, + @Parameter(description = "컴포넌트 식별자", required = true) @PathVariable("id") String id) { + moduleComponentService.deleteComponent(module, id); + return ResponseEntity.ok(new ResponseWrapper<>("Component delete completed")); + } + + @Operation(summary = "컴포넌트 등록") + @PostMapping("/{module}/create/{name}") + public ResponseEntity> createComponent( + @Parameter(description = "모듈 타입", required = true, example = "nexus") @PathVariable("module") String module, + @Parameter(description = "레포지토리 이름", required = true) @PathVariable("name") String name, + @RequestPart(value = "directory", required = false) String directory, + @RequestPart(value = "asset", required = false) List files + ) { + moduleComponentService.createComponent(module, name, directory, files); + return ResponseEntity.ok(new ResponseWrapper<>("Component create completed")); + } +} diff --git a/src/main/java/kr/co/mcmp/api/oss/repository/CommonRepositoryController.java b/src/main/java/kr/co/mcmp/api/oss/repository/CommonRepositoryController.java new file mode 100644 index 0000000..1026aa1 --- /dev/null +++ b/src/main/java/kr/co/mcmp/api/oss/repository/CommonRepositoryController.java @@ -0,0 +1,67 @@ +package kr.co.mcmp.api.oss.repository; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import kr.co.mcmp.dto.oss.repository.CommonRepository; +import kr.co.mcmp.response.ResponseWrapper; +import kr.co.mcmp.service.oss.repository.CommonModuleRepositoryService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + +@Tag(name = "CommonRepositoryController - 레포지토리 API 관련") +@RequestMapping("/oss/v1/repositories") +@RestController +@RequiredArgsConstructor +public class CommonRepositoryController { + + private final CommonModuleRepositoryService moduleRepositoryService; + + @Operation(summary = "레포지토리 목록 조회") + @GetMapping("/{module}/list") + public ResponseEntity>> getRepositoryList( + @Parameter(description = "모듈 타입", required = true, example = "nexus") @PathVariable("module") String module) { + List repositoryList = moduleRepositoryService.getRepositoryList(module); + return ResponseEntity.ok(new ResponseWrapper<>(repositoryList)); + } + + @Operation(summary = "레포지토리 상세 조회") + @GetMapping("/{module}/detail/{name}") + public ResponseEntity> getRepositoryDetailByName( + @Parameter(description = "모듈 타입", required = true, example = "nexus") @PathVariable("module") String module, + @Parameter(description = "레포지토리 이름", required = true) @PathVariable("name") String name) { + CommonRepository.RepositoryDto repositoryDetailByName = moduleRepositoryService.getRepositoryDetailByName(module, name); + return ResponseEntity.ok(new ResponseWrapper<>(repositoryDetailByName)); + } + + @Operation(summary = "레포지토리 등록") + @PostMapping("/{module}/create") + public ResponseEntity> createRepository( + @Parameter(description = "모듈 타입", required = true, example = "nexus") @PathVariable("module") String module, + @RequestBody @Valid CommonRepository.RepositoryDto repositoryDto) { + moduleRepositoryService.createRepository(module, repositoryDto); + return ResponseEntity.ok(new ResponseWrapper<>("Repository create completed")); + } + + @Operation(summary = "레포지토리 수정") + @PutMapping("/{module}/update") + public ResponseEntity> updateRepository( + @Parameter(description = "모듈 타입", required = true, example = "nexus") @PathVariable("module") String module, + @RequestBody @Valid CommonRepository.RepositoryDto repositoryDto) { + moduleRepositoryService.updateRepository(module, repositoryDto); + return ResponseEntity.ok(new ResponseWrapper<>("Repository update completed")); + } + + @Operation(summary = "레포지토리 삭제") + @DeleteMapping("/{module}/delete/{name}") + public ResponseEntity> deleteRepository( + @Parameter(description = "모듈 타입", required = true, example = "nexus") @PathVariable("module") String module, + @Parameter(description = "레포지토리 이름", required = true) @PathVariable("name") String name) { + moduleRepositoryService.deleteRepository(module, name); + return ResponseEntity.ok(new ResponseWrapper<>("Repository delete completed")); + } +} diff --git a/src/main/java/kr/co/mcmp/api/response/ResponseCode.java b/src/main/java/kr/co/mcmp/api/response/ResponseCode.java index 1e62d67..2c7037a 100644 --- a/src/main/java/kr/co/mcmp/api/response/ResponseCode.java +++ b/src/main/java/kr/co/mcmp/api/response/ResponseCode.java @@ -67,8 +67,6 @@ public enum ResponseCode { Stream.of(values()).collect(Collectors.toMap(ResponseCode::getCode, e -> e)); public static ResponseCode findByCode(int code) { - //test - //return Optional.ofNullable(map.get(code)).orElseThrow(() -> new McmpException(ResponseCode.UNKNOWN_ERROR)); - return null; + return Optional.ofNullable(map.get(code)).orElseThrow(() -> new McmpException(String.valueOf(ResponseCode.UNKNOWN_ERROR))); } } diff --git a/src/main/java/kr/co/mcmp/catalog/CatalogController.java b/src/main/java/kr/co/mcmp/catalog/CatalogController.java index 23caa35..7daf8ee 100644 --- a/src/main/java/kr/co/mcmp/catalog/CatalogController.java +++ b/src/main/java/kr/co/mcmp/catalog/CatalogController.java @@ -20,26 +20,25 @@ 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 List getCatalogList(@RequestParam String title){ -// return catalogService.getCatalogList(title); +// public List getCatalogList(){ +// return catalogService.getCatalogList(); // } -// @Operation(summary = "search software catalog") -// @ApiOperation(value="software catalog list(keyword search)", notes="software catalog 검색") -// @GetMapping("/list/{keyword}") -// public List getCatalogList(@PathVariable(required = false) String keyword){ -// return catalogService.getCatalogListSearch(keyword); -// } + @ApiOperation(value="software catalog list(all)", notes="software catalog 리스트 불러오기") + @Operation(summary = "get software catalog list") + @GetMapping("/") + public List getCatalogList(@RequestParam String title){ + if(title != null && title.trim().equals("")){ + System.out.println("==================================non title search"); + return catalogService.getCatalogList(); + }else { + System.out.println("==================================" + title); + return catalogService.getCatalogListSearch(title); + } + } @Operation(summary = "software catalogd detail(and reference)") @ApiOperation(value="software catalog detail", notes="software catalog 내용 확인(연결된 정보들까지)") diff --git a/src/main/java/kr/co/mcmp/catalog/CatalogRefDTO.java b/src/main/java/kr/co/mcmp/catalog/CatalogRefDTO.java index 8aa23d6..a5d5628 100644 --- a/src/main/java/kr/co/mcmp/catalog/CatalogRefDTO.java +++ b/src/main/java/kr/co/mcmp/catalog/CatalogRefDTO.java @@ -9,7 +9,7 @@ public class CatalogRefDTO { private Integer catalogRefIdx; private Integer catalogIdx; - private Integer refernectIdx; + private Integer referncetIdx; private String referenceValue; // ref url, ref value, etc... private String referenceDescription; private String referenceType; // homepage, manifest, workflow, image, etc... @@ -17,7 +17,7 @@ public class CatalogRefDTO { public CatalogRefDTO(CatalogRefEntity crEntity){ this.catalogRefIdx = crEntity.getId(); this.catalogIdx = crEntity.getCatalogId(); - this.refernectIdx = crEntity.getRefIdx(); + this.referncetIdx = crEntity.getRefIdx(); this.referenceValue = crEntity.getRefValue(); this.referenceDescription = crEntity.getRefDesc(); this.referenceType = crEntity.getRefType(); diff --git a/src/main/java/kr/co/mcmp/catalog/CatalogRefEntity.java b/src/main/java/kr/co/mcmp/catalog/CatalogRefEntity.java index 71c3ef7..82bac3e 100644 --- a/src/main/java/kr/co/mcmp/catalog/CatalogRefEntity.java +++ b/src/main/java/kr/co/mcmp/catalog/CatalogRefEntity.java @@ -39,7 +39,7 @@ public class CatalogRefEntity { public CatalogRefEntity(CatalogRefDTO crDto){ this.catalogId = crDto.getCatalogIdx(); - this.refIdx = crDto.getRefernectIdx(); + this.refIdx = crDto.getReferncetIdx(); this.refValue = crDto.getReferenceValue(); this.refDesc = crDto.getReferenceDescription(); this.refType = crDto.getReferenceType(); diff --git a/src/main/java/kr/co/mcmp/catalog/CatalogRepository.java b/src/main/java/kr/co/mcmp/catalog/CatalogRepository.java index 1caa598..ade113f 100644 --- a/src/main/java/kr/co/mcmp/catalog/CatalogRepository.java +++ b/src/main/java/kr/co/mcmp/catalog/CatalogRepository.java @@ -3,11 +3,13 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface CatalogRepository extends JpaRepository { void deleteById(Integer catalogIdx); - //List findbyTitle(String title); + List findByTitleLikeIgnoreCase(String title); } diff --git a/src/main/java/kr/co/mcmp/catalog/CatalogService.java b/src/main/java/kr/co/mcmp/catalog/CatalogService.java index 46c3b2d..ee8c3b5 100644 --- a/src/main/java/kr/co/mcmp/catalog/CatalogService.java +++ b/src/main/java/kr/co/mcmp/catalog/CatalogService.java @@ -29,13 +29,13 @@ public List getCatalogList(){ } public List getCatalogListSearch(String keyword){ -// List lcEntity = catalogRepository.findbyTitle(keyword); -// List lcDto = new ArrayList<>(); -// for(CatalogEntity ce:lcEntity){ -// lcDto.add(new CatalogDTO(ce)); -// } -// return lcDto; - return null; + List lcEntity = catalogRepository.findByTitleLikeIgnoreCase("%" + keyword + "%"); + System.out.println("=========================" + lcEntity.size()); + List lcDto = new ArrayList<>(); + for(CatalogEntity ce:lcEntity){ + lcDto.add(new CatalogDTO(ce)); + } + return lcDto; } public CatalogDTO getCatalogDetail(Integer catalogIdx){ diff --git a/src/main/java/kr/co/mcmp/dto/oss/component/CommonComponent.java b/src/main/java/kr/co/mcmp/dto/oss/component/CommonComponent.java new file mode 100644 index 0000000..7cd01e2 --- /dev/null +++ b/src/main/java/kr/co/mcmp/dto/oss/component/CommonComponent.java @@ -0,0 +1,70 @@ +package kr.co.mcmp.dto.oss.component; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import java.util.List; + +@Getter +public class CommonComponent { + + @Getter + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class ComponentDto { + + @Schema(title = "컴포넌트 식별자", required = true, example = "dGTzdKenZQCzMlY8Ne") + @NotBlank + private String id; + + @Schema(title = "컴포넌트가 속한 저장소", required = true, example = "repo") + @NotBlank + private String repository; + + @Schema(title = "컴포넌트 포맷 유형", required = true, example = "raw, helm, docker") + @NotBlank + private String format; + + @Schema(title = "컴포넌트가 속한 그룹", required = true, example = "hosted") + @NotBlank + private String group; + + @Schema(title = "컴포넌트 이름", required = true, example = "comp") + @NotBlank + private String name; + + @Valid + private List assets; + + @Getter + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class AssetsDto { + + @Schema(title = "다운로드 URL", required = true, example = "http://127.0.0.1:8080/repository/repo/comp.zip") + @NotBlank + private String downloadUrl; + + @Schema(title = "자원 식별자", required = true, example = "dGTzdKenZQCzMlY8Ne") + @NotBlank + private String id; + + @Schema(title = "컨텐츠 타입", required = true, example = "application/zip") + @NotBlank + private String contentType; + + @Schema(title = "파일 크기", required = true, example = "1000") + private Integer fileSize; + + @Schema(title = "업로드 날짜", required = true, example = "2024-01-01T00:00:00.188+00:00") + private String blobCreated; + } + } +} diff --git a/src/main/java/kr/co/mcmp/dto/oss/component/CommonUploadComponent.java b/src/main/java/kr/co/mcmp/dto/oss/component/CommonUploadComponent.java new file mode 100644 index 0000000..f1a56fa --- /dev/null +++ b/src/main/java/kr/co/mcmp/dto/oss/component/CommonUploadComponent.java @@ -0,0 +1,40 @@ +package kr.co.mcmp.dto.oss.component; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.web.multipart.MultipartFile; + +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import java.util.List; + +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class CommonUploadComponent { + + @Schema(title = "디렉토리 이름", required = true, example = "test") + @NotBlank + private String directory; + + @Schema(title = "파일", required = true) + @Valid + private List asset; + + @Getter + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class FilesDto { + + @Schema(title = "파일") + private MultipartFile file; + + @Schema(title = "파일 이름", example = "test") + private String filename; + } +} diff --git a/src/main/java/kr/co/mcmp/dto/oss/repository/CommonFormatType.java b/src/main/java/kr/co/mcmp/dto/oss/repository/CommonFormatType.java new file mode 100644 index 0000000..bdda840 --- /dev/null +++ b/src/main/java/kr/co/mcmp/dto/oss/repository/CommonFormatType.java @@ -0,0 +1,20 @@ +package kr.co.mcmp.dto.oss.repository; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class CommonFormatType { + + @Schema(title = "포맷 유형", example = "raw, docker, helm") + private String format; + + @Schema(title = "타입 유형", example = "hosted") + private String type; +} 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 new file mode 100644 index 0000000..7c026e3 --- /dev/null +++ b/src/main/java/kr/co/mcmp/dto/oss/repository/CommonRepository.java @@ -0,0 +1,91 @@ +package kr.co.mcmp.dto.oss.repository; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@Getter +public class CommonRepository { + + @Getter + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class RepositoryDto { + + @Schema(title = "레포지토리 이름", required = true, example = "repo") + @NotBlank + private String name; + + @Schema(title = "레포지토리 포맷 유형", required = true, example = "raw, helm, docker") + @NotBlank + private String format; + + @Schema(title = "레포지토리 타입 유형", required = true, example = "hosted") + @NotBlank + private String type; + + @Schema(title = "레포지토리 접근 url", required = true, example = "등록: 빈값, 수정: 값") + @NotNull + private String url; + + @Schema(title = "레포지토리 사용자 접근 가능 여부", required = true) + @NotNull + private Boolean online; + + @Valid + private StorageDto storage; + + @Valid + private DockerDto docker; + + @Getter + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class StorageDto { + + @Schema(title = "아티팩트를 저장하는 물리적 저장소 이름", required = true, example = "default") + @NotBlank + private String blobStoreName; + + @Schema(title = "저장되는 아티팩트 유형 일치 여부 검증", required = true) + @NotNull + private Boolean strictContentTypeValidation; + + @Schema(title = "레포지토리 읽기/쓰기 설정", required = true, example = "allow, allow_once, deny") + @NotBlank + private String writePolicy; + } + + @Getter + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class DockerDto { + + @Schema(title = "도커 registry 버전 지원(false: v2 지원)", required = true) + @NotNull + private Boolean v1Enabled; + + @Schema(title = "도커 클라이언트가 레포지토리에 접근할 때 기본 인증 사용 여부", required = true) + @NotNull + private Boolean forceBasicAuth; + + @Schema(title = "도커 레포지토리에 접근할 때 사용할 http 포트", example = "8080") + private Integer httpPort; + + @Schema(title = "도커 레포지토리에 접근할 때 사용할 https 포트", example = "9090") + private Integer httpsPort; + + @Schema(title = "도커 레포지토리에 접근할 때 사용할 서브도메인", example = "/test") + private String subdomain; + } + } +} diff --git a/src/main/java/kr/co/mcmp/externalrepo/ArtifactHubInteface.java b/src/main/java/kr/co/mcmp/externalrepo/ArtifactHubInteface.java index 7642ad4..6b83610 100644 --- a/src/main/java/kr/co/mcmp/externalrepo/ArtifactHubInteface.java +++ b/src/main/java/kr/co/mcmp/externalrepo/ArtifactHubInteface.java @@ -1,16 +1,22 @@ package kr.co.mcmp.externalrepo; +import kr.co.mcmp.externalrepo.model.ArtifactHubPackage; +import kr.co.mcmp.externalrepo.model.ArtifactHubRespository; import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.List; @FeignClient(name = "artifactHubClient", url = "https://artifacthub.io") public interface ArtifactHubInteface { -// @GetMapping(value="/api/v1/repositories/search") -// //https://artifacthub.io/api/v1/repositories/search?offset=0&limit=5&kind=0&name=argo -// List searchRepository(@RequestParam("name") String helm); -// -// @GetMapping(value="/api/v1/packages/search") -// ArtifactHubPackage searchPackage(@RequestParam("ts_query_web") String helm, @RequestParam(required=false, value="kind", defaultValue="0") String kind); + @GetMapping(value="/api/v1/repositories/search") + //https://artifacthub.io/api/v1/repositories/search?offset=0&limit=5&kind=0&name=argo + List searchRepository(@RequestParam("name") String helm); + + @GetMapping(value="/api/v1/packages/search") + ArtifactHubPackage searchPackage(@RequestParam("ts_query_web") String helm, @RequestParam(required=false, value="kind", defaultValue="0") String kind); } diff --git a/src/main/java/kr/co/mcmp/externalrepo/ExternalRepoController.java b/src/main/java/kr/co/mcmp/externalrepo/ExternalRepoController.java index d64fdb8..79e27a3 100644 --- a/src/main/java/kr/co/mcmp/externalrepo/ExternalRepoController.java +++ b/src/main/java/kr/co/mcmp/externalrepo/ExternalRepoController.java @@ -27,24 +27,22 @@ public class ExternalRepoController { @Operation(summary = "dockerHub catalog 조회(image 조회)") @GetMapping("/dockerhub/{keyword}") public ResponseWrapper getDockerHubList(@PathVariable String keyword){ -// logger.info("testString: {}", keyword); -// if(keyword != null) { -// return new ResponseWrapper<>(outSvc.searchDockerHubCatalog(keyword)); -// }else{ -// return null; -// } - return null; + logger.info("testString: {}", keyword); + if(keyword != null) { + return new ResponseWrapper<>(outSvc.searchDockerHubCatalog(keyword)); + }else{ + return null; + } } @Operation(summary = "artifactHub package 목록 조회(helm 조회)") @GetMapping("/artifacthub/{keyword}") public ResponseWrapper getArtifactHubList(@PathVariable String keyword){ -// if(keyword != null) { -// return new ResponseWrapper<>(outSvc.searchArtifactHubPackage(keyword)); -// }else{ -// return null; -// } - return null; + if(keyword != null) { + return new ResponseWrapper<>(outSvc.searchArtifactHubPackage(keyword)); + }else{ + return null; + } } diff --git a/src/main/java/kr/co/mcmp/externalrepo/ExternalRepoService.java b/src/main/java/kr/co/mcmp/externalrepo/ExternalRepoService.java index 431bec9..71ea3b8 100644 --- a/src/main/java/kr/co/mcmp/externalrepo/ExternalRepoService.java +++ b/src/main/java/kr/co/mcmp/externalrepo/ExternalRepoService.java @@ -3,6 +3,7 @@ import kr.co.mcmp.externalrepo.model.ArtifactHubPackage; import kr.co.mcmp.externalrepo.model.ArtifactHubRespository; import kr.co.mcmp.externalrepo.model.DockerHubCatalog; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @@ -10,30 +11,28 @@ @Service public class ExternalRepoService { -// @Autowired -// private ArtifactHubInteface artfInt; + @Autowired + private ArtifactHubInteface artfInt; -// @Autowired -// private DockerHubInterface dockerInt; + @Autowired + private DockerHubInterface dockerInt; public List searchArtifactHubRepository(String keyword){ - //return artfInt.searchRepository(keyword); - return null; + return artfInt.searchRepository(keyword); + } public ArtifactHubPackage searchArtifactHubPackage(String keyword){ - //return artfInt.searchPackage(keyword, "0"); - return null; + return artfInt.searchPackage(keyword, "0"); } public DockerHubNamespace searchDockerHubNamespace(String keyword){ - //return dockerInt.searchNamespace(keyword); - return null; + return dockerInt.searchNamespace(keyword); } public DockerHubCatalog searchDockerHubCatalog(String keyword){ - //return dockerInt.searchCatalog(keyword); - return null; + return dockerInt.searchCatalog(keyword); + //return null; } diff --git a/src/main/java/kr/co/mcmp/manifest/K8S.java b/src/main/java/kr/co/mcmp/manifest/K8S.java new file mode 100644 index 0000000..3e3ceec --- /dev/null +++ b/src/main/java/kr/co/mcmp/manifest/K8S.java @@ -0,0 +1,134 @@ +package kr.co.mcmp.manifest; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.kubernetes.client.util.Yaml; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class K8S { + + private static Logger logger = LoggerFactory.getLogger(K8S.class); + + public static final String podAntiAffinityKey = "devops.type"; + + public static enum Controller { + Pod("apps/v1", "dep"), + Deployment("apps/v1", "dep"), + DaemonSet("apps/v1", "dep"), + StatefulSet("apps/v1", "dep"), + CronJob("batch/v1beta1", "dep"), + Rollout("argoproj.io/v1alpha1", "dep"); + + String apiVersion; + + String postfix; + + private Controller(String apiVersion, String postfix) { + this.apiVersion = apiVersion; + this.postfix = postfix; + } + + public String getApiVersion() { + return this.apiVersion; + } + + public String getPostfix() { + return this.postfix; + } + + + } + + public static enum StrategyType { + RollingUpdate, + Recreate + } + +// public static enum VolumeType { +// HostPath, PVC +// } + + public static enum Kind { + Service("v1", "svc"), + Ingress("networking.k8s.io/v1beta1", "ing"), + ConfigMap("v1", "cfm"), + Secret("v1", "sec"), + TlsSecret("v1", "httptls"), + HorizontalPodAutoscaler("autoscaling/v2beta2", "hpa"), + HTTPProxy("projectcontour.io/v1", "htp"), + PersistentVolumeClaim("v1", "pvc") + ; + + + + String apiVersion; + + String postfix; + + private Kind(String apiVersion, String postfix) { + this.apiVersion = apiVersion; + this.postfix = postfix; + } + + public String getApiVersion() { + return this.apiVersion; + } + + public String getPostfix() { + return this.postfix; + } + + } + + + + + + + public static enum VolumeType2 { + DirectoryOrCreate, + File + } + + public static Map getIngressRewriteAnnotaions() { + + Map map = new LinkedHashMap<> (); + map.put("nginx.ingress.kubernetes.io/rewrite-target", "/$2"); + + return map; + + } + + + public static void printJson(String title, Object object) { + + if (object == null) { + logger.info("[{}] null", title); + return; + } + + try { + ObjectMapper mapper = new ObjectMapper(); + JsonNode jsonNode = mapper.convertValue(object, JsonNode.class); + logger.info("[{}] {}", title, mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonNode)); + } catch (Exception e) { + logger.info("[{}] {}", title, e.getMessage()); + } + } + + + public static void printYaml(String title, Object object) { + + if (object == null) { + logger.info("[{}] null", title); + return; + } + + logger.info("[{}] {}", title, Yaml.dump(object)); + } + +} diff --git a/src/main/java/kr/co/mcmp/manifest/K8SDeployService.java b/src/main/java/kr/co/mcmp/manifest/K8SDeployService.java new file mode 100644 index 0000000..89ba960 --- /dev/null +++ b/src/main/java/kr/co/mcmp/manifest/K8SDeployService.java @@ -0,0 +1,27 @@ +package kr.co.mcmp.manifest; + +import kr.co.mcmp.manifest.k8s.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import java.io.IOException; + +@Service +public class K8SDeployService{ + + private static Logger logger = LoggerFactory.getLogger(K8SDeployService.class); + + @Autowired + private K8SDeployYamlGenerator deployYamlGenerator; + + + //yaml 미리보기 + public String getK8SDeployYaml(K8SDeployDTO deploy) throws IOException { + String deployYaml = deployYamlGenerator.generateDeployYaml(deploy); + return deployYaml; + } + + + +} diff --git a/src/main/java/kr/co/mcmp/manifest/K8SDeployYamlGenerator.java b/src/main/java/kr/co/mcmp/manifest/K8SDeployYamlGenerator.java index b2c580c..b455c30 100644 --- a/src/main/java/kr/co/mcmp/manifest/K8SDeployYamlGenerator.java +++ b/src/main/java/kr/co/mcmp/manifest/K8SDeployYamlGenerator.java @@ -1,30 +1,24 @@ package kr.co.mcmp.manifest; -//import io.kubernetes.client.common.KubernetesObject; -//import io.kubernetes.client.custom.IntOrString; -//import io.kubernetes.client.custom.Quantity; -//import io.kubernetes.client.openapi.models.*; -//import io.kubernetes.client.util.Yaml; -//import kr.co.mcmp.devops.dto.k8s.*; -//import kr.co.mcmp.devops.model.httpproxy.*; -//import kr.co.mcmp.devops.model.rollout.BlueGreen; -//import kr.co.mcmp.devops.model.rollout.Canary; -//import kr.co.mcmp.devops.model.rollout.Pause; -//import kr.co.mcmp.devops.model.rollout.Rollout; -//import kr.co.mcmp.devops.model.rollout.RolloutSpec; -//import kr.co.mcmp.devops.model.rollout.RolloutStrategy; -// -//import org.apache.commons.lang.StringUtils; -// -//import java.util.ArrayList; -//import java.util.HashMap; -//import java.util.List; -//import java.util.Map; - -//@Component +import io.kubernetes.client.common.KubernetesObject; +import io.kubernetes.client.custom.IntOrString; +import io.kubernetes.client.custom.Quantity; +import io.kubernetes.client.openapi.models.*; +import io.kubernetes.client.util.Yaml; +import kr.co.mcmp.manifest.k8s.*; + +import org.apache.commons.lang3.StringUtils; // lang -> lang3 +//import org.springframework.util.StringUtils; + +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component public class K8SDeployYamlGenerator { -/* - private static Logger logger = LoggerFactory.getLogger(K8SDeployYamlGenerator.class); public String generateDeployYaml(K8SDeployDTO deploy) { @@ -57,13 +51,8 @@ public String generateDeployYaml(K8SDeployDTO deploy) { case CronJob: appendYaml(buffer, getCronJob(deploy)); break; - case Rollout: - Rollout rollout = getRollout(deploy); - appendYaml(buffer, rollout); - if (BlueGreen.name.equals(deploy.getStrategyType())) { - appendYaml(buffer, getPreviewService(deploy)); - } - appendYaml(buffer, getAutoscaler(deploy, rollout)); + case Pod: + appendYaml(buffer, getPod(deploy)); break; } @@ -75,15 +64,12 @@ public String generateDeployYaml(K8SDeployDTO deploy) { // httprpoxy appendYaml(buffer, getTlsSecret(deploy)); - appendYaml(buffer, getHTTPProxy(deploy)); // ingress kbcard ingress 사용하지 않음 // appendYaml(buffer, getIngress(deploy)); String yaml = buffer.toString(); - logger.info("[generateYaml]{}", yaml); - - + //default Label 삭제 removeDefaultLabel(deploy.getLabels()); @@ -145,8 +131,7 @@ private V1Deployment getDeployment(K8SDeployDTO deploy) { deployment.setKind(deploy.getController()); // metadata - V1ObjectMeta metadata = getControllerMetadata(deploy.getController(), deploy.getName(), deploy.getNamespace(), - deploy.getLabels()); + V1ObjectMeta metadata = getControllerMetadata(deploy.getController(), deploy.getName(), deploy.getNamespace(), deploy.getLabels()); deployment.setMetadata(metadata); // spec @@ -172,114 +157,30 @@ private V1Deployment getDeployment(K8SDeployDTO deploy) { return deployment; } - // Rollout - private Rollout getRollout(K8SDeployDTO deploy) { - Rollout rollout = new Rollout(); - rollout.setApiVersion(K8S.Controller.Rollout.getApiVersion()); - rollout.setKind(deploy.getController()); + private V1Pod getPod(K8SDeployDTO deploy) { + + V1Pod pod = new V1Pod(); + pod.setApiVersion(K8S.Controller.Pod.getApiVersion()); + pod.setKind(deploy.getController()); // metadata - V1ObjectMeta metadata = getControllerMetadata(deploy.getController(), deploy.getName(), deploy.getNamespace(), - deploy.getLabels()); - rollout.setMetadata(metadata); + V1ObjectMeta metadata = getControllerMetadata(deploy.getController(), deploy.getName(), deploy.getNamespace(), deploy.getLabels()); + pod.setMetadata(metadata); // spec - RolloutSpec rolloutSpec = new RolloutSpec(); - rollout.setSpec(rolloutSpec); - - // spec.selector - V1LabelSelector labelSelector = new V1LabelSelector(); - labelSelector.setMatchLabels(deploy.getLabels()); - rolloutSpec.setSelector(labelSelector); + V1PodSpec podSpec = new V1PodSpec(); + V1Container container = new V1Container(); + container.setName(deploy.getName().replace("KIND", "pod")); + container.setImage(deploy.getImage()); + //pod.setSpec(podSpec); + podSpec.addContainersItem(container); - // spec.replicas - Integer replicas = (deploy.getReplicas() == null || deploy.getReplicas() == 0) ? 1 : deploy.getReplicas(); - rolloutSpec.setReplicas(replicas); + return pod; + } - // spec.strategy - RolloutStrategy strategy = new RolloutStrategy(); - - switch(deploy.getStrategyType()) { - case BlueGreen.name: - BlueGreen blueGreen = new BlueGreen(); - String activeServiceName = getServiceName(deploy); - String previewServiceName = String.format("%s-preview", activeServiceName); - blueGreen.setActiveService(activeServiceName); - blueGreen.setPreviewService(previewServiceName); - blueGreen.setAutoPromotionEnabled(true); - // blueGreen.setAutoPromotionSeconds(replicas); - strategy.setBlueGreen(blueGreen); - break; - case Canary.name: - Canary canary = getCanary(deploy, false); - strategy.setCanary(canary); - break; - } - rolloutSpec.setStrategy(strategy); - // template(pod) - rolloutSpec.setTemplate(getPodTemplateSpec(deploy)); - return rollout; - } - - - private Canary getCanary(K8SDeployDTO deploy, boolean promote) { - - Canary canary = new Canary(); - Map stepMap = null; - - if (promote) { - - //canary.setMaxSurge("100%"); - canary.setMaxUnavailable(0); - - //50% - stepMap = new HashMap<> (1); - stepMap.put("setWeight", 50); - canary.addStep(stepMap); - - //5sec - stepMap = new HashMap<> (1); - stepMap.put("pause", new Pause(5)); - canary.addStep(stepMap); - - //75% - stepMap = new HashMap<> (1); - stepMap.put("setWeight", 75); - canary.addStep(stepMap); - - //5sec - stepMap = new HashMap<> (1); - stepMap.put("pause", new Pause(5)); - canary.addStep(stepMap); - - //100 - stepMap = new HashMap<> (1); - stepMap.put("setWeight", 100); - canary.addStep(stepMap); - - } else { - - //canary.setMaxSurge("25%"); - canary.setMaxUnavailable(0); - - //순서중요!! Object Model 만들어 Yaml dump시 알파벳 오더링 규칙에 따라 순서가 뒤바뀜 - //int setWeight = Math.floorDiv(100, deploy.getReplicas()); - stepMap = new HashMap<> (1); - stepMap.put("setWeight", 25); - canary.addStep(stepMap); - - //suspend - stepMap = new HashMap<> (1); - stepMap.put("pause", new Pause()); - canary.addStep(stepMap); - - } - - return canary; - } // DaemonSet private V1DaemonSet getDaemonSet(K8SDeployDTO deploy) { @@ -289,8 +190,7 @@ private V1DaemonSet getDaemonSet(K8SDeployDTO deploy) { daemonSet.setKind(deploy.getController()); // metadata - V1ObjectMeta metadata = getControllerMetadata(deploy.getController(), deploy.getName(), deploy.getNamespace(), - deploy.getLabels()); + V1ObjectMeta metadata = getControllerMetadata(deploy.getController(), deploy.getName(), deploy.getNamespace(), deploy.getLabels()); daemonSet.setMetadata(metadata); // spec @@ -321,8 +221,7 @@ private V1StatefulSet getStatefulSet(K8SDeployDTO deploy) { statefulSet.setKind(deploy.getController()); // metadata - V1ObjectMeta metadata = getControllerMetadata(deploy.getController(), deploy.getName(), deploy.getNamespace(), - deploy.getLabels()); + V1ObjectMeta metadata = getControllerMetadata(deploy.getController(), deploy.getName(), deploy.getNamespace(), deploy.getLabels()); statefulSet.setMetadata(metadata); // spec @@ -361,8 +260,7 @@ private V1beta1CronJob getCronJob(K8SDeployDTO deploy) { cronJob.setKind(deploy.getController()); // metadata - V1ObjectMeta metadata = getControllerMetadata(deploy.getController(), deploy.getName(), deploy.getNamespace(), - deploy.getLabels()); + V1ObjectMeta metadata = getControllerMetadata(deploy.getController(), deploy.getName(), deploy.getNamespace(), deploy.getLabels()); cronJob.setMetadata(metadata); // spec @@ -581,7 +479,7 @@ private V1PodTemplateSpec getPodTemplateSpec(K8SDeployDTO deploy) { // template.spec.volume setHostPathVolumes(podSpec, deploy.getHostPathVolumes()); setPVCVolumes(podSpec, deploy.getPvcVolumes()); - setAzureFileVolumes(podSpec, deploy.getAzureFileVolumes()); + //setAzureFileVolumes(podSpec, deploy.getAzureFileVolumes()); // template.spec.affinity switch (K8S.Controller.valueOf(deploy.getController())) { @@ -655,26 +553,6 @@ private void setPVCVolumes(V1PodSpec podSpec, List volumesList) { } } - // AzureFileVolumes - private void setAzureFileVolumes(V1PodSpec podSpec, List volumesList) { - - if (volumesList == null || volumesList.size() == 0) { - return; - } - - for (K8SVolume k8sVolume : volumesList) { - V1Volume volume = new V1Volume(); - volume.setName(k8sVolume.getName()); - - V1AzureFileVolumeSource azureFileVolumeSource = new V1AzureFileVolumeSource(); - azureFileVolumeSource.setSecretName(k8sVolume.getSecretName()); - azureFileVolumeSource.setShareName(k8sVolume.getShareName()); - volume.setAzureFile(azureFileVolumeSource); - - podSpec.addVolumesItem(volume); - } - } - private void setResource(V1Container container, K8SResource resource) { if (resource == null) @@ -752,8 +630,6 @@ private V1Affinity getPodAntiAffinity(K8SDeployDTO deploy) { podAntiAffinity.addRequiredDuringSchedulingIgnoredDuringExecutionItem(term); return affinity; - - } // ConfigMap @@ -827,10 +703,6 @@ private V1Secret getTlsSecret(K8SDeployDTO deploy) { // byte[] crtBuf = Base64.encodeBase64(proxyInfo.getTlsCrt().trim().getBytes()); // byte[] keyBuf = Base64.encodeBase64(proxyInfo.getTlsKey().trim().getBytes()); -// logger.info("SECRET-CRT\n{}<---\n----------------------------------------------", proxyInfo.getTlsCrt()); -// logger.info("SECRET-CRT\n{}<---\n----------------------------------------------", new String(crtBuf)); -// logger.info("SECRET-KEY\n{}<---\n----------------------------------------------", proxyInfo.getTlsKey()); -// logger.info("SECRET-KEY\n{}<---\n----------------------------------------------", new String(keyBuf)); deploy.getProxyInfo().setTlsSecretName(secret.getMetadata().getName()); @@ -964,70 +836,7 @@ private V1Service getPreviewService(K8SDeployDTO deploy) { private final String KBC_HttpProxy_LoadBalancerPolicy = "Cookie"; - // HttpProxy - private HTTPProxy getHTTPProxy(K8SDeployDTO deploy) { - K8SProxyInfo proxyInfo = deploy.getProxyInfo(); - if (proxyInfo == null) - return null; - if (StringUtils.isBlank(proxyInfo.getDomainName())) - return null; - - HTTPProxy httpProxy = new HTTPProxy(); - httpProxy.setApiVersion(K8S.Kind.HTTPProxy.getApiVersion()); - httpProxy.setKind(K8S.Kind.HTTPProxy.name()); - - String name = getName(K8S.Kind.HTTPProxy.getPostfix(), deploy.getName()); - //String p = (proxyInfo.getTlsYn().equals("Y")) ? "443" : "80"; - //name = String.format("%s-%s", name, p); - - httpProxy.setMetadata(getMetadata(name, deploy.getNamespace())); - - // spec - HTTPProxySpec spec = new HTTPProxySpec(); - httpProxy.setSpec(spec); - - // virtualhost - Virtualhost virtualhost = new Virtualhost(); - spec.setVirtualhost(virtualhost); - // doamin - virtualhost.setFqdn(proxyInfo.getDomainName()); - // tls - if (proxyInfo.getTlsYn().equals("Y")) { - Tls tls = new Tls(); - tls.setSecretName(proxyInfo.getTlsSecretName()); - virtualhost.setTls(tls); - } - - List routeList = new ArrayList(); - spec.setRoutes(routeList); - - Route route = new Route(); - routeList.add(route); - - // LoadBalancerPolicy Cookie - LoadBalancerPolicy loadBalancerPolicy = new LoadBalancerPolicy(); - loadBalancerPolicy.setStrategy(KBC_HttpProxy_LoadBalancerPolicy); - route.setLoadBalancerPolicy(loadBalancerPolicy); - - List list = new ArrayList(); - route.setServices(list); - - // Service - List portList = deploy.getPorts(); - for (K8SPort port : portList) { - RouteService service = new RouteService(); - service.setName(getServiceName(deploy)); - service.setPort(port.getPort()); -// if (StringUtils.isNotBlank(port.getProtocol())) { -// service.setProtocol(port.getProtocol()); -// } - - list.add(service); - } - - return httpProxy; - } private V2beta2HorizontalPodAutoscaler getAutoscaler(K8SDeployDTO deploy, KubernetesObject object) { @@ -1139,52 +948,6 @@ private V1PersistentVolumeClaim getPvc(K8SDeployDTO deploy, K8SVolume volume) { return pvc; } - // Ingress - /** - * private ExtensionsV1beta1Ingress getIngress(K8SDeployDTO deploy) { - * - * if (deploy.getPorts() == null || deploy.getPorts().isEmpty()) { return null; - * } - * - * List paths = new ArrayList<> (); for - * (K8SPort port : deploy.getPorts()) { - * - * if (port.getIngressPath() == null || port.getIngressPath().isEmpty()) { - * continue; } - * - * //spec.rule.paths.path ExtensionsV1beta1HTTPIngressPath path = new - * ExtensionsV1beta1HTTPIngressPath(); String ingressPath = - * (deploy.getIngressPathRewriteYn().equals("Y")) ? String.format("%s(/|$)(.*)", - * port.getIngressPath()) : port.getIngressPath(); path.setPath(ingressPath); - * //spec.rule.paths.backend ExtensionsV1beta1IngressBackend backend = new - * ExtensionsV1beta1IngressBackend(); - * backend.setServiceName(getName(K8S.Kind.Service.getPostfix(), - * deploy.getName())); backend.setServicePort(new IntOrString(port.getPort())); - * path.setBackend(backend); - * - * paths.add(path); } - * - * if (paths.size() == 0) { return null; } - * - * ExtensionsV1beta1Ingress ingress = new ExtensionsV1beta1Ingress(); - * ingress.apiVersion(K8S.Kind.Ingress.getApiVersion()); - * ingress.setKind(K8S.Kind.Ingress.name()); - * - * //metadata V1ObjectMeta metadata = getMetadata(K8S.Kind.Ingress.getPostfix(), - * deploy.getName()); metadata.setNamespace(deploy.getNamespace()); - * //metadata.annotation if (deploy.getIngressPathRewriteYn().equals("Y")) { - * metadata.setAnnotations(K8S.getIngressRewriteAnnotaions()); } - * ingress.setMetadata(metadata); - * - * //spec ExtensionsV1beta1IngressSpec ingressSpec = new - * ExtensionsV1beta1IngressSpec(); ingress.setSpec(ingressSpec); - * - * //spec.rules List rules = new ArrayList<>(1); - * ExtensionsV1beta1IngressRule rule = new ExtensionsV1beta1IngressRule(); - * rule.setHttp(new ExtensionsV1beta1HTTPIngressRuleValue()); - * rule.getHttp().setPaths(paths); rules.add(rule); ingressSpec.setRules(rules); - * - * return ingress; } - **/ + } diff --git a/src/main/java/kr/co/mcmp/manifest/YamlGenerateController.java b/src/main/java/kr/co/mcmp/manifest/YamlGenerateController.java index d430d7e..01cf456 100644 --- a/src/main/java/kr/co/mcmp/manifest/YamlGenerateController.java +++ b/src/main/java/kr/co/mcmp/manifest/YamlGenerateController.java @@ -2,6 +2,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import kr.co.mcmp.manifest.k8s.K8SDeployDTO; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -21,25 +22,25 @@ public class YamlGenerateController { @Operation(summary = "yaml generate for pod") @PostMapping("/pod") - public String generatePodYaml(){ + public String generatePodYaml(K8SDeployDTO k8sDto){ return null; } @Operation(summary = "yaml generate for deployment") @PostMapping("/deployment") - public String generateDeploymentYaml(){ + public String generateDeploymentYaml(K8SDeployDTO k8sDto){ return null; } @Operation(summary = "yaml generate for service") @PostMapping("/service") - public String generateServiceYaml(){ + public String generateServiceYaml(K8SDeployDTO k8sDto){ return null; } @Operation(summary = "yaml generate for configmap") @PostMapping("/configmap") - public String generateConfigmapYaml(){ + public String generateConfigmapYaml(K8SDeployDTO k8sDto){ return null; } diff --git a/src/main/java/kr/co/mcmp/manifest/k8s/K8SDeployDTO.java b/src/main/java/kr/co/mcmp/manifest/k8s/K8SDeployDTO.java index af26aa2..911bafc 100644 --- a/src/main/java/kr/co/mcmp/manifest/k8s/K8SDeployDTO.java +++ b/src/main/java/kr/co/mcmp/manifest/k8s/K8SDeployDTO.java @@ -5,13 +5,21 @@ import java.util.List; import java.util.Map; -public class K8SDeployDTO extends K8SDeployBaseDTO implements Serializable { +public class K8SDeployDTO extends DeployDTO implements Serializable { private static final long serialVersionUID = 5433248174008755823L; @NotNull private String namespace = "default"; + private String image; + public String getImage() { + return image; + } + public void setImage(String image) { + this.image = image; + } + @NotNull private String controller; diff --git a/src/main/java/kr/co/mcmp/oss/dto/OssDto.java b/src/main/java/kr/co/mcmp/oss/dto/OssDto.java index ed13e3a..2db9270 100644 --- a/src/main/java/kr/co/mcmp/oss/dto/OssDto.java +++ b/src/main/java/kr/co/mcmp/oss/dto/OssDto.java @@ -1,12 +1,16 @@ package kr.co.mcmp.oss.dto; import kr.co.mcmp.oss.entity.Oss; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; +import lombok.NoArgsConstructor; @Getter @Builder +@NoArgsConstructor +@AllArgsConstructor public class OssDto { private Long ossIdx; diff --git a/src/main/java/kr/co/mcmp/oss/dto/OssTypeDto.java b/src/main/java/kr/co/mcmp/oss/dto/OssTypeDto.java index a026995..c7fa9eb 100644 --- a/src/main/java/kr/co/mcmp/oss/dto/OssTypeDto.java +++ b/src/main/java/kr/co/mcmp/oss/dto/OssTypeDto.java @@ -1,12 +1,16 @@ package kr.co.mcmp.oss.dto; import kr.co.mcmp.oss.entity.OssType; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; +import lombok.NoArgsConstructor; @Getter @Builder +@NoArgsConstructor +@AllArgsConstructor public class OssTypeDto { private Long ossTypeIdx; diff --git a/src/main/java/kr/co/mcmp/oss/repository/OssRepository.java b/src/main/java/kr/co/mcmp/oss/repository/OssRepository.java index d3b07f2..f3486a0 100644 --- a/src/main/java/kr/co/mcmp/oss/repository/OssRepository.java +++ b/src/main/java/kr/co/mcmp/oss/repository/OssRepository.java @@ -11,7 +11,7 @@ @Repository public interface OssRepository extends JpaRepository { List findAll(); - List findByOssName(String ossName); + Oss findByOssName(String ossName); @Query("SELECT o FROM Oss o WHERE o.ossType.ossTypeIdx IN :ossTypeIdxs") List findByOssTypeIdxIn(@Param("ossTypeIdxs") List ossTypeIdxs); Boolean existsByOssNameAndOssUrlAndOssUsername(String ossName, String ossUrl, String ossUsername); diff --git a/src/main/java/kr/co/mcmp/oss/service/OssServiceImpl.java b/src/main/java/kr/co/mcmp/oss/service/OssServiceImpl.java index e443789..62bb707 100644 --- a/src/main/java/kr/co/mcmp/oss/service/OssServiceImpl.java +++ b/src/main/java/kr/co/mcmp/oss/service/OssServiceImpl.java @@ -6,8 +6,9 @@ import kr.co.mcmp.oss.nexus.service.NexusService; import kr.co.mcmp.oss.repository.OssRepository; import kr.co.mcmp.oss.repository.OssTypeRepository; -import kr.co.mcmp.util.AES256Util; -import kr.co.mcmp.util.Base64Util; +import kr.co.mcmp.util.AES256Utils; + +import kr.co.mcmp.util.Base64Utils; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; @@ -175,6 +176,21 @@ public OssDto detailOss(Long ossIdx) { return OssDto.withDetailDecryptPassword(oss, encodingBase64String(decryptAesString(oss.getOssPassword()))); } + public OssDto detailOssByOssName(String ossName) { + Oss oss = ossRepository.findByOssName(ossName); + String pwd = oss.getOssPassword(); + String decodePwd = Base64Utils.base64Decoding(pwd); + return OssDto.builder() + .ossIdx(oss.getOssIdx()) + .ossTypeIdx(oss.getOssType().getOssTypeIdx()) + .ossName(oss.getOssName()) + .ossDesc(oss.getOssDesc()) + .ossUrl(oss.getOssUrl()) + .ossUsername(oss.getOssUsername()) + .ossPassword(decodePwd) + .build(); + } + // /** // * OSS 정보 상세 조회 // * @param ossCd @@ -204,7 +220,7 @@ public Boolean isOssInfoDuplicated(OssDto ossDto) { */ public String encryptBase64String(String str) { if ( StringUtils.isNotBlank(str) ) { - return Base64Util.base64Encoding(AES256Util.decryptOssPassword(str)); + return Base64Utils.base64Encoding(AES256Utils.encrypt(str)); } else { return null; @@ -218,7 +234,7 @@ public String encryptBase64String(String str) { */ public String encryptAesString(String str) { if ( StringUtils.isNotBlank(str) ) { - return AES256Util.encryptOssPassword(Base64Util.base64Decoding(str)); + return AES256Utils.encrypt(Base64Utils.base64Decoding(str)); } else { return null; @@ -231,7 +247,7 @@ public String encryptAesString(String str) { */ public String encodingBase64String(String str) { if ( StringUtils.isNotBlank(str) ) { - return Base64Util.base64Encoding(str); + return Base64Utils.base64Encoding(str); } else { return null; @@ -246,7 +262,7 @@ public String encodingBase64String(String str) { public String decryptAesString(String encryptedStr) { if (StringUtils.isNotBlank(encryptedStr)) { // AES256으로 암호화된 문자열을 복호화 - String decrypted = AES256Util.decryptOssPassword(encryptedStr); + String decrypted = AES256Utils.decrypt(encryptedStr); // 복호화된 문자열을 Base64로 인코딩 return decrypted; } else { diff --git a/src/main/java/kr/co/mcmp/service/oss/component/CommonComponentFactory.java b/src/main/java/kr/co/mcmp/service/oss/component/CommonComponentFactory.java new file mode 100644 index 0000000..37229fc --- /dev/null +++ b/src/main/java/kr/co/mcmp/service/oss/component/CommonComponentFactory.java @@ -0,0 +1,21 @@ +package kr.co.mcmp.service.oss.component; + +import kr.co.mcmp.service.oss.component.nexus.NexusComponentService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class CommonComponentFactory { + + private final NexusComponentService nexusComponentService; + + public CommonComponentService generatedComponentService(String module) { + switch (module) { + case "nexus": + return nexusComponentService; + default: + throw new IllegalArgumentException("Unsupported module: " + module); + } + } +} diff --git a/src/main/java/kr/co/mcmp/service/oss/component/CommonComponentService.java b/src/main/java/kr/co/mcmp/service/oss/component/CommonComponentService.java new file mode 100644 index 0000000..f0358f9 --- /dev/null +++ b/src/main/java/kr/co/mcmp/service/oss/component/CommonComponentService.java @@ -0,0 +1,17 @@ +package kr.co.mcmp.service.oss.component; + +import kr.co.mcmp.dto.oss.component.CommonComponent; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +public interface CommonComponentService { + + List getComponentList(String name); + + CommonComponent.ComponentDto getComponentDetailByName(String id); + + void deleteComponent(String id); + + void createComponent(String name, String directory, List files); +} diff --git a/src/main/java/kr/co/mcmp/service/oss/component/CommonModuleComponentService.java b/src/main/java/kr/co/mcmp/service/oss/component/CommonModuleComponentService.java new file mode 100644 index 0000000..b255060 --- /dev/null +++ b/src/main/java/kr/co/mcmp/service/oss/component/CommonModuleComponentService.java @@ -0,0 +1,39 @@ +package kr.co.mcmp.service.oss.component; + +import kr.co.mcmp.dto.oss.component.CommonComponent; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class CommonModuleComponentService { + + private final CommonComponentFactory componentFactory; + + public List getComponentList(String module, String name) { + CommonComponentService componentService = getComponentService(module); + return componentService.getComponentList(name); + } + + public CommonComponent.ComponentDto getComponentDetailByName(String module, String id) { + CommonComponentService componentService = getComponentService(module); + return componentService.getComponentDetailByName(id); + } + + public void deleteComponent(String module, String id) { + CommonComponentService componentService = getComponentService(module); + componentService.deleteComponent(id); + } + + public void createComponent(String module, String name, String directory, List files) { + CommonComponentService componentService = getComponentService(module); + componentService.createComponent(name, directory, files); + } + + private CommonComponentService getComponentService(String module) { + return componentFactory.generatedComponentService(module); + } +} diff --git a/src/main/java/kr/co/mcmp/service/oss/component/nexus/NexusComponentAdapterClient.java b/src/main/java/kr/co/mcmp/service/oss/component/nexus/NexusComponentAdapterClient.java new file mode 100644 index 0000000..22e23a3 --- /dev/null +++ b/src/main/java/kr/co/mcmp/service/oss/component/nexus/NexusComponentAdapterClient.java @@ -0,0 +1,152 @@ +package kr.co.mcmp.service.oss.component.nexus; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import kr.co.mcmp.config.oss.RestTemplateProvider; +import kr.co.mcmp.dto.oss.component.CommonComponent; +import kr.co.mcmp.exception.NexusClientException; +import kr.co.mcmp.oss.dto.OssDto; +import kr.co.mcmp.oss.service.OssServiceImpl; +import kr.co.mcmp.util.Base64Util; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.*; +import org.springframework.stereotype.Service; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +@Service +public class NexusComponentAdapterClient { + + private static final String GET_COMP_LIST = "/v1/components"; + private static final String GET_COMP_DETAIL = "/v1/components/{id}"; + private static final String DELETE_COMP_DELETE = "/v1/components/{id}"; + private static final String POST_COMP_CREATE = "/v1/components"; + + private String nexusId = ""; + private String nexusPwd = ""; + private String baseUrl = ""; + private String authorization = "Authorization"; + + @Autowired private ObjectMapper mapper; + @Autowired private OssServiceImpl ossService; + + private void getOssInfo() { + try { + OssDto nexus = ossService.detailOssByOssName("NEXUS"); + this.nexusId = nexus.getOssUsername(); + this.nexusPwd = nexus.getOssPassword(); + this.baseUrl = nexus.getOssUrl(); + } catch (Exception e) { + throw new IllegalArgumentException ("DB Nexus 계정 정보가 없습니다."); + } + } + + public List getComponentList(String name) { + getOssInfo(); + String url = UriComponentsBuilder.fromHttpUrl(baseUrl) + .path(GET_COMP_LIST) + .queryParam("repository", name) + .toUriString(); + + HttpEntity request = getRequest(null); + Map response = exchange(url, HttpMethod.GET, request, new ParameterizedTypeReference>() {}); + return mapper.convertValue(response.get("items"), new TypeReference>() {}); + } + + public CommonComponent.ComponentDto getComponentDetailByName(String id) { + getOssInfo(); + String url = UriComponentsBuilder.fromHttpUrl(baseUrl) + .path(GET_COMP_DETAIL) + .buildAndExpand(id) + .toUriString(); + + HttpEntity request = getRequest(null); + Map response = exchange(url, HttpMethod.GET, request, new ParameterizedTypeReference>() {}); + return mapper.convertValue(response, new TypeReference() {}); + } + + public Object deleteComponent(String id) { + getOssInfo(); + String url = UriComponentsBuilder.fromHttpUrl(baseUrl) + .path(DELETE_COMP_DELETE) + .buildAndExpand(id) + .toUriString(); + + HttpEntity request = getRequest(null); + return exchange(url, HttpMethod.DELETE, request, new ParameterizedTypeReference() {}); + } + + public Object createComponent(String name, MultiValueMap uploadMap) { + getOssInfo(); + String url = UriComponentsBuilder.fromHttpUrl(baseUrl) + .path(POST_COMP_CREATE) + .queryParam("repository", name) + .toUriString(); + + HttpEntity> request = getUploadRequest(uploadMap); + return exchange(url, HttpMethod.POST, request, new ParameterizedTypeReference() {}); + } + + private HttpEntity getRequest(T body) { + String basicToken = createToken(); + HttpHeaders headers = getHeaders(basicToken); + return new HttpEntity<>(body, headers); + } + + private HttpHeaders getHeaders(String basicToken) { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + headers.set(authorization, basicToken); + return headers; + } + + private HttpEntity getUploadRequest(T body) { + String basicToken = createToken(); + HttpHeaders headers = getUploadHeaders(basicToken); + return new HttpEntity<>(body, headers); + } + + private HttpHeaders getUploadHeaders(String basicToken) { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.MULTIPART_FORM_DATA); + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + headers.set(authorization, basicToken); + return headers; + } + + private String createToken() { + String auth = nexusId + ":" + nexusPwd; + return "Basic " + Base64Util.base64Encoding(auth); + } + + private T exchange(String url, HttpMethod method, HttpEntity requestEntity, ParameterizedTypeReference responseType) { + RestTemplate template = RestTemplateProvider.get(); + try { + ResponseEntity response = template.exchange(url, method, requestEntity, responseType); + return response.getBody(); + } catch (HttpClientErrorException e) { + String errorMessage = e.getResponseBodyAsString(); + throw new NexusClientException(parseErrorMessage(errorMessage)); + } + } + + private String parseErrorMessage(String errorMessage) { + ObjectMapper mapper = new ObjectMapper(); + try { + JsonNode rootNode = mapper.readTree(errorMessage); + JsonNode messageNode = rootNode.path("message"); + return messageNode.asText().replace("\\\"", "\"").replace("\"", ""); + } catch (Exception e) { + return "Message Parsing Error"; + } + } +} diff --git a/src/main/java/kr/co/mcmp/service/oss/component/nexus/NexusComponentAdapterService.java b/src/main/java/kr/co/mcmp/service/oss/component/nexus/NexusComponentAdapterService.java new file mode 100644 index 0000000..948a9ca --- /dev/null +++ b/src/main/java/kr/co/mcmp/service/oss/component/nexus/NexusComponentAdapterService.java @@ -0,0 +1,59 @@ +package kr.co.mcmp.service.oss.component.nexus; + +import kr.co.mcmp.dto.oss.component.CommonComponent; +import kr.co.mcmp.dto.oss.component.CommonUploadComponent; +import kr.co.mcmp.dto.oss.repository.CommonRepository; +import kr.co.mcmp.service.oss.repository.nexus.NexusRepositoryAdapterService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class NexusComponentAdapterService { + + private final NexusComponentAdapterClient componentAdapterClient; + private final NexusRepositoryAdapterService nexusRepositoryAdapterService; + + public List getComponentList(String name) { + return componentAdapterClient.getComponentList(name); + } + + public CommonComponent.ComponentDto getComponentDetailByName(String id) { + return componentAdapterClient.getComponentDetailByName(id); + } + + public void deleteComponent(String id) { + componentAdapterClient.deleteComponent(id); + } + + public void createComponent(String name, CommonUploadComponent uploadComponent) { + CommonRepository.RepositoryDto repositoryByName = nexusRepositoryAdapterService.getRepositoryByName(name); + String format = repositoryByName.getFormat(); + + MultiValueMap uploadComponentMap = getUploadComponentMap(uploadComponent, format); + + componentAdapterClient.createComponent(name, uploadComponentMap); + } + + private static MultiValueMap getUploadComponentMap(CommonUploadComponent uploadComponent, String format) { + MultiValueMap uploadComponentMap = new LinkedMultiValueMap<>(); + + if ("raw".equals(format)) { + uploadComponentMap.add(format + ".directory", uploadComponent.getDirectory()); + + for (int i = 0; i < uploadComponent.getAsset().size(); i ++) { + CommonUploadComponent.FilesDto filesDto = uploadComponent.getAsset().get(i); + uploadComponentMap.add(format + ".asset" + (i + 1), filesDto.getFile().getResource()); + uploadComponentMap.add(format + ".asset" + (i + 1) + ".filename", filesDto.getFilename()); + } + } else if ("docker".equals(format) || "helm".equals(format)) { + CommonUploadComponent.FilesDto filesDto = uploadComponent.getAsset().get(0); + uploadComponentMap.add(format + ".asset", filesDto.getFile().getResource()); + } + return uploadComponentMap; + } +} diff --git a/src/main/java/kr/co/mcmp/service/oss/component/nexus/NexusComponentService.java b/src/main/java/kr/co/mcmp/service/oss/component/nexus/NexusComponentService.java new file mode 100644 index 0000000..6125bd7 --- /dev/null +++ b/src/main/java/kr/co/mcmp/service/oss/component/nexus/NexusComponentService.java @@ -0,0 +1,56 @@ +package kr.co.mcmp.service.oss.component.nexus; + +import kr.co.mcmp.dto.oss.component.CommonComponent; +import kr.co.mcmp.dto.oss.component.CommonUploadComponent; +import kr.co.mcmp.service.oss.component.CommonComponentService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.util.ArrayList; +import java.util.List; + +@Service +@RequiredArgsConstructor +public class NexusComponentService implements CommonComponentService { + + private final NexusComponentAdapterService componentAdapterService; + + @Override + public List getComponentList(String name) { + return componentAdapterService.getComponentList(name); + } + + @Override + public CommonComponent.ComponentDto getComponentDetailByName(String id) { + return componentAdapterService.getComponentDetailByName(id); + } + + @Override + public void deleteComponent(String id) { + componentAdapterService.deleteComponent(id); + } + + @Override + public void createComponent(String name, String directory, List files) { + + List uploadFileList = new ArrayList<>(); + + for (MultipartFile file : files) { + CommonUploadComponent.FilesDto filesDto = CommonUploadComponent.FilesDto.builder() + .file(file) + .filename(file.getOriginalFilename()) + .build(); + + uploadFileList.add(filesDto); + } + + CommonUploadComponent uploadComponent = CommonUploadComponent.builder() + .directory(directory) + .asset(uploadFileList) + .build(); + + componentAdapterService.createComponent(name, uploadComponent); + } +} + diff --git a/src/main/java/kr/co/mcmp/service/oss/repository/CommonModuleRepositoryService.java b/src/main/java/kr/co/mcmp/service/oss/repository/CommonModuleRepositoryService.java new file mode 100644 index 0000000..020df3e --- /dev/null +++ b/src/main/java/kr/co/mcmp/service/oss/repository/CommonModuleRepositoryService.java @@ -0,0 +1,43 @@ +package kr.co.mcmp.service.oss.repository; + +import kr.co.mcmp.dto.oss.repository.CommonRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class CommonModuleRepositoryService { + + private final CommonRepositoryFactory repositoryFactory; + + public List getRepositoryList(String module) { + CommonRepositoryService repositoryService = getRepositoryService(module); + return repositoryService.getRepositoryList(); + } + + public CommonRepository.RepositoryDto getRepositoryDetailByName(String module, String name) { + CommonRepositoryService repositoryService = getRepositoryService(module); + return repositoryService.getRepositoryDetailByName(name); + } + + public void createRepository(String module, CommonRepository.RepositoryDto repositoryDto) { + CommonRepositoryService repositoryService = getRepositoryService(module); + repositoryService.createRepository(repositoryDto); + } + + public void updateRepository(String module, CommonRepository.RepositoryDto repositoryDto) { + CommonRepositoryService repositoryService = getRepositoryService(module); + repositoryService.updateRepository(repositoryDto); + } + + public void deleteRepository(String module, String name) { + CommonRepositoryService repositoryService = getRepositoryService(module); + repositoryService.deleteRepository(name); + } + + private CommonRepositoryService getRepositoryService(String module) { + return repositoryFactory.generatedRepositoryService(module); + } +} diff --git a/src/main/java/kr/co/mcmp/service/oss/repository/CommonRepositoryFactory.java b/src/main/java/kr/co/mcmp/service/oss/repository/CommonRepositoryFactory.java new file mode 100644 index 0000000..8e2ac99 --- /dev/null +++ b/src/main/java/kr/co/mcmp/service/oss/repository/CommonRepositoryFactory.java @@ -0,0 +1,21 @@ +package kr.co.mcmp.service.oss.repository; + +import kr.co.mcmp.service.oss.repository.nexus.NexusRepositoryService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class CommonRepositoryFactory { + + private final NexusRepositoryService nexusRepositoryService; + + public CommonRepositoryService generatedRepositoryService(String module) { + switch (module) { + case "nexus": + return nexusRepositoryService; + default: + throw new IllegalArgumentException("Unsupported module: " + module); + } + } +} diff --git a/src/main/java/kr/co/mcmp/service/oss/repository/CommonRepositoryService.java b/src/main/java/kr/co/mcmp/service/oss/repository/CommonRepositoryService.java new file mode 100644 index 0000000..5e0ab91 --- /dev/null +++ b/src/main/java/kr/co/mcmp/service/oss/repository/CommonRepositoryService.java @@ -0,0 +1,20 @@ +package kr.co.mcmp.service.oss.repository; + +import kr.co.mcmp.dto.oss.repository.CommonRepository; + +import java.util.List; + +public interface CommonRepositoryService { + + List getRepositoryList(); + + CommonRepository.RepositoryDto getRepositoryByName(String name); + + CommonRepository.RepositoryDto getRepositoryDetailByName(String name); + + void createRepository(CommonRepository.RepositoryDto repositoryDto); + + void updateRepository(CommonRepository.RepositoryDto repositoryDto); + + void deleteRepository(String name); +} diff --git a/src/main/java/kr/co/mcmp/service/oss/repository/nexus/NexusRepositoryAdapterClient.java b/src/main/java/kr/co/mcmp/service/oss/repository/nexus/NexusRepositoryAdapterClient.java new file mode 100644 index 0000000..4012838 --- /dev/null +++ b/src/main/java/kr/co/mcmp/service/oss/repository/nexus/NexusRepositoryAdapterClient.java @@ -0,0 +1,156 @@ +package kr.co.mcmp.service.oss.repository.nexus; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import kr.co.mcmp.config.oss.RestTemplateProvider; +import kr.co.mcmp.dto.oss.repository.CommonFormatType; +import kr.co.mcmp.dto.oss.repository.CommonRepository; +import kr.co.mcmp.exception.NexusClientException; +import kr.co.mcmp.oss.dto.OssDto; +import kr.co.mcmp.oss.service.OssServiceImpl; +import kr.co.mcmp.util.Base64Util; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.*; +import org.springframework.stereotype.Service; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.Collections; +import java.util.List; + +@Service +public class NexusRepositoryAdapterClient { + + private static final String GET_REPO_LIST = "/v1/repositories"; + private static final String GET_REPO_BY_NAME = "/v1/repositories/{repositoryName}"; + private static final String GET_REPO_DETAIL = "/v1/repositories/{format}/{type}/{repositoryName}"; + private static final String POST_REPO_CREATE = "/v1/repositories/{format}/{type}"; + private static final String PUT_REPO_UPDATE = "/v1/repositories/{format}/{type}/{repositoryName}"; + private static final String DELETE_REPO_DELETE = "/v1/repositories/{repositoryName}"; + + private String nexusId = ""; + private String nexusPwd = ""; + private String baseUrl = ""; + private String authorization = "Authorization"; + + @Autowired private OssServiceImpl ossService; + + private void getOssInfo() { + try { + OssDto nexus = ossService.detailOssByOssName("NEXUS"); + this.nexusId = nexus.getOssUsername(); + this.nexusPwd = nexus.getOssPassword(); + this.baseUrl = nexus.getOssUrl(); + } catch (Exception e) { + throw new IllegalArgumentException ("DB Nexus 계정 정보가 없습니다."); + } + } + + public List getRepositoryList() { + getOssInfo(); + String url = UriComponentsBuilder.fromHttpUrl(baseUrl) + .path(GET_REPO_LIST) + .toUriString(); + + HttpEntity request = getRequest(null); + return exchange(url, HttpMethod.GET, request, new ParameterizedTypeReference>() {}); + } + + public CommonRepository.RepositoryDto getRepositoryByName(String name) { + getOssInfo(); + String url = UriComponentsBuilder.fromHttpUrl(baseUrl) + .path(GET_REPO_BY_NAME) + .buildAndExpand(name) + .toUriString(); + + HttpEntity request = getRequest(null); + return exchange(url, HttpMethod.GET, request, new ParameterizedTypeReference() {}); + } + + public CommonRepository.RepositoryDto getRepositoryDetailByName(CommonFormatType formatType, String name) { + getOssInfo(); + String url = UriComponentsBuilder.fromHttpUrl(baseUrl) + .path(GET_REPO_DETAIL) + .buildAndExpand(formatType.getFormat(), formatType.getType(), name) + .toUriString(); + + HttpEntity request = getRequest(null); + return exchange(url, HttpMethod.GET, request, new ParameterizedTypeReference() {}); + } + + public Object createRepository(CommonRepository.RepositoryDto repositoryDto) { + getOssInfo(); + String url = UriComponentsBuilder.fromHttpUrl(baseUrl) + .path(POST_REPO_CREATE) + .buildAndExpand(repositoryDto.getFormat(), repositoryDto.getType()) + .toUriString(); + + HttpEntity request = getRequest(repositoryDto); + return exchange(url, HttpMethod.POST, request, new ParameterizedTypeReference() {}); + } + + public Object updateRepository(CommonRepository.RepositoryDto repositoryDto) { + getOssInfo(); + String url = UriComponentsBuilder.fromHttpUrl(baseUrl) + .path(PUT_REPO_UPDATE) + .buildAndExpand(repositoryDto.getFormat(), repositoryDto.getType(), repositoryDto.getName()) + .toUriString(); + + HttpEntity request = getRequest(repositoryDto); + return exchange(url, HttpMethod.PUT, request, new ParameterizedTypeReference() {}); + } + + public Object deleteRepository(String name) { + getOssInfo(); + String url = UriComponentsBuilder.fromHttpUrl(baseUrl) + .path(DELETE_REPO_DELETE) + .buildAndExpand(name) + .toUriString(); + + HttpEntity request = getRequest(null); + return exchange(url, HttpMethod.DELETE, request, new ParameterizedTypeReference() {}); + } + + private HttpEntity getRequest(T body) { + String basicToken = createToken(); + HttpHeaders headers = getHeaders(basicToken); + return new HttpEntity<>(body, headers); + } + + private HttpHeaders getHeaders(String basicToken) { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + headers.set(authorization, basicToken); + return headers; + } + + private String createToken() { + String auth = nexusId + ":" + nexusPwd; + return "Basic " + Base64Util.base64Encoding(auth); + } + + private T exchange(String url, HttpMethod method, HttpEntity requestEntity, ParameterizedTypeReference responseType) { + RestTemplate template = RestTemplateProvider.get(); + try { + ResponseEntity response = template.exchange(url, method, requestEntity, responseType); + return response.getBody(); + } catch (HttpClientErrorException e) { + String errorMessage = e.getResponseBodyAsString(); + throw new NexusClientException(parseErrorMessage(errorMessage)); + } + } + + private String parseErrorMessage(String errorMessage) { + ObjectMapper mapper = new ObjectMapper(); + try { + JsonNode rootNode = mapper.readTree(errorMessage); + JsonNode messageNode = rootNode.path("message"); + return messageNode.asText().replace("\\\"", "\"").replace("\"", ""); + } catch (Exception e) { + return "Message Parsing Error"; + } + } +} diff --git a/src/main/java/kr/co/mcmp/service/oss/repository/nexus/NexusRepositoryAdapterService.java b/src/main/java/kr/co/mcmp/service/oss/repository/nexus/NexusRepositoryAdapterService.java new file mode 100644 index 0000000..cc9cfbf --- /dev/null +++ b/src/main/java/kr/co/mcmp/service/oss/repository/nexus/NexusRepositoryAdapterService.java @@ -0,0 +1,39 @@ +package kr.co.mcmp.service.oss.repository.nexus; + +import kr.co.mcmp.dto.oss.repository.CommonFormatType; +import kr.co.mcmp.dto.oss.repository.CommonRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class NexusRepositoryAdapterService { + + private final NexusRepositoryAdapterClient repositoryAdapterClient; + + public List getRepositoryList() { + return repositoryAdapterClient.getRepositoryList(); + } + + public CommonRepository.RepositoryDto getRepositoryByName(String name) { + return repositoryAdapterClient.getRepositoryByName(name); + } + + public CommonRepository.RepositoryDto getRepositoryDetailByName(CommonFormatType formatType, String name) { + return repositoryAdapterClient.getRepositoryDetailByName(formatType, name); + } + + public void createRepository(CommonRepository.RepositoryDto repositoryDto) { + repositoryAdapterClient.createRepository(repositoryDto); + } + + public void updateRepository(CommonRepository.RepositoryDto repositoryDto) { + repositoryAdapterClient.updateRepository(repositoryDto); + } + + public void deleteRepository(String name) { + repositoryAdapterClient.deleteRepository(name); + } +} diff --git a/src/main/java/kr/co/mcmp/service/oss/repository/nexus/NexusRepositoryService.java b/src/main/java/kr/co/mcmp/service/oss/repository/nexus/NexusRepositoryService.java new file mode 100644 index 0000000..9cd3020 --- /dev/null +++ b/src/main/java/kr/co/mcmp/service/oss/repository/nexus/NexusRepositoryService.java @@ -0,0 +1,53 @@ +package kr.co.mcmp.service.oss.repository.nexus; + +import kr.co.mcmp.dto.oss.repository.CommonFormatType; +import kr.co.mcmp.dto.oss.repository.CommonRepository; +import kr.co.mcmp.service.oss.repository.CommonRepositoryService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class NexusRepositoryService implements CommonRepositoryService { + + private final NexusRepositoryAdapterService repositoryAdapterService; + + @Override + public List getRepositoryList() { + return repositoryAdapterService.getRepositoryList(); + } + + @Override + public CommonRepository.RepositoryDto getRepositoryByName(String name) { + return repositoryAdapterService.getRepositoryByName(name); + } + + @Override + public CommonRepository.RepositoryDto getRepositoryDetailByName(String name) { + CommonRepository.RepositoryDto repositoryByName = getRepositoryByName(name); + + CommonFormatType formatType = CommonFormatType.builder() + .format(repositoryByName.getFormat()) + .type(repositoryByName.getType()) + .build(); + + return repositoryAdapterService.getRepositoryDetailByName(formatType, name); + } + + @Override + public void createRepository(CommonRepository.RepositoryDto repositoryDto) { + repositoryAdapterService.createRepository(repositoryDto); + } + + @Override + public void updateRepository(CommonRepository.RepositoryDto repositoryDto) { + repositoryAdapterService.updateRepository(repositoryDto); + } + + @Override + public void deleteRepository(String name) { + repositoryAdapterService.deleteRepository(name); + } +} diff --git a/src/main/java/kr/co/mcmp/util/AES256Utils.java b/src/main/java/kr/co/mcmp/util/AES256Utils.java new file mode 100644 index 0000000..5097f4d --- /dev/null +++ b/src/main/java/kr/co/mcmp/util/AES256Utils.java @@ -0,0 +1,77 @@ +package kr.co.mcmp.util; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.binary.Base64; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.io.UnsupportedEncodingException; +import java.security.GeneralSecurityException; + +@Component +@Slf4j +public class AES256Utils { + + private static String authAesKey; + + @Value("${aes.key}") + public void setAuthAesKey(String aesKey) { + authAesKey = aesKey; + } + + public static String encrypt(String str) { + String enStr = null; + + try { + String iv = authAesKey.substring(0, 16); + byte[] keyBytes = new byte[16]; + byte[] b = authAesKey.getBytes("UTF-8"); + int len = b.length; + if (len > keyBytes.length) { + len = keyBytes.length; + } + System.arraycopy(b, 0, keyBytes, 0, len); + SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES"); + + Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding"); + c.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(iv.getBytes())); + byte[] encrypted = c.doFinal(str.getBytes("UTF-8")); + enStr = new String(Base64.encodeBase64(encrypted)); + + } catch (GeneralSecurityException | UnsupportedEncodingException e ) { + log.error("[AES256Utils] encrypt error >>>>>>>>>>>>>>>>>> ", e); + return null; + } + + return enStr; + } + + public static String decrypt(String str){ + String deStr = null; + + try { + String iv = authAesKey.substring(0, 16); + byte[] keyBytes = new byte[16]; + byte[] b = authAesKey.getBytes("UTF-8"); + int len = b.length; + if (len > keyBytes.length) { + len = keyBytes.length; + } + System.arraycopy(b, 0, keyBytes, 0, len); + SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES"); + + Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding"); + c.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(iv.getBytes())); + byte[] byteStr = Base64.decodeBase64(str.getBytes()); + deStr = new String(c.doFinal(byteStr), "UTF-8"); + }catch (GeneralSecurityException | UnsupportedEncodingException e ) { + log.error("[AES256Utils] decrypt error >>>>>>>>>>>>>>>>>> ", e); + return null; + } + + return deStr; + } +} diff --git a/src/main/java/kr/co/mcmp/util/Base64Utils.java b/src/main/java/kr/co/mcmp/util/Base64Utils.java new file mode 100644 index 0000000..8293a14 --- /dev/null +++ b/src/main/java/kr/co/mcmp/util/Base64Utils.java @@ -0,0 +1,50 @@ +package kr.co.mcmp.util; + +import java.io.UnsupportedEncodingException; +import java.util.Base64; +import java.util.Base64.Decoder; +import java.util.Base64.Encoder; + +public class Base64Utils { + /** + * Base64 Decoding. + * @param encodedString + * @return + */ + public static String base64Decoding(String encodedString) { + return base64Decoding(encodedString, "UTF-8"); + } + + public static String base64Decoding(String encodedString, String charset) { + Decoder decoder = Base64.getDecoder(); + byte[] decodedBytes1 = decoder.decode(encodedString.getBytes()); + String decodedString = null; + try { + decodedString = new String(decodedBytes1, charset); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return decodedString; + } + + /** + * Base64 encoding. + * @param encodedString + * @return + */ + public static String base64Encoding(String text) { + return base64Encoding(text, "UTF-8"); + } + + public static String base64Encoding(String text, String charset) { + String encodedString = null; + Encoder encoder = Base64.getEncoder(); + try { + byte[] targetByte = text.getBytes(charset); + encodedString = encoder.encodeToString(targetByte); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return encodedString; + } +} diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index e11bf82..b0ce6d4 100755 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -59,3 +59,6 @@ spring: max-request-size: 500MB object: object-mapper-pretty-print: true + +aes: + key: fb1755281b0ca6184a0ee644e6477ee7 diff --git a/src/main/resources/import.sql b/src/main/resources/import.sql index 1bd5b3e..391a099 100644 --- a/src/main/resources/import.sql +++ b/src/main/resources/import.sql @@ -24,24 +24,67 @@ VALUES 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, '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'); 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, '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'); 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, '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'); 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, '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'); 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, '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'); 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, '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'); 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, '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'); + +-- Insert into oss_type +INSERT INTO oss_type (oss_type_idx, oss_type_name, oss_type_desc) +VALUES + (1, 'NEXUS', 'init'); +INSERT INTO oss_type (oss_type_idx, oss_type_name, oss_type_desc) +VALUES + (2, 'WORKFLOWMANAGER', 'init'); + +-- Insert into oss +INSERT INTO oss (oss_idx, oss_type_idx, oss_name, oss_desc, oss_url, oss_username, oss_password) +VALUES + (1, 1, 'Sample NEXUS', 'Sample Description', 'http://sample.com', 'root', null); +INSERT INTO oss (oss_idx, oss_type_idx, oss_name, oss_desc, oss_url, oss_username, oss_password) +VALUES + (2, 2, 'Sample WorkflowManager', 'Sample Description', 'http://sample.com', null, null); + diff --git a/src/main/resources/static/favicon.ico b/src/main/resources/static/favicon.ico new file mode 100644 index 0000000..8e29c71 Binary files /dev/null and b/src/main/resources/static/favicon.ico differ diff --git a/src/main/resources/static/tabler/software-catalog-list-entity-workflow.html b/src/main/resources/static/tabler/software-catalog-list-entity-workflow.html index 47be9dc..0b122cb 100644 --- a/src/main/resources/static/tabler/software-catalog-list-entity-workflow.html +++ b/src/main/resources/static/tabler/software-catalog-list-entity-workflow.html @@ -1,3 +1,3 @@
  • {{workflowTitle}} - +
  • \ No newline at end of file diff --git a/src/main/resources/static/tabler/software-catalog-list-entity.html b/src/main/resources/static/tabler/software-catalog-list-entity.html index 49de7b4..548a4ba 100644 --- a/src/main/resources/static/tabler/software-catalog-list-entity.html +++ b/src/main/resources/static/tabler/software-catalog-list-entity.html @@ -7,7 +7,7 @@
    Górą ty
    -
    +
    {{title}}
    {{summary}} @@ -36,7 +36,7 @@
    -