diff options
Diffstat (limited to 'docker-api')
5 files changed, 80 insertions, 29 deletions
diff --git a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/ContainerLite.java b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/ContainerLite.java new file mode 100644 index 00000000000..51d815a412f --- /dev/null +++ b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/ContainerLite.java @@ -0,0 +1,61 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.dockerapi; + +import java.util.Objects; + +/** + * Information about a container as a result of listing containers (aka "docker ps"). + * + * @author hakonhall + */ +public class ContainerLite { + private final String id; + private final String imageId; + // state is one of: "running" + private final String state; + + public ContainerLite(String id, String imageId, String state) { + this.id = id; + this.imageId = imageId; + this.state = state; + } + + /** Of format: "94a66101b8dfbf485f4f77a448b079684ea704927aa39e31d824de708cfa3373" */ + public String id() { + return id; + } + + /** Of format: "sha256:7f3abbbbb17d135840a1f185ac291c87f7b90651e65b6021e820abaf397dd282" */ + public String imageId() { + return imageId; + } + + /** Whether the container is running. */ + public boolean isRunning() { + return "running".equals(state); + } + + @Override + public String toString() { + return "ContainerLite{" + + "id='" + id + '\'' + + ", imageId='" + imageId + '\'' + + ", state='" + state + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ContainerLite that = (ContainerLite) o; + return Objects.equals(id, that.id) && + Objects.equals(imageId, that.imageId) && + Objects.equals(state, that.state); + } + + @Override + public int hashCode() { + return Objects.hash(id, imageId, state); + } +} diff --git a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/Docker.java b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/Docker.java index 8344830e229..1729c4843ef 100644 --- a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/Docker.java +++ b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/Docker.java @@ -81,6 +81,9 @@ public interface Docker { */ boolean pullImageAsyncIfNeeded(DockerImage image); + /** List all containers, including those not running. */ + List<ContainerLite> listAllContainers(); + /** * Deletes the local images that are currently not in use by any container and not recently used. */ diff --git a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerImageGarbageCollector.java b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerImageGarbageCollector.java index 4eeb00c7685..242332ebd54 100644 --- a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerImageGarbageCollector.java +++ b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerImageGarbageCollector.java @@ -73,7 +73,7 @@ class DockerImageGarbageCollector { */ boolean deleteUnusedDockerImages(List<DockerImage> excludes, Duration minImageAgeToDelete) { List<Image> images = docker.listAllImages(); - List<Container> containers = docker.listAllContainers(); + List<ContainerLite> containers = docker.listAllContainers(); Map<String, Image> imageByImageId = images.stream().collect(Collectors.toMap(Image::getId, Function.identity())); @@ -138,14 +138,14 @@ class DockerImageGarbageCollector { .count() > 0; } - private Set<String> getRecentlyUsedImageIds(List<Image> images, List<Container> containers, Duration minImageAgeToDelete) { + private Set<String> getRecentlyUsedImageIds(List<Image> images, List<ContainerLite> containers, Duration minImageAgeToDelete) { final Instant now = clock.instant(); // Add any already downloaded image to the list once images.forEach(image -> lastTimeUsedByImageId.putIfAbsent(image.getId(), now)); // Update last used time for all current containers - containers.forEach(container -> lastTimeUsedByImageId.put(container.getImageId(), now)); + containers.forEach(container -> lastTimeUsedByImageId.put(container.imageId(), now)); // Return list of images that have been used within minImageAgeToDelete return lastTimeUsedByImageId.entrySet().stream() diff --git a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerImpl.java b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerImpl.java index 9299cedaf21..683c8a98788 100644 --- a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerImpl.java +++ b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerImpl.java @@ -42,6 +42,7 @@ import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import java.util.stream.Collectors; import java.util.stream.Stream; public class DockerImpl implements Docker { @@ -296,9 +297,15 @@ public class DockerImpl implements Docker { return encodedContainerName.substring(FRAMEWORK_CONTAINER_PREFIX.length()); } - List<com.github.dockerjava.api.model.Container> listAllContainers() { + @Override + public List<ContainerLite> listAllContainers() { try { - return dockerClient.listContainersCmd().withShowAll(true).exec(); + return dockerClient.listContainersCmd().withShowAll(true).exec().stream() + .map(c -> new ContainerLite( + c.getId(), // Example: "94a66101b8dfbf485f4f77a448b079684ea704927aa39e31d824de708cfa3373" + c.getImageId(), // Example: "sha256:7f3abbbbb17d135840a1f185ac291c87f7b90651e65b6021e820abaf397dd282" + c.getState())) // Example: "running" + .collect(Collectors.toList()); } catch (RuntimeException e) { numberOfDockerDaemonFails.add(); throw new DockerException("Failed to list all containers", e); diff --git a/docker-api/src/test/java/com/yahoo/vespa/hosted/dockerapi/DockerImageGarbageCollectionTest.java b/docker-api/src/test/java/com/yahoo/vespa/hosted/dockerapi/DockerImageGarbageCollectionTest.java index 412b8301e4c..520f8a74d58 100644 --- a/docker-api/src/test/java/com/yahoo/vespa/hosted/dockerapi/DockerImageGarbageCollectionTest.java +++ b/docker-api/src/test/java/com/yahoo/vespa/hosted/dockerapi/DockerImageGarbageCollectionTest.java @@ -50,7 +50,7 @@ public class DockerImageGarbageCollectionTest { @Test public void singleImageWithContainerIsUsed() { gcTester.withExistingImages(ImageBuilder.forId("image-1")) - .andExistingContainers(ContainerBuilder.forId("container-1").withImageId("image-1")) + .andExistingContainers(new ContainerLite("container-1", "image-1", "running")) .expectDeletedImages(); } @@ -77,7 +77,7 @@ public class DockerImageGarbageCollectionTest { ImageBuilder.forId("parent-image"), ImageBuilder.forId("image-1").withParentId("parent-image").withTags("latest"), ImageBuilder.forId("image-2").withParentId("parent-image").withTags("1.24")) - .andExistingContainers(ContainerBuilder.forId("vespa-node-1").withImageId("image-1")) + .andExistingContainers(new ContainerLite("vespa-node-1", "image-1", "running")) .expectDeletedImages("1.24"); // Deleting the only tag will delete the image } @@ -173,10 +173,8 @@ public class DockerImageGarbageCollectionTest { return this; } - private ImageGcTester andExistingContainers(ContainerBuilder... containers) { - when(docker.listAllContainers()).thenReturn(Arrays.stream(containers) - .map(ContainerBuilder::toContainer) - .collect(Collectors.toList())); + private ImageGcTester andExistingContainers(ContainerLite... containers) { + when(docker.listAllContainers()).thenReturn(List.of(containers)); return this; } @@ -257,22 +255,4 @@ public class DockerImageGarbageCollectionTest { private ImageBuilder withTags(String... tags) { this.repoTags = tags; return this; } private Image toImage() { return createFrom(Image.class, this); } } - - // Workaround for Container class that can't be instantiated directly in Java (instantiate via Jackson instead). - private static class ContainerBuilder { - // Json property names must match exactly the property names in the Container class. - @JsonProperty("Id") - private final String id; - - @JsonProperty("ImageID") - private String imageId; - - private ContainerBuilder(String id) { this.id = id; } - private static ContainerBuilder forId(final String id) { return new ContainerBuilder(id); } - private ContainerBuilder withImageId(String imageId) { this.imageId = imageId; return this; } - - private com.github.dockerjava.api.model.Container toContainer() { - return createFrom(com.github.dockerjava.api.model.Container.class, this); - } - } } |