diff options
6 files changed, 47 insertions, 4 deletions
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..4e7ef5a1ff6 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,9 +81,8 @@ public interface Docker { */ boolean pullImageAsyncIfNeeded(DockerImage image); - /** - * Deletes the local images that are currently not in use by any container and not recently used. - */ + boolean noManagedContainersRunning(String manager); + boolean deleteUnusedDockerImages(List<DockerImage> excludes, Duration minImageAgeToDelete); /** 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..8cdb0bee7c2 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 @@ -296,6 +296,13 @@ public class DockerImpl implements Docker { return encodedContainerName.substring(FRAMEWORK_CONTAINER_PREFIX.length()); } + @Override + public boolean noManagedContainersRunning(String manager) { + return listAllContainers().stream() + .filter(container -> isManagedBy(container, manager)) + .noneMatch(container -> "running".equalsIgnoreCase(container.getState())); + } + 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/DockerOperations.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/DockerOperations.java index 6b3c09e812a..2a40428cad2 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/DockerOperations.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/DockerOperations.java @@ -9,6 +9,8 @@ import com.yahoo.vespa.hosted.dockerapi.ProcessResult; import com.yahoo.vespa.hosted.node.admin.nodeagent.ContainerData; import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContext; +import java.time.Duration; +import java.util.List; import java.util.Optional; public interface DockerOperations { @@ -48,4 +50,9 @@ public interface DockerOperations { void stopServices(NodeAgentContext context); Optional<ContainerStats> getContainerStats(NodeAgentContext context); + + boolean noManagedContainersRunning(); + + /** Deletes the local images that are currently not in use by any container and not recently used. */ + boolean deleteUnusedDockerImages(List<DockerImage> excludes, Duration minImageAgeToDelete); } diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/DockerOperationsImpl.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/DockerOperationsImpl.java index 2f5d6ae60d8..954ba25895a 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/DockerOperationsImpl.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/DockerOperationsImpl.java @@ -15,12 +15,14 @@ import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeMembers import com.yahoo.vespa.hosted.node.admin.nodeagent.ContainerData; import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContext; import com.yahoo.vespa.hosted.node.admin.task.util.network.IPAddresses; +import com.yahoo.vespa.hosted.node.admin.task.util.network.IPAddressesImpl; import java.io.IOException; import java.net.Inet6Address; import java.net.InetAddress; import java.nio.file.Path; import java.nio.file.Paths; +import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -47,6 +49,10 @@ public class DockerOperationsImpl implements DockerOperations { private final ProcessExecuter processExecuter; private final IPAddresses ipAddresses; + public DockerOperationsImpl(Docker docker) { + this(docker, new ProcessExecuter(), new IPAddressesImpl()); + } + public DockerOperationsImpl(Docker docker, ProcessExecuter processExecuter, IPAddresses ipAddresses) { this.docker = docker; this.processExecuter = processExecuter; @@ -323,6 +329,16 @@ public class DockerOperationsImpl implements DockerOperations { command.withSharedVolume(Paths.get("/var/zpe"), context.pathInNodeUnderVespaHome("var/zpe")); } + @Override + public boolean noManagedContainersRunning() { + return docker.noManagedContainersRunning(MANAGER_NAME); + } + + @Override + public boolean deleteUnusedDockerImages(List<DockerImage> excludes, Duration minImageAgeToDelete) { + return docker.deleteUnusedDockerImages(excludes, minImageAgeToDelete); + } + /** Returns whether given nodeType is a Docker host for infrastructure nodes */ private static boolean isInfrastructureHost(NodeType nodeType) { return nodeType == NodeType.config || diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/systemd/SystemCtl.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/systemd/SystemCtl.java index 77510f7b6ef..17d8126a5c9 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/systemd/SystemCtl.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/systemd/SystemCtl.java @@ -2,6 +2,7 @@ package com.yahoo.vespa.hosted.node.admin.task.util.systemd; import com.yahoo.vespa.hosted.node.admin.component.TaskContext; +import com.yahoo.vespa.hosted.node.admin.task.util.process.CommandResult; import com.yahoo.vespa.hosted.node.admin.task.util.process.Terminal; import java.util.Objects; @@ -58,7 +59,7 @@ public class SystemCtl { public boolean serviceExists(TaskContext context, String unit) { return terminal.newCommandLine(context) - .add("systemctl").add("list-unit-files").add(unit + ".service").executeSilently() + .add("systemctl", "list-unit-files", unit + ".service").executeSilently() .mapOutput(output -> { // Last line of the form: "1 unit files listed." Matcher matcher = UNIT_FILES_LISTED_PATTERN.matcher(output); @@ -70,6 +71,15 @@ public class SystemCtl { }); } + /** Returns true if the unit exists and is active (i.e. running). unit is e.g. "docker". */ + public boolean isActive(TaskContext context, String unit) { + return terminal.newCommandLine(context) + .add("systemctl", "--quiet", "is-active", unit + ".service") + .ignoreExitCode() + .executeSilently() + .map(CommandResult::getExitCode) == 0; + } + public class SystemCtlEnable extends SystemCtlCommand { private SystemCtlEnable(String unit) { super("enable", unit); diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/DockerMock.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/DockerMock.java index 31e64dc886f..e2ad9e3de97 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/DockerMock.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/DockerMock.java @@ -91,6 +91,10 @@ public class DockerMock implements Docker { return new ProcessResult(0, null, ""); } + @Override + public boolean noManagedContainersRunning(String manager) { + return false; + } public class StartContainerCommandMock implements CreateContainerCommand { |