aboutsummaryrefslogtreecommitdiffstats
path: root/node-admin/src/main/java
diff options
context:
space:
mode:
authorHåkon Hallingstad <hakon@oath.com>2018-02-08 01:45:37 +0100
committerHåkon Hallingstad <hakon@oath.com>2018-02-08 01:45:37 +0100
commit03a2d26265433a2f055a3bb2f470ba5400df7c44 (patch)
treec1edb2458a2a0bf893a79b6864cebb211cce523d /node-admin/src/main/java
parent74b3ef7b54e8ac8b0473c016185f1476a3fd3db4 (diff)
Add file editor
Diffstat (limited to 'node-admin/src/main/java')
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/Editor.java98
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/EditorFactory.java13
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/LineEdit.java31
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/LineEditor.java21
4 files changed, 163 insertions, 0 deletions
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/Editor.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/Editor.java
new file mode 100644
index 00000000000..cfd7756ad0e
--- /dev/null
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/Editor.java
@@ -0,0 +1,98 @@
+// 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 com.yahoo.vespa.hosted.node.admin.component.TaskContext;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+
+import static com.yahoo.vespa.hosted.node.admin.task.util.file.IOExceptionUtil.uncheck;
+
+/**
+ * An editor meant to edit small line-based files like /etc/fstab.
+ *
+ * @author hakonhall
+ */
+public class Editor {
+ private static final Logger logger = Logger.getLogger(Editor.class.getName());
+ private static final Charset ENCODING = StandardCharsets.UTF_8;
+
+ private static int maxLength = 300;
+
+ private final Path path;
+ private final LineEditor editor;
+
+ public Editor(Path path, LineEditor editor) {
+ this.path = path;
+ this.editor = editor;
+ }
+
+ /**
+ * Read the file which must be encoded in UTF-8, use the LineEditor to edit it,
+ * and any modifications were done write it back and return true.
+ */
+ public boolean converge(TaskContext context) {
+ List<String> lines = uncheck(() -> Files.readAllLines(path, ENCODING));
+ List<String> newLines = new ArrayList<>();
+ StringBuilder diff = new StringBuilder();
+ boolean modified = false;
+
+ for (String line : lines) {
+ LineEdit edit = editor.edit(line);
+ switch (edit.getType()) {
+ case REMOVE:
+ modified = true;
+ maybeRemove(diff, line);
+ break;
+ case REPLACE:
+ modified = true;
+ String replacementLine = edit.replacementLine();
+ newLines.add(replacementLine);
+ maybeRemove(diff, line);
+ maybeAdd(diff, replacementLine);
+ break;
+ case NONE:
+ newLines.add(line);
+ break;
+ default: throw new IllegalArgumentException("Unknown EditType " + edit.getType());
+ }
+ }
+
+ List<String> linesToAppend = editor.onComplete();
+ if (!linesToAppend.isEmpty()) {
+ modified = true;
+ newLines.addAll(linesToAppend);
+ linesToAppend.forEach(line -> maybeAdd(diff, line));
+ }
+
+ if (!modified) {
+ return false;
+ }
+
+ String diffDescription = diffTooLarge(diff) ? "" : ":\n" + diff.toString();
+ context.recordSystemModification(logger, "Patching file " + path + diffDescription);
+ uncheck(() -> Files.write(path, newLines, ENCODING));
+ return true;
+ }
+
+ private static void maybeAdd(StringBuilder diff, String line) {
+ if (!diffTooLarge(diff)) {
+ diff.append('+').append(line).append('\n');
+ }
+ }
+
+ private static void maybeRemove(StringBuilder diff, String line) {
+ if (!diffTooLarge(diff)) {
+ diff.append('-').append(line).append('\n');
+ }
+ }
+
+ private static boolean diffTooLarge(StringBuilder diff) {
+ return diff.length() > maxLength;
+ }
+}
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/EditorFactory.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/EditorFactory.java
new file mode 100644
index 00000000000..a167840a8a6
--- /dev/null
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/EditorFactory.java
@@ -0,0 +1,13 @@
+// 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 java.nio.file.Path;
+
+/**
+ * @author hakonhall
+ */
+public class EditorFactory {
+ public Editor create(Path path, LineEditor editor) {
+ return new Editor(path, editor);
+ }
+}
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/LineEdit.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/LineEdit.java
new file mode 100644
index 00000000000..d822b6fae80
--- /dev/null
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/LineEdit.java
@@ -0,0 +1,31 @@
+// 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 javax.annotation.concurrent.Immutable;
+import java.util.Optional;
+
+import static com.yahoo.vespa.hosted.node.admin.task.util.file.LineEdit.Type.REMOVE;
+import static com.yahoo.vespa.hosted.node.admin.task.util.file.LineEdit.Type.REPLACE;
+import static com.yahoo.vespa.hosted.node.admin.task.util.file.LineEdit.Type.NONE;
+
+/**
+ * @author hakonhall
+ */
+@Immutable
+public class LineEdit {
+ enum Type { NONE, REPLACE, REMOVE}
+ private final Type type;
+ private final Optional<String> line;
+
+ public static LineEdit none() { return new LineEdit(NONE, Optional.empty()); }
+ public static LineEdit remove() { return new LineEdit(REMOVE, Optional.empty()); }
+ public static LineEdit replaceWith(String line) { return new LineEdit(REPLACE, Optional.of(line)); }
+
+ private LineEdit(Type type, Optional<String> newLine) {
+ this.type = type;
+ this.line = newLine;
+ }
+
+ public Type getType() { return type; }
+ public String replacementLine() { return line.get(); }
+}
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/LineEditor.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/LineEditor.java
new file mode 100644
index 00000000000..de43eb57074
--- /dev/null
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/LineEditor.java
@@ -0,0 +1,21 @@
+// 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 java.util.List;
+
+/**
+ * @author hakonhall
+ */
+public interface LineEditor {
+ /**
+ * @param line The line of a file.
+ * @return The edited line, or empty if the line should be removed.
+ */
+ LineEdit edit(String line);
+
+ /**
+ * Called after edit() has been called on all lines in the file.
+ * @return Lines to append to the file.
+ */
+ List<String> onComplete();
+}