diff options
author | Valerij Fredriksen <valerijf@oath.com> | 2018-04-17 15:56:54 +0200 |
---|---|---|
committer | Valerij Fredriksen <valerijf@oath.com> | 2018-04-17 15:56:54 +0200 |
commit | a5ba5cf1e6f816385a343b29f9959dbb6502c9b7 (patch) | |
tree | f88c8d6fc00b269be16d47faca7f52375b49af04 | |
parent | b9f6244b3cf0830ad423b41732e0279285bce7b8 (diff) |
Write container data in hosted
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) { |