summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorValerij Fredriksen <valerijf@oath.com>2018-04-17 15:56:54 +0200
committerValerij Fredriksen <valerijf@oath.com>2018-04-17 15:56:54 +0200
commita5ba5cf1e6f816385a343b29f9959dbb6502c9b7 (patch)
treef88c8d6fc00b269be16d47faca7f52375b49af04
parentb9f6244b3cf0830ad423b41732e0279285bce7b8 (diff)
Write container data in hosted
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/containerdata/ConfigServerContainerData.java53
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/containerdata/ContainerData.java94
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/containerdata/MotdContainerData.java69
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/containerdata/PromptContainerData.java57
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImpl.java30
-rw-r--r--node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/containerdata/MotdContainerDataTest.java62
-rw-r--r--node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/containerdata/PromptContainerDataTest.java34
-rw-r--r--node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImplTest.java17
8 files changed, 2 insertions, 414 deletions
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/containerdata/ConfigServerContainerData.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/containerdata/ConfigServerContainerData.java
deleted file mode 100644
index 7357bded110..00000000000
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/containerdata/ConfigServerContainerData.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.yahoo.vespa.hosted.node.admin.containerdata;
-
-import com.yahoo.vespa.hosted.node.admin.component.Environment;
-
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-public class ConfigServerContainerData {
-
- public static final Path configServerAppDir = Paths.get("home/y/conf/configserver-app/");
-
- private final Environment environment;
- private final String configServerNodeHostName;
-
- public ConfigServerContainerData(Environment environment, String configServerNodeHostName) {
- this.environment = environment;
- this.configServerNodeHostName = configServerNodeHostName;
- }
-
- public void writeTo(ContainerData containerData) {
- containerData.addFile(getPath("configserver-config.xml"), createConfigServerConfigXml());
- containerData.addFile(getPath("node-repository-config.xml"), createNodeRepoConfigXml());
- }
-
- private Path getPath(String fileName) {
- return configServerAppDir.resolve(fileName);
- }
-
- private String createConfigServerConfigXml() {
- return "<config name=\"cloud.config.configserver\">\n" +
- " <system>" + environment.getSystem() + "</system>\n" +
- " <environment>" + environment.getEnvironment() + "</environment>\n" +
- " <region>" + environment.getRegion() + "</region>\n" +
- " <hostedVespa>true</hostedVespa>\n" +
- " <multitenant>true</multitenant>\n" +
- " <useVespaVersionInRequest>true</useVespaVersionInRequest>\n" +
- " <defaultFlavor>" + environment.getDefaultFlavor() + "</defaultFlavor>\n" +
- " <zookeeper>\n" +
- " <barrierTimeout>1200</barrierTimeout>\n" +
- " </zookeeper>\n" +
- " <serverId>" + configServerNodeHostName + "</serverId>\n" +
- " <nodeAdminInContainer>false</nodeAdminInContainer>\n" +
- "</config>\n";
- }
-
- // TODO: Avoid hardcoded Docker registry
- private String createNodeRepoConfigXml() {
- return "<config name=\"config.provisioning.node-repository\">\n" +
- " <dockerImage>docker.ouroath.com:4443/vespa/ci</dockerImage>\n" +
- "</config>\n";
- }
-
-}
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/containerdata/ContainerData.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/containerdata/ContainerData.java
deleted file mode 100644
index 1dc06d52e87..00000000000
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/containerdata/ContainerData.java
+++ /dev/null
@@ -1,94 +0,0 @@
-package com.yahoo.vespa.hosted.node.admin.containerdata;
-
-import com.yahoo.io.IOUtils;
-import com.yahoo.log.LogLevel;
-import com.yahoo.text.Utf8;
-import com.yahoo.vespa.hosted.dockerapi.ContainerName;
-import com.yahoo.vespa.hosted.node.admin.component.Environment;
-import com.yahoo.vespa.hosted.node.admin.task.util.file.IOExceptionUtil;
-
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Collections;
-import java.util.List;
-import java.util.logging.Logger;
-import java.util.stream.Collectors;
-
-/**
- * This class can be used for adding files that should be accessible in a container's file system after
- * the container has been started.
- * <p>
- * Files that are added will be copied into the destination path on the host.
- * The entry point for a Docker image will take care of copying
- * everything into it's right place (ATM only done for config server nodes)
- * Note: Creating a new instance of this will cleanup all old data in the destination path
- */
-public class ContainerData {
-
- private static final Logger log = Logger.getLogger(ContainerData.class.getName());
- public static final Path containerDataPath = Paths.get("/home/y/var/container-data");
-
- private final Path destinationPathOnHost;
-
- private ContainerData(Environment environment, ContainerName containerName) {
- this.destinationPathOnHost = environment.pathInHostFromPathInNode(containerName, ContainerData.containerDataPath);
- }
-
- public static ContainerData createClean(Environment environment, ContainerName containerName) {
- ContainerData containerData = new ContainerData(environment, containerName);
- IOExceptionUtil.uncheck(containerData::cleanup);
- return containerData;
- }
-
-
- public void addFile(Path relativePathInContainer, String data) {
- if (relativePathInContainer.isAbsolute())
- throw new IllegalArgumentException("Path must be relative to root: " + relativePathInContainer);
-
- Path path = destinationPathOnHost.resolve(relativePathInContainer);
- if (!path.toFile().exists()) {
- IOExceptionUtil.uncheck(() -> Files.createDirectories(path.getParent()));
- }
- IOUtils.writeFile(path.toFile(), Utf8.toBytes(data));
- }
-
- private void cleanup() throws IOException {
- log.log(LogLevel.INFO, "Cleaning up " + destinationPathOnHost.toAbsolutePath());
- recursiveDelete(destinationPathOnHost);
- }
-
-
- /* The below is copied from FileHelper in node-maintainer. Use methods in that class
- instead when we start depending on node-maintainer
- */
-
- /**
- * Similar to rm -rf file:
- * - It's not an error if file doesn't exist
- * - If file is a directory, it and all content is removed
- * - For symlinks: Only the symlink is removed, not what the symlink points to
- */
- private static void recursiveDelete(Path basePath) throws IOException {
- if (Files.isDirectory(basePath)) {
- for (Path path : listContentsOfDirectory(basePath)) {
- recursiveDelete(path);
- }
- }
-
- Files.deleteIfExists(basePath);
- }
-
- private static List<Path> listContentsOfDirectory(Path basePath) {
- try {
- return Files.list(basePath).collect(Collectors.toList());
- } catch (NoSuchFileException ignored) {
- return Collections.emptyList();
- } catch (IOException e) {
- throw new RuntimeException("Failed to list contents of directory " + basePath.toAbsolutePath(), e);
- }
- }
-
-}
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/containerdata/MotdContainerData.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/containerdata/MotdContainerData.java
deleted file mode 100644
index 63fd7f95054..00000000000
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/containerdata/MotdContainerData.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package com.yahoo.vespa.hosted.node.admin.containerdata;
-
-import com.yahoo.config.provision.ApplicationId;
-import com.yahoo.vespa.hosted.node.admin.NodeSpec;
-import com.yahoo.vespa.hosted.node.admin.component.Environment;
-import com.yahoo.vespa.hosted.node.admin.task.util.file.Template;
-
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.function.BiConsumer;
-
-/**
- * @author jvenstad
- */
-public class MotdContainerData {
-
- private static final Path motdPath = Paths.get("etc/profile.d/motd.sh");
- private static final String templateString = "#!/usr/bin/env bash\n" +
- "\n" +
- "function motd {\n" +
- "\n" +
- " local -r uptime=$(uptime | cut -f 3- -d ' ')\n" +
- "\n" +
- " local -r no_color='\\e[0m'\n" +
- " local -r green='\\e[0;32m'\n" +
- "## Use red zone name for main prod zones, yellow for other main zones and no colour for cd and dev zones.\n" +
- " local -r alert=#if($zone.getSystem() == \"main\")#if($zone.getEnvironment() == \"prod\")'\\e[0;91m'#else'\\e[0;33m'#end#else$green#end\n" +
- "\n" +
- "\n" +
- " echo -e \"\n" +
- "${green}Zone : ${alert}$zone.getSystem().toUpperCase() $zone.getEnvironment().toUpperCase() $zone.getRegion().toUpperCase()\n" +
- "${green}Node type : ${no_color}$type\n" +
- "${green}Node flavor : ${no_color}$flavor\n" +
- "${green}Host name : ${no_color}$(hostname)\n" +
- "${green}Uptime : ${no_color}$uptime\n" +
- "${green}Version : ${no_color}wanted = $wanted.orElse(\"unknown\"); installed = $installed.orElse(\"unknown\")\n" +
- "#if($owner.isPresent())\n" +
- "${green}Node state : ${no_color}$state\n" +
- "${green}Owner : ${no_color}$owner.get().serializedForm()\n" +
- "#end\n" +
- "\"\n" +
- "}\n" +
- "\n" +
- "# Display motd (gently)\n" +
- "[ ! -f ~/.hushlogin ] && motd\n";
-
- private final String renderedString;
-
- public MotdContainerData(NodeSpec node, Environment environment) {
- renderedString = Template.of(templateString)
- .set("zone", environment)
- .set("type", node.nodeType)
- .set("state", node.nodeState)
- .set("installed", node.vespaVersion)
- .set("wanted", node.wantedVespaVersion)
- .set("owner", node.owner.map(id -> ApplicationId.from(id.tenant, id.application, id.instance)))
- .set("flavor", node.nodeFlavor)
- .render();
- }
-
- public void writeTo(ContainerData containerData) {
- writeTo(containerData::addFile);
- }
-
- void writeTo(BiConsumer<Path, String> fileWriter) {
- fileWriter.accept(motdPath, renderedString);
- }
-
-}
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/containerdata/PromptContainerData.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/containerdata/PromptContainerData.java
deleted file mode 100644
index 8b6be32f649..00000000000
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/containerdata/PromptContainerData.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.yahoo.vespa.hosted.node.admin.containerdata;
-
-import com.yahoo.vespa.hosted.node.admin.component.Environment;
-import com.yahoo.vespa.hosted.node.admin.task.util.file.Template;
-
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.function.BiConsumer;
-
-public class PromptContainerData {
-
- private static final Path promptPath = Paths.get("etc/profile.d/prompt.sh");
- private static final String templateString = "# Make sure we get UTC/GMT all over\n" +
- "export TZ=UTC\n" +
- "\n" +
- "# Skip the rest for non-interactice shells\n" +
- "[ -z \"$PS1\" ] && return\n" +
- "\n" +
- "# Check the window size after each command and, if necessary,\n" +
- "# Update the values of LINES and COLUMNS.\n" +
- "shopt -s checkwinsize\n" +
- "\n" +
- "# Colors; see https://wiki.archlinux.org/index.php/Color_Bash_Prompt\n" +
- "color_off='\\[\\e[0m\\]' # Text Reset\n" +
- "color_bold='\\[\\e[1m\\]' # Bold text\n" +
- "\n" +
- "env_colour=#if($zone.getSystem() == \"main\")#if($zone.getEnvironment() == \"prod\")'\\[\\e[0;91m\\]'#else'\\[\\e[0;33m\\]'#end#else'\\[\\e[0;32m\\]'#end\n" +
- "\n" +
- "\n" +
- "PS1=\"${env_colour}$zone.getRegion().toUpperCase()${color_off} [\\u@${color_bold}\\h${color_off}:\\w]\\$ \"\n" +
- "\n" +
- "# Fix colors\n" +
- "if type dircolors > /dev/null 2>&1; then\n" +
- " eval $(dircolors -b)\n" +
- "fi\n" +
- "\n" +
- "# Make PS1 available in sub-shells\n" +
- "export PS1\n" +
- "\n";
-
- private final String renderedString;
-
- public PromptContainerData(Environment environment) {
- renderedString = Template.of(templateString)
- .set("zone", environment)
- .render();
- }
-
- public void writeTo(ContainerData containerData) {
- writeTo(containerData::addFile);
- }
-
- void writeTo(BiConsumer<Path, String> fileWriter) {
- fileWriter.accept(promptPath, renderedString);
- }
-
-}
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImpl.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImpl.java
index 26242961754..fbf727bb6de 100644
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImpl.java
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImpl.java
@@ -3,7 +3,6 @@ package com.yahoo.vespa.hosted.node.admin.nodeagent;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.yahoo.concurrent.ThreadFactoryFactory;
-import com.yahoo.config.provision.NodeType;
import com.yahoo.vespa.hosted.dockerapi.Container;
import com.yahoo.vespa.hosted.dockerapi.ContainerName;
import com.yahoo.vespa.hosted.dockerapi.ContainerResources;
@@ -16,12 +15,8 @@ import com.yahoo.vespa.hosted.dockerapi.metrics.DimensionMetrics;
import com.yahoo.vespa.hosted.dockerapi.metrics.Dimensions;
import com.yahoo.vespa.hosted.dockerapi.metrics.MetricReceiverWrapper;
import com.yahoo.vespa.hosted.node.admin.NodeSpec;
-import com.yahoo.vespa.hosted.node.admin.containerdata.ContainerData;
-import com.yahoo.vespa.hosted.node.admin.containerdata.MotdContainerData;
-import com.yahoo.vespa.hosted.node.admin.containerdata.PromptContainerData;
import com.yahoo.vespa.hosted.node.admin.docker.DockerOperations;
import com.yahoo.vespa.hosted.node.admin.maintenance.StorageMaintainer;
-import com.yahoo.vespa.hosted.node.admin.containerdata.ConfigServerContainerData;
import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeRepository;
import com.yahoo.vespa.hosted.node.admin.configserver.orchestrator.Orchestrator;
import com.yahoo.vespa.hosted.node.admin.configserver.orchestrator.OrchestratorException;
@@ -29,7 +24,6 @@ import com.yahoo.vespa.hosted.node.admin.component.Environment;
import com.yahoo.vespa.hosted.node.admin.util.PrefixLogger;
import com.yahoo.vespa.hosted.provision.Node;
-import java.io.UncheckedIOException;
import java.text.SimpleDateFormat;
import java.time.Clock;
import java.time.Duration;
@@ -277,7 +271,7 @@ public class NodeAgentImpl implements NodeAgent {
}
private void startContainer(NodeSpec node) {
- createContainerData(node);
+ createContainerData(environment, node);
dockerOperations.createContainer(containerName, node);
dockerOperations.startContainer(containerName, node);
lastCpuMetric = new CpuUsageReporter();
@@ -737,25 +731,5 @@ public class NodeAgentImpl implements NodeAgent {
orchestrator.suspend(hostname);
}
- private void createContainerData(NodeSpec node) {
- ContainerData containerData = ContainerData.createClean(environment, ContainerName.fromHostname(node.hostname));
-
- // ContainerData only works when root, which is the case only for HostAdmin so far -- config nodes are only used under HostAdmin.
- // If this fails, however, we should fail the start-up, as the config server won't work without it. Thus, no catch here.
- if (node.nodeType == NodeType.config) {
- logger.info("Creating files needed by config server");
- new ConfigServerContainerData(environment, node.hostname).writeTo(containerData);
- }
-
- // ContainerData only works when root, which is the case only for HostAdmin so far. Allow this to fail, since it's not critical.
- try {
- logger.info("Creating files for message of the day and the bash prompt");
- new MotdContainerData(node, environment).writeTo(containerData);
- new PromptContainerData(environment).writeTo(containerData);
- }
- catch (UncheckedIOException e) {
- logger.info("Failed creating files for message of the day and the bash prompt", e);
- }
- }
-
+ protected void createContainerData(Environment environment, NodeSpec node) { }
}
diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/containerdata/MotdContainerDataTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/containerdata/MotdContainerDataTest.java
deleted file mode 100644
index 61164c1e936..00000000000
--- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/containerdata/MotdContainerDataTest.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package com.yahoo.vespa.hosted.node.admin.containerdata;
-
-import com.yahoo.config.provision.NodeType;
-import com.yahoo.vespa.hosted.node.admin.NodeSpec;
-import com.yahoo.vespa.hosted.node.admin.component.Environment;
-import com.yahoo.vespa.hosted.node.admin.config.ConfigServerConfig;
-import com.yahoo.vespa.hosted.provision.Node;
-import org.junit.Test;
-
-import java.nio.file.Paths;
-import java.util.Collections;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-public class MotdContainerDataTest {
-
- @Test
- public void writesMotd() {
- MotdContainerData motdContainerData = new MotdContainerData(
- new NodeSpec.Builder()
- .nodeType(NodeType.tenant)
- .owner(new NodeSpec.Owner("tenant1", "application1", "default"))
- .nodeState(Node.State.dirty)
- .vespaVersion("7.0.0")
- .hostname("nope")
- .nodeFlavor("D-WAVE")
- .allowedToBeDown(false)
- .membership(new NodeSpec.Membership(null, null, null, 0, false))
- .minCpuCores(0)
- .minMainMemoryAvailableGb(0)
- .minDiskAvailableGb(0)
- .fastDisk(false)
- .ipAddresses(Collections.emptySet())
- .build(),
- new Environment.Builder()
- .configServerConfig(new ConfigServerConfig(new ConfigServerConfig.Builder()))
- .system("main")
- .environment("prod")
- .region("aws-us-east-1a")
- .defaultFlavor("cherry")
- .cloud("mycloud")
- .build());
-
- motdContainerData.writeTo((path, content) -> {
- assertEquals(path, Paths.get("etc/profile.d/motd.sh"));
-
- System.out.println(content);
-
- assertTrue(content.contains("tenant"));
- assertTrue(content.contains("D-WAVE"));
- assertTrue(content.contains("[0;91m"));
- assertTrue(content.contains("MAIN PROD AWS-US-EAST-1A"));
- assertTrue(content.contains("tenant1:application1:default"));
- assertTrue(content.contains("dirty"));
- assertTrue(content.contains("wanted = unknown"));
- assertTrue(content.contains("installed = 7.0.0"));
- });
-
- }
-
-}
diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/containerdata/PromptContainerDataTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/containerdata/PromptContainerDataTest.java
deleted file mode 100644
index 24ab35fc407..00000000000
--- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/containerdata/PromptContainerDataTest.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.yahoo.vespa.hosted.node.admin.containerdata;
-
-import com.yahoo.vespa.hosted.node.admin.component.Environment;
-import com.yahoo.vespa.hosted.node.admin.config.ConfigServerConfig;
-import org.junit.Test;
-
-import java.nio.file.Paths;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-public class PromptContainerDataTest {
-
- @Test
- public void writesPrompt() {
- PromptContainerData promptContainerData = new PromptContainerData(new Environment.Builder()
- .configServerConfig(new ConfigServerConfig(new ConfigServerConfig.Builder()))
- .system("main")
- .environment("prod")
- .region("aws-us-east-1a")
- .defaultFlavor("cherry")
- .cloud("mycloud")
- .build());
-
- promptContainerData.writeTo((path, content) -> {
- assertEquals(path, Paths.get("etc/profile.d/prompt.sh"));
-
- assertTrue(content.contains("[0;91m"));
- assertTrue(content.contains("AWS-US-EAST-1A"));
- });
-
- }
-
-}
diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImplTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImplTest.java
index db92e4c3838..aed2ca4d83e 100644
--- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImplTest.java
+++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImplTest.java
@@ -15,8 +15,6 @@ import com.yahoo.vespa.hosted.dockerapi.DockerImage;
import com.yahoo.vespa.hosted.dockerapi.metrics.MetricReceiverWrapper;
import com.yahoo.vespa.hosted.node.admin.NodeSpec;
import com.yahoo.vespa.hosted.node.admin.config.ConfigServerConfig;
-import com.yahoo.vespa.hosted.node.admin.containerdata.ConfigServerContainerData;
-import com.yahoo.vespa.hosted.node.admin.containerdata.ContainerData;
import com.yahoo.vespa.hosted.node.admin.docker.DockerOperations;
import com.yahoo.vespa.hosted.node.admin.maintenance.StorageMaintainer;
import com.yahoo.vespa.hosted.node.admin.maintenance.acl.AclMaintainer;
@@ -714,21 +712,6 @@ public class NodeAgentImplTest {
.withDockerImage(dockerImage)
.withVespaVersion(vespaVersion));
inOrder.verify(orchestrator).resume(hostName);
-
- // Files written in createContainerData()
- assertFileExists(containerName, tempDirectory, "node-repository-config.xml");
- assertFileExists(containerName, tempDirectory, "configserver-config.xml");
- }
-
- private void assertFileExists(ContainerName containerName, Path tempDirectory, String filename) {
- File file = tempDirectory
- .resolve(containerName.asString())
- .resolve(Paths.get("/").relativize(ContainerData.containerDataPath))
- .resolve(ConfigServerContainerData.configServerAppDir)
- .resolve(filename)
- .toAbsolutePath()
- .toFile();
- assertTrue("File " + file + " does not exist", file.exists());
}
private NodeAgentImpl makeNodeAgent(DockerImage dockerImage, boolean isRunning) {