diff options
6 files changed, 49 insertions, 4 deletions
diff --git a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/ContainerEngine.java b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/ContainerEngine.java index cd5f208e9e0..7a8d98f0e85 100644 --- a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/ContainerEngine.java +++ b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/ContainerEngine.java @@ -83,6 +83,8 @@ public interface ContainerEngine { boolean noManagedContainersRunning(String manager); + List<ContainerName> listManagedContainers(String manager); + boolean deleteUnusedDockerImages(List<DockerImage> excludes, Duration minImageAgeToDelete); /** diff --git a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerEngine.java b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerEngine.java index 33b301256b2..a45855764ed 100644 --- a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerEngine.java +++ b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerEngine.java @@ -286,7 +286,7 @@ public class DockerEngine implements ContainerEngine { response.getConfig().getHostName(), DockerImage.fromString(response.getConfig().getImage()), containerResourcesFromHostConfig(response.getHostConfig()), - new ContainerName(decode(response.getName())), + toContainerName(response.getName()), Container.State.valueOf(response.getState().getStatus().toUpperCase()), response.getState().getPid() )) @@ -309,8 +309,8 @@ public class DockerEngine implements ContainerEngine { return labels != null && manager.equals(labels.get(LABEL_NAME_MANAGEDBY)); } - private String decode(String encodedContainerName) { - return encodedContainerName.substring(FRAMEWORK_CONTAINER_PREFIX.length()); + private ContainerName toContainerName(String encodedContainerName) { + return new ContainerName(encodedContainerName.substring(FRAMEWORK_CONTAINER_PREFIX.length())); } @Override @@ -320,6 +320,14 @@ public class DockerEngine implements ContainerEngine { .noneMatch(container -> "running".equalsIgnoreCase(container.getState())); } + @Override + public List<ContainerName> listManagedContainers(String manager) { + return listAllContainers().stream() + .filter(container -> isManagedBy(container, manager)) + .map(container -> toContainerName(container.getNames()[0])) + .collect(Collectors.toList()); + } + List<com.github.dockerjava.api.model.Container> listAllContainers() { try { return dockerClient.listContainersCmd().withShowAll(true).exec(); diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/ContainerOperations.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/ContainerOperations.java index 8d62196d092..c8fd4c077ce 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/ContainerOperations.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/ContainerOperations.java @@ -3,6 +3,7 @@ package com.yahoo.vespa.hosted.node.admin.docker; import com.yahoo.config.provision.DockerImage; import com.yahoo.vespa.hosted.dockerapi.Container; +import com.yahoo.vespa.hosted.dockerapi.ContainerName; import com.yahoo.vespa.hosted.dockerapi.ContainerResources; import com.yahoo.vespa.hosted.dockerapi.ContainerStats; import com.yahoo.vespa.hosted.dockerapi.ProcessResult; @@ -14,6 +15,7 @@ import com.yahoo.vespa.hosted.node.admin.task.util.process.CommandResult; import java.time.Duration; import java.util.List; import java.util.Optional; +import java.util.Set; /** * @author hakonhall @@ -59,6 +61,9 @@ public interface ContainerOperations { boolean noManagedContainersRunning(); + /** Stops and removes all managed containers except the ones given in {@code containerNames} */ + boolean retainManagedContainers(Set<ContainerName> containerNames); + /** Deletes the local images that are currently not in use by any container and not recently used. */ boolean deleteUnusedContainerImages(List<DockerImage> excludes, Duration minImageAgeToDelete); diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/ContainerOperationsImpl.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/ContainerOperationsImpl.java index a6f2184179e..0a1cac73882 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/ContainerOperationsImpl.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/ContainerOperationsImpl.java @@ -8,6 +8,7 @@ import com.yahoo.config.provision.NodeType; import com.yahoo.config.provision.SystemName; import com.yahoo.vespa.hosted.dockerapi.Container; import com.yahoo.vespa.hosted.dockerapi.ContainerEngine; +import com.yahoo.vespa.hosted.dockerapi.ContainerName; import com.yahoo.vespa.hosted.dockerapi.ContainerResources; import com.yahoo.vespa.hosted.dockerapi.ContainerStats; import com.yahoo.vespa.hosted.dockerapi.ProcessResult; @@ -43,7 +44,7 @@ public class ContainerOperationsImpl implements ContainerOperations { private static final Logger logger = Logger.getLogger(ContainerOperationsImpl.class.getName()); - private static final String MANAGER_NAME = "node-admin"; + static final String MANAGER_NAME = "node-admin"; private static final InetAddress IPV6_NPT_PREFIX = InetAddresses.forString("fd00::"); private static final InetAddress IPV4_NPT_PREFIX = InetAddresses.forString("172.17.0.0"); @@ -325,6 +326,16 @@ public class ContainerOperationsImpl implements ContainerOperations { } @Override + public boolean retainManagedContainers(Set<ContainerName> containerNames) { + return containerEngine.listManagedContainers(MANAGER_NAME).stream() + .filter(containerName -> ! containerNames.contains(containerName)) + .peek(containerName -> { + containerEngine.stopContainer(containerName); + containerEngine.deleteContainer(containerName); + }).count() > 0; + } + + @Override public boolean deleteUnusedContainerImages(List<DockerImage> excludes, Duration minImageAgeToDelete) { return containerEngine.deleteUnusedDockerImages(excludes, minImageAgeToDelete); } diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/docker/ContainerOperationsImplTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/docker/ContainerOperationsImplTest.java index 4bbe7354ecb..b8eb9187265 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/docker/ContainerOperationsImplTest.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/docker/ContainerOperationsImplTest.java @@ -19,8 +19,10 @@ import org.mockito.InOrder; import java.net.InetAddress; import java.nio.file.FileSystem; +import java.util.List; import java.util.Optional; import java.util.OptionalLong; +import java.util.Set; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; @@ -123,4 +125,16 @@ public class ContainerOperationsImplTest { "0:0:0:0:0:0:0:1 hostname\n" + "127.0.0.1 hostname\n"); } + + @Test + public void retainContainersTest() { + when(containerEngine.listManagedContainers(ContainerOperationsImpl.MANAGER_NAME)) + .thenReturn(List.of(new ContainerName("cnt1"), new ContainerName("cnt2"), new ContainerName("cnt3"))); + dockerOperations.retainManagedContainers(Set.of(new ContainerName("cnt2"), new ContainerName("cnt4"))); + + verify(containerEngine).stopContainer(eq(new ContainerName("cnt1"))); + verify(containerEngine).deleteContainer(eq(new ContainerName("cnt1"))); + verify(containerEngine).stopContainer(eq(new ContainerName("cnt3"))); + verify(containerEngine).deleteContainer(eq(new ContainerName("cnt3"))); + } } diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/ContainerEngineMock.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/ContainerEngineMock.java index 121dca54e37..ef6564db2a5 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/ContainerEngineMock.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/ContainerEngineMock.java @@ -97,6 +97,11 @@ public class ContainerEngineMock implements ContainerEngine { return false; } + @Override + public List<ContainerName> listManagedContainers(String manager) { + return List.copyOf(containersByContainerName.keySet()); + } + public class StartContainerCommandMock implements CreateContainerCommand { private final DockerImage dockerImage; |