From 2488de4aaddb516832a49e15bcfb84a844656122 Mon Sep 17 00:00:00 2001 From: bjkim Date: Mon, 13 Oct 2025 16:06:54 +0900 Subject: [PATCH] [REMOVE] Remove DockerPullPushService, DockerRegistryController, and DockerRegistryService due to deprecation --- .../controllers/DockerRegistryController.java | 59 -------- .../service/DockerPullPushService.java | 133 ------------------ .../service/DockerRegistryService.java | 73 ---------- 3 files changed, 265 deletions(-) delete mode 100644 src/main/java/kr/re/etri/autoflow/controllers/DockerRegistryController.java delete mode 100644 src/main/java/kr/re/etri/autoflow/service/DockerPullPushService.java delete mode 100644 src/main/java/kr/re/etri/autoflow/service/DockerRegistryService.java diff --git a/src/main/java/kr/re/etri/autoflow/controllers/DockerRegistryController.java b/src/main/java/kr/re/etri/autoflow/controllers/DockerRegistryController.java deleted file mode 100644 index afcc451..0000000 --- a/src/main/java/kr/re/etri/autoflow/controllers/DockerRegistryController.java +++ /dev/null @@ -1,59 +0,0 @@ -package kr.re.etri.autoflow.controllers; - -import com.fasterxml.jackson.databind.JsonNode; -import io.swagger.v3.oas.annotations.Operation; -import kr.re.etri.autoflow.entity.PullRequest; -import kr.re.etri.autoflow.payload.request.TagWithDigest; -import kr.re.etri.autoflow.service.DockerPullPushService; -import kr.re.etri.autoflow.service.DockerRegistryService; -import lombok.RequiredArgsConstructor; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import reactor.core.publisher.Mono; - -import java.util.List; -import java.util.Map; - -@RestController -@RequestMapping("/api/docker") -@RequiredArgsConstructor -public class DockerRegistryController { - - private final DockerRegistryService dockerRegistryService; - private final DockerPullPushService dockerPullPushService; - - @GetMapping("/repositories") - @Operation(summary = "모든 리포지토리 조회") - public Mono> listRepositories() { - return dockerRegistryService.listRepositories() - .map(ResponseEntity::ok); - } - - @GetMapping("/repositories/search") - @Operation(summary = "리포지토리 검색 (키워드 + 페이지네이션)") - public Mono> searchRepositories( - @RequestParam(required = false) String keyword, - @RequestParam(defaultValue = "0") int page, - @RequestParam(defaultValue = "10") int size) { - return dockerRegistryService.searchRepositories(keyword, page, size) - .map(ResponseEntity::ok); - } - - @GetMapping("/repositories/{repo}/tags") - @Operation(summary = "특정 리포지토리의 태그 조회") - public Mono> listTags(@PathVariable String repo) { - return dockerRegistryService.listTags(repo) - .map(ResponseEntity::ok); - } - - @Operation(summary = "이미지 pull (manifest + config + blobs) 후 로컬에 저장") - @PostMapping("/pull") - public Mono>> pullImage(@RequestBody PullRequest req) { - return dockerPullPushService.pullImage(req.getRegistry(), req.getRepository(), req.getTag(), req.getUsername(), req.getPassword()) - .map(result -> ResponseEntity.ok(Map.of( - "savedFiles", result, - "path", dockerPullPushService.getDownloadBaseDir() - ))); - } -} diff --git a/src/main/java/kr/re/etri/autoflow/service/DockerPullPushService.java b/src/main/java/kr/re/etri/autoflow/service/DockerPullPushService.java deleted file mode 100644 index b73e920..0000000 --- a/src/main/java/kr/re/etri/autoflow/service/DockerPullPushService.java +++ /dev/null @@ -1,133 +0,0 @@ -package kr.re.etri.autoflow.service; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.http.client.reactive.ReactorClientHttpConnector; -import org.springframework.stereotype.Service; -import org.springframework.util.FileSystemUtils; -import org.springframework.web.reactive.function.BodyExtractors; -import org.springframework.web.reactive.function.client.ClientResponse; -import org.springframework.web.reactive.function.client.WebClient; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.netty.http.client.HttpClient; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; - -@Service -@RequiredArgsConstructor -public class DockerPullPushService { - private final ObjectMapper objectMapper = new ObjectMapper(); - - @Value("${docker-registry.download-dir:./downloads}") - private String downloadBaseDir; - - public String getDownloadBaseDir() { - return downloadBaseDir; - } - - public Mono> pullImage(String registry, String repository, String tag, String username, String password) { - if (registry == null || registry.isBlank()) { - registry = "localhost:5000"; // 기본값 - } - - String base = registry.startsWith("http") ? registry : "http://" + registry; - WebClient.Builder builder = WebClient.builder() - .clientConnector(new ReactorClientHttpConnector(HttpClient.create().responseTimeout(Duration.ofSeconds(60)))) - .baseUrl(base); - - if (username != null && !username.isBlank()) { - builder.defaultHeaders(h -> h.setBasicAuth(username, password == null ? "" : password)); - } - - WebClient client = builder.build(); - - Path dstDir = Path.of(downloadBaseDir, repository.replace('/', '-'), tag); - try { - if (Files.exists(dstDir)) { - FileSystemUtils.deleteRecursively(dstDir); - } - Files.createDirectories(dstDir); - } catch (IOException e) { - return Mono.error(e); - } - - // 1) manifest - String manifestAccept = "application/vnd.docker.distribution.manifest.v2+json"; - return client.get() - .uri(uriBuilder -> uriBuilder.path("/v2/{repo}/manifests/{tag}").build(repository, tag)) - .header(HttpHeaders.ACCEPT, manifestAccept) - .accept(MediaType.valueOf("application/vnd.docker.distribution.manifest.v2+json")) - .exchangeToMono(response -> saveResponseBodyToFile(response, dstDir.resolve("image.manifest"))) - .flatMap(manifestPath -> { - try { - byte[] b = Files.readAllBytes(manifestPath); - JsonNode manifest = objectMapper.readTree(b); - List saved = new ArrayList<>(); - saved.add(manifestPath.toString()); - - // 2) config (config is a blob) - JsonNode config = manifest.get("config"); - Mono configMono = Mono.empty(); - if (config != null && config.has("digest")) { - String configDigest = config.get("digest").asText(); - Path configPath = dstDir.resolve(configDigest); - configMono = client.get() - .uri(uriBuilder -> uriBuilder.path("/v2/{repo}/blobs/{digest}").build(repository, configDigest)) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_OCTET_STREAM_VALUE) - .exchangeToMono(response -> saveResponseBodyToFile(response, configPath).then()) - .doOnSuccess(v -> saved.add(configPath.toString())); - } - - // 3) layers - JsonNode layers = manifest.get("layers"); - Flux layersFlux = Flux.empty(); - if (layers != null && layers.isArray()) { - List> monos = new ArrayList<>(); - for (JsonNode layer : layers) { - String digest = layer.get("digest").asText(); - Path layerPath = dstDir.resolve(digest); - Mono m = client.get() - .uri(uriBuilder -> uriBuilder.path("/v2/{repo}/blobs/{digest}").build(repository, digest)) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_OCTET_STREAM_VALUE) - .exchangeToMono(response -> saveResponseBodyToFile(response, layerPath).then()) - .doOnSuccess(v -> saved.add(layerPath.toString())); - monos.add(m); - } - layersFlux = Flux.concat(monos); - } - - return configMono.thenMany(layersFlux).then(Mono.just(saved)); - } catch (IOException e) { - return Mono.error(e); - } - }); - } - - private Mono saveResponseBodyToFile(ClientResponse response, Path path) { - if (response.statusCode().is2xxSuccessful()) { - return response.body(BodyExtractors.toDataBuffers()) - .map(dataBuffer -> { - try (var in = dataBuffer.asInputStream(true)) { - Files.copy(in, path); - } catch (IOException e) { - throw new RuntimeException(e); - } - return path; - }) - .next() - .onErrorMap(t -> t); - } else { - return response.createException().flatMap(Mono::error); - } - } -} diff --git a/src/main/java/kr/re/etri/autoflow/service/DockerRegistryService.java b/src/main/java/kr/re/etri/autoflow/service/DockerRegistryService.java deleted file mode 100644 index d7bad6f..0000000 --- a/src/main/java/kr/re/etri/autoflow/service/DockerRegistryService.java +++ /dev/null @@ -1,73 +0,0 @@ -package kr.re.etri.autoflow.service; - -import com.fasterxml.jackson.databind.JsonNode; -import kr.re.etri.autoflow.payload.request.TagWithDigest; -import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpHeaders; -import org.springframework.stereotype.Service; -import org.springframework.web.reactive.function.client.WebClient; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - -@Service -@RequiredArgsConstructor -public class DockerRegistryService { - - private final WebClient.Builder webClientBuilder; - private static final String REGISTRY_URL = "http://192.168.10.135:5000"; - - public Mono listRepositories() { - return webClientBuilder.build() - .get() - .uri(REGISTRY_URL + "/v2/_catalog") - .retrieve() - .bodyToMono(JsonNode.class); - } - - // 검색 + 페이지네이션 - public Mono> searchRepositories(String keyword, int page, int size) { - return webClientBuilder.build() - .get() - .uri(REGISTRY_URL + "/v2/_catalog") - .retrieve() - .bodyToMono(JsonNode.class) - .map(json -> { - JsonNode repositoriesNode = json.get("repositories"); - if (repositoriesNode == null || !repositoriesNode.isArray()) { - return List.of(); - } - - List allRepos = StreamSupport.stream(repositoriesNode.spliterator(), false) - .map(JsonNode::asText) - .collect(Collectors.toList()); - - // 키워드 필터링 - if (keyword != null && !keyword.isBlank()) { - allRepos = allRepos.stream() - .filter(name -> name.contains(keyword)) - .collect(Collectors.toList()); - } - - // 페이지네이션 - int fromIndex = Math.min(page * size, allRepos.size()); - int toIndex = Math.min(fromIndex + size, allRepos.size()); - return allRepos.subList(fromIndex, toIndex); - }); - } - - - public Mono listTags(String repository) { - return webClientBuilder.build() - .get() - .uri(REGISTRY_URL + "/v2/" + repository + "/tags/list") - .retrieve() - .bodyToMono(JsonNode.class); - } -}