diff options
author | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2019-08-02 15:58:22 +0200 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2019-08-02 16:01:25 +0200 |
commit | b4ae9b9a122ab0e9d625eef3fd3b426059fd4175 (patch) | |
tree | 480defb6c086b60ff39feb8774d980fe27feaea1 | |
parent | 6544cc5228dc104ebc254de04f9b728e1e5312fc (diff) |
Add helper to rewrite default-env.txt files
5 files changed, 166 insertions, 0 deletions
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/env/DefaultEnvRewriter.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/env/DefaultEnvRewriter.java new file mode 100644 index 00000000000..7a6c5d23bc1 --- /dev/null +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/env/DefaultEnvRewriter.java @@ -0,0 +1,101 @@ +// Copyright 2019 Oath Inc. 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.env; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +/** + * Rewrites default-env.txt files. + * + * @author bjorncs + */ +public class DefaultEnvRewriter { + + private final Map<String, Operation> operations = new TreeMap<>(); + private final Path defaultEnvFile; + + public DefaultEnvRewriter(Path defaultEnvFile) { + this.defaultEnvFile = defaultEnvFile; + } + + public DefaultEnvRewriter addOverride(String name, String value) { + return addOperation("override", name, value); + } + + public DefaultEnvRewriter addFallback(String name, String value) { + return addOperation("fallback", name, value); + } + + public DefaultEnvRewriter addUnset(String name) { + return addOperation("unset", name, null); + } + + private DefaultEnvRewriter addOperation(String action, String name, String value) { + if (operations.containsKey(name)) { + throw new IllegalArgumentException(String.format("Operation on variable '%s' already added", name)); + } + operations.put(name, new Operation(action, name, value)); + return this; + } + + public boolean converge() throws IOException { + List<String> defaultEnvLines = Files.readAllLines(defaultEnvFile); + List<String> newDefaultEnvLines = new ArrayList<>(); + Set<String> seenNames = new TreeSet<>(); + for (String line : defaultEnvLines) { + String[] items = line.split(" "); + if (items.length < 2) { + throw new IllegalArgumentException(String.format("Invalid line in file '%s': %s", defaultEnvFile, line)); + } + String name = items[1]; + if (!seenNames.contains(name)) { // implicitly removes duplicated variables + seenNames.add(name); + Operation operation = operations.get(name); + if (operation != null) { + newDefaultEnvLines.add(operation.toLine()); + } else { + newDefaultEnvLines.add(line); + } + } + } + for (var operation : operations.values()) { + if (!seenNames.contains(operation.name)) { + newDefaultEnvLines.add(operation.toLine()); + } + } + if (defaultEnvLines.equals(newDefaultEnvLines)) { + return false; + } else { + Files.write(defaultEnvFile, newDefaultEnvLines); + return true; + } + } + + private static class Operation { + final String action; + final String name; + final String value; + + Operation(String action, String name, String value) { + this.action = action; + this.name = name; + this.value = value; + } + + String toLine() { + if (action.equals("unset")) { + return "unset " + name; + } + return action + " " + name + " " + value; + } + } +} + + diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/env/package-info.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/env/package-info.java new file mode 100644 index 00000000000..cd42fbed899 --- /dev/null +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/env/package-info.java @@ -0,0 +1,8 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +/** + * @author bjorncs + */ +@ExportPackage +package com.yahoo.vespa.hosted.node.admin.task.util.env; + +import com.yahoo.osgi.annotation.ExportPackage;
\ No newline at end of file diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/env/DefaultEnvRewriterTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/env/DefaultEnvRewriterTest.java new file mode 100644 index 00000000000..2f24af37b71 --- /dev/null +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/env/DefaultEnvRewriterTest.java @@ -0,0 +1,48 @@ +// Copyright 2019 Oath Inc. 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.env; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * @author bjorncs + */ +public class DefaultEnvRewriterTest { + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + private static final Path EXAMPLE_FILE = Paths.get(DefaultEnvRewriterTest.class.getResource("/default-env-example.txt").getFile()); + private static final Path EXPECTED_RESULT_FILE = Paths.get(DefaultEnvRewriterTest.class.getResource("/default-env-rewritten.txt").getFile()); + + @Test + public void default_env_is_correctly_rewritten() throws IOException { + Path tempFile = temporaryFolder.newFile().toPath(); + Files.copy(EXAMPLE_FILE, tempFile, REPLACE_EXISTING); + + DefaultEnvRewriter rewriter = new DefaultEnvRewriter(tempFile); + rewriter.addOverride("VESPA_HOSTNAME", "my-new-hostname"); + rewriter.addFallback("VESPA_CONFIGSERVER", "new-fallback-configserver"); + rewriter.addOverride("VESPA_TLS_CONFIG_FILE", "/override/path/to/config.file"); + + boolean converged = rewriter.converge(); + + assertTrue(converged); + assertEquals(Files.readString(EXPECTED_RESULT_FILE), Files.readString(tempFile)); + + converged = rewriter.converge(); + assertFalse(converged); + assertEquals(Files.readString(EXPECTED_RESULT_FILE), Files.readString(tempFile)); + } +}
\ No newline at end of file diff --git a/node-admin/src/test/resources/default-env-example.txt b/node-admin/src/test/resources/default-env-example.txt new file mode 100644 index 00000000000..debae073271 --- /dev/null +++ b/node-admin/src/test/resources/default-env-example.txt @@ -0,0 +1,5 @@ +override VESPA_HOSTNAME myhostname +fallback VESPA_CONFIGSERVER fallback-configserver +fallback VESPA_TLS_CONFIG_FILE /fallback/path/to/config.file +unset VESPA_LEGACY_OPTION +fallback VESPA_LEGACY_OPTION duplicated-variable
\ No newline at end of file diff --git a/node-admin/src/test/resources/default-env-rewritten.txt b/node-admin/src/test/resources/default-env-rewritten.txt new file mode 100644 index 00000000000..94a91f4e793 --- /dev/null +++ b/node-admin/src/test/resources/default-env-rewritten.txt @@ -0,0 +1,4 @@ +override VESPA_HOSTNAME my-new-hostname +fallback VESPA_CONFIGSERVER new-fallback-configserver +override VESPA_TLS_CONFIG_FILE /override/path/to/config.file +unset VESPA_LEGACY_OPTION |