diff options
author | Jon Marius Venstad <jvenstad@yahoo-inc.com> | 2018-03-12 15:58:48 +0100 |
---|---|---|
committer | Jon Marius Venstad <jvenstad@yahoo-inc.com> | 2018-03-12 15:58:58 +0100 |
commit | 96d471be29e995b02a46ff51ec7c691ea6bab383 (patch) | |
tree | 9ac16d3d1477339cb30843bd2a853892ea6ea97b | |
parent | 6b1f2ba9ad2fca1e13b72efd134f42c4eebbc0c7 (diff) |
Rework Template(File) to allow String input
10 files changed, 146 insertions, 140 deletions
diff --git a/node-admin/src/main/application/templates/motd.sh.vm b/node-admin/src/main/application/templates/motd.sh.vm deleted file mode 100644 index 43087520368..00000000000 --- a/node-admin/src/main/application/templates/motd.sh.vm +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash - -function motd { - - local -r uptime=$(uptime | cut -f 3- -d ' ') - - local -r no_color='\e[0m' - local -r green='\e[0;32m' -## Use red zone name for main prod zones, yellow for other main zones and no colour for cd and dev zones. - local -r alert=#if($zone.getSystem() == "main")#if($zone.getEnvironment() == "prod")'\e[0;91m'#else'\e[0;33m'#end#else$green#end - - - echo -e " -${green}Zone : ${alert}$zone.getSystem().toUpperCase() $zone.getEnvironment().toUpperCase() $zone.getRegion().toUpperCase() -${green}Node type : ${no_color}$node.nodeType -${green}Host name : ${no_color}$(hostname) -${green}Uptime : ${no_color}$uptime -${green}Version : ${no_color}wanted=$node.wantedVespaVersion.orElse("unknown") installed=$node.vespaVersion.orElse("unknown") -#if($node.owner.isPresent()) -${green}Node state : ${no_color}$node.nodeState -${green}Owner : ${no_color}$node.owner.get().tenant $node.owner.get().application $node.owner.get().instance -#end -" -} - -# Display motd (gently) -[ ! -f ~/.hushlogin ] && motd diff --git a/node-admin/src/main/application/templates/prompt.sh.vm b/node-admin/src/main/application/templates/prompt.sh.vm deleted file mode 100644 index 73232907a32..00000000000 --- a/node-admin/src/main/application/templates/prompt.sh.vm +++ /dev/null @@ -1,27 +0,0 @@ -# Make sure we get UTC/GMT all over -export TZ=UTC - -# Skip the rest for non-interactice shells -[ -z "$PS1" ] && return - -# Check the window size after each command and, if necessary, -# Update the values of LINES and COLUMNS. -shopt -s checkwinsize - -# Colors; see https://wiki.archlinux.org/index.php/Color_Bash_Prompt -color_off='\[\e[0m\]' # Text Reset -color_bold='\[\e[1m\]' # Bold text - -env_colour=#if($zone.getSystem() == "main")#if($zone.getEnvironment() == "prod")'\e[0;91m'#else'\e[0;33m'#end#else$green#end - - -PS1="${env_colour}$zone.getRegion().toUpperCase()${color_off} [\u@${color_bold}\h${color_off}:\w]\$ " - -# Fix colors -if type dircolors > /dev/null 2>&1; then - eval $(dircolors -b) -fi - -# Make PS1 available in sub-shells -export PS1 - 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 index 566e8ca5c39..9c6a9adf1f1 100644 --- 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 @@ -3,7 +3,7 @@ package com.yahoo.vespa.hosted.node.admin.containerdata; import com.yahoo.config.provision.ApplicationId; import com.yahoo.vespa.hosted.node.admin.ContainerNodeSpec; import com.yahoo.vespa.hosted.node.admin.component.Environment; -import com.yahoo.vespa.hosted.node.admin.task.util.file.TemplateFile; +import com.yahoo.vespa.hosted.node.admin.task.util.file.Template; import com.yahoo.vespa.hosted.provision.Node.State; import java.nio.file.Path; @@ -11,21 +11,51 @@ import java.nio.file.Paths; import java.util.Optional; 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 Path templatePath = Paths.get("src/main/application/templates/motd.sh.vm"); + 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}$node.type()\n" + + "${green}Host name : ${no_color}$(hostname)\n" + + "${green}Uptime : ${no_color}$uptime\n" + + "${green}Version : ${no_color}wanted = $node.wanted().orElse(\"unknown\"); installed = $node.installed().orElse(\"unknown\")\n" + + "#if($node.owner().isPresent())\n" + + "${green}Node state : ${no_color}$node.state()\n" + + "${green}Owner : ${no_color}$node.owner().get().serializedForm()\n" + + "#end\n" + + "\"\n" + + "}\n" + + "\n" + + "# Display motd (gently)\n" + + "[ ! -f ~/.hushlogin ] && motd\n"; - private final TemplateFile template; + private final String renderedString; public MotdContainerData(ContainerNodeSpec nodeSpec, Environment environment) { - template = new TemplateFile(templatePath) + renderedString = Template.of(templateString) .set("zone", environment) .set("node", new Node(nodeSpec.nodeType, nodeSpec.nodeState, nodeSpec.vespaVersion, nodeSpec.wantedVespaVersion, - nodeSpec.owner)); + nodeSpec.owner)) + .render(); } public void writeTo(ContainerData containerData) { @@ -33,11 +63,12 @@ public class MotdContainerData { } void writeTo(BiConsumer<Path, String> fileWriter) { - System.out.println(template.render()); - fileWriter.accept(motdPath, template.render()); + fileWriter.accept(motdPath, renderedString); } - private static class Node { + + // Needs to be public for Velocity to use it. + public static class Node { private final String type; private final State state; 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 index 18fd12c0a47..ea9b2312b77 100644 --- 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 @@ -1,7 +1,7 @@ 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.TemplateFile; +import com.yahoo.vespa.hosted.node.admin.task.util.file.Template; import java.nio.file.Path; import java.nio.file.Paths; @@ -10,13 +10,40 @@ import java.util.function.BiConsumer; public class PromptContainerData { private static final Path promptPath = Paths.get("etc/profile.d/prompt.sh"); - private static final Path templatePath = Paths.get("src/main/application/templates/prompt.sh.vm"); - - private final TemplateFile template; + 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$green#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) { - template = new TemplateFile(templatePath) - .set("zone", environment); + renderedString = Template.of(templateString) + .set("zone", environment) + .render(); } public void writeTo(ContainerData containerData) { @@ -24,7 +51,7 @@ public class PromptContainerData { } void writeTo(BiConsumer<Path, String> fileWriter) { - fileWriter.accept(promptPath, template.render()); + fileWriter.accept(promptPath, renderedString); } } diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/Template.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/Template.java new file mode 100644 index 00000000000..6092cc1f038 --- /dev/null +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/Template.java @@ -0,0 +1,55 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.node.admin.task.util.file; + +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.app.VelocityEngine; + +import java.io.StringWriter; +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * Uses the Velocity engine to render a template, to and from both String and Path objects. + * + * @author hakonhall + * @author jvenstad + */ +public class Template { + + private final VelocityEngine velocityEngine = new VelocityEngine(); + private final VelocityContext velocityContext = new VelocityContext(); + private final String template; + + private Template(String template) { + this.template = template; + + velocityEngine.addProperty(Velocity.RUNTIME_LOG_LOGSYSTEM_CLASS, + "org.apache.velocity.runtime.log.NullLogSystem"); + velocityEngine.init(); + } + + public static Template at(Path templatePath) { + return of(IOExceptionUtil.uncheck(() -> new String(Files.readAllBytes(templatePath)))); + } + + public static Template of(String template) { + return new Template(template); + } + + public Template set(String name, Object value) { + velocityContext.put(name, value); + return this; + } + + public FileWriter getFileWriterTo(Path destinationPath) { + return new FileWriter(destinationPath, this::render); + } + + public String render() { + StringWriter writer = new StringWriter(); + velocityEngine.evaluate(velocityContext, writer, "Template", template); + return writer.toString(); + } + +} diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/TemplateFile.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/TemplateFile.java deleted file mode 100644 index ecde0aca9af..00000000000 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/TemplateFile.java +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.hosted.node.admin.task.util.file; - -import org.apache.velocity.Template; -import org.apache.velocity.VelocityContext; -import org.apache.velocity.app.Velocity; -import org.apache.velocity.app.VelocityEngine; - -import java.io.StringWriter; -import java.nio.file.Path; - -/** - * Make a file based on a Velocity template file. - * - * @author hakonhall - */ -public class TemplateFile { - private final Path templatePath; - private final VelocityEngine velocityEngine; - private final VelocityContext velocityContext = new VelocityContext(); - - public TemplateFile(Path templatePath) { - this.templatePath = templatePath; - velocityEngine = new VelocityEngine(); - velocityEngine.addProperty( - Velocity.RUNTIME_LOG_LOGSYSTEM_CLASS, - "org.apache.velocity.runtime.log.NullLogSystem"); - velocityEngine.addProperty(Velocity.FILE_RESOURCE_LOADER_PATH, templatePath.getParent().toString()); - velocityEngine.init(); - } - - public TemplateFile set(String name, Object value) { - velocityContext.put(name, value); - return this; - } - - public FileWriter getFileWriterTo(Path destinationPath) { - return new FileWriter(destinationPath, this::render); - } - - public String render() { - Template template = velocityEngine.getTemplate(templatePath.getFileName().toString(), "UTF-8"); - StringWriter writer = new StringWriter(); - template.merge(velocityContext, writer); - return writer.toString(); - } -} 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 index 9d2ef7980c5..5554f99299e 100644 --- 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 @@ -46,10 +46,10 @@ public class MotdContainerDataTest { assertTrue(content.contains("tenant")); assertTrue(content.contains("[0;91m")); assertTrue(content.contains("MAIN PROD AWS-US-EAST-1A")); - assertTrue(content.contains("tenant1 application1 default")); + assertTrue(content.contains("tenant1:application1:default")); assertTrue(content.contains("dirty")); - assertTrue(content.contains("wanted-unknown")); - assertTrue(content.contains("installed=7.0.0")); + 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 index 4d64af75453..7a1ba860ad1 100644 --- 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 @@ -1,9 +1,7 @@ package com.yahoo.vespa.hosted.node.admin.containerdata; -import com.yahoo.vespa.hosted.node.admin.ContainerNodeSpec; 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; 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 a97a11faab8..9d379babeca 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 @@ -175,6 +175,7 @@ public class NodeAgentImplTest { when(nodeRepository.getContainerNodeSpec(hostName)).thenReturn(Optional.of(nodeSpec)); when(pathResolver.getApplicationStoragePathForNodeAdmin()).thenReturn(Files.createTempDirectory("foo")); + when(pathResolver.getApplicationStoragePathForHost()).thenReturn(Files.createTempDirectory("bar")); when(dockerOperations.pullImageAsyncIfNeeded(eq(dockerImage))).thenReturn(false); when(storageMaintainer.getDiskUsageFor(eq(containerName))).thenReturn(Optional.of(201326592000L)); @@ -230,7 +231,7 @@ public class NodeAgentImplTest { } @Test - public void containerIsRestartedIfFlavorChanged() { + public void containerIsRestartedIfFlavorChanged() throws IOException { final long wantedRestartGeneration = 1; final long currentRestartGeneration = 1; ContainerNodeSpec.Builder specBuilder = nodeSpecBuilder @@ -253,6 +254,7 @@ public class NodeAgentImplTest { .thenReturn(Optional.of(thirdSpec)); when(dockerOperations.pullImageAsyncIfNeeded(any())).thenReturn(true); when(storageMaintainer.getDiskUsageFor(eq(containerName))).thenReturn(Optional.of(201326592000L)); + when(pathResolver.getApplicationStoragePathForHost()).thenReturn(Files.createTempDirectory("bar")); nodeAgent.converge(); nodeAgent.converge(); @@ -472,6 +474,7 @@ public class NodeAgentImplTest { when(nodeRepository.getContainerNodeSpec(eq(hostName))).thenReturn(Optional.of(nodeSpec)); when(pathResolver.getApplicationStoragePathForNodeAdmin()).thenReturn(Files.createTempDirectory("foo")); + when(pathResolver.getApplicationStoragePathForHost()).thenReturn(Files.createTempDirectory("bar")); when(storageMaintainer.getDiskUsageFor(eq(containerName))).thenReturn(Optional.of(201326592000L)); nodeAgent.tick(); @@ -583,6 +586,7 @@ public class NodeAgentImplTest { when(dockerOperations.getContainerStats(eq(containerName))) .thenReturn(Optional.of(stats1)) .thenReturn(Optional.of(stats2)); + when(pathResolver.getApplicationStoragePathForHost()).thenReturn(Files.createTempDirectory("bar")); nodeAgent.converge(); // Run the converge loop once to initialize lastNodeSpec nodeAgent.updateContainerNodeMetrics(); // Update metrics once to init and lastCpuMetric diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/file/TemplateFileTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/file/TemplateTest.java index b1d88fdaaee..7aa672e9e80 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/file/TemplateFileTest.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/file/TemplateTest.java @@ -2,40 +2,31 @@ package com.yahoo.vespa.hosted.node.admin.task.util.file; +import com.google.common.jimfs.Jimfs; import com.yahoo.vespa.hosted.node.admin.component.TaskContext; -import org.junit.Rule; +import com.yahoo.vespa.test.file.TestFileSystem; import org.junit.Test; -import org.junit.rules.TemporaryFolder; import java.io.IOException; +import java.nio.file.FileSystem; import java.nio.file.Path; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; -/** - * WARNING: Velocity does not honor an alternative FileSystem like JimFS. - */ -public class TemplateFileTest { - @Rule - public TemporaryFolder folder = new TemporaryFolder(); - - private void writeFile(Path path, String content) { - UnixPath unixPath = new UnixPath(path); - unixPath.createParents(); - unixPath.writeUtf8File(content); - } +public class TemplateTest { @Test public void basic() throws IOException { + FileSystem fileSystem = TestFileSystem.create(); + Path templatePath = fileSystem.getPath("/example.vm"); String templateContent = "a $x, $y b"; - Path templatePath = folder.newFile("example.vm").toPath(); - writeFile(templatePath, templateContent); + new UnixPath(templatePath).writeUtf8File(templateContent); - Path toPath = folder.newFile().toPath(); + Path toPath = fileSystem.getPath("/example"); TaskContext taskContext = mock(TaskContext.class); - boolean converged = new TemplateFile(templatePath) + boolean converged = Template.at(templatePath) .set("x", "foo") .set("y", "bar") .getFileWriterTo(toPath) @@ -46,4 +37,5 @@ public class TemplateFileTest { String actualContent = new UnixPath(toPath).readUtf8File(); assertEquals("a foo, bar b", actualContent); } + }
\ No newline at end of file |