summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java8
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/ApplicationRepositoryTest.java8
-rw-r--r--container-core/src/main/java/com/yahoo/container/handler/LogHandler.java4
-rw-r--r--container-core/src/main/java/com/yahoo/container/handler/LogReader.java12
-rw-r--r--container-core/src/test/java/com/yahoo/container/handler/LogHandlerTest.java3
-rw-r--r--container-core/src/test/java/com/yahoo/container/handler/LogReaderTest.java36
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/jira/Jira.java3
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/Flags.java3
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/StorageMaintainer.java9
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/acl/AclMaintainer.java5
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/identity/AthenzCredentialsMaintainer.java5
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContext.java6
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImpl.java24
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentTask.java30
-rw-r--r--node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImplTest.java22
-rw-r--r--storage/src/vespa/storage/distributor/operations/external/twophaseupdateoperation.cpp4
16 files changed, 137 insertions, 45 deletions
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java
index 937cf4dfe7f..58b7d0ec5bb 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java
@@ -874,12 +874,8 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
// We make no validation that the hostname is actually allocated to the given application since
// most applications under hosted-vespa are not known to the model and it's OK for a user to get
// logs for any host if they are authorized for the hosted-vespa tenant.
- if (hostname.isPresent()) {
- if (HOSTED_VESPA_TENANT.equals(applicationId.tenant()))
- return "http://" + hostname.get() + ":8080/logs";
- else
- throw new IllegalArgumentException("Using hostname parameter when getting logs is not supported for application "
- + applicationId);
+ if (hostname.isPresent() && HOSTED_VESPA_TENANT.equals(applicationId.tenant())) {
+ return "http://" + hostname.get() + ":8080/logs";
}
Application application = getApplication(applicationId);
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/ApplicationRepositoryTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/ApplicationRepositoryTest.java
index a4b2bfb8902..e20fef0909c 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/ApplicationRepositoryTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/ApplicationRepositoryTest.java
@@ -234,14 +234,6 @@ public class ApplicationRepositoryTest {
assertEquals(200, response.getStatus());
}
- @Test(expected = IllegalArgumentException.class)
- public void refuseToGetLogsFromHostnameNotInApplication() {
- applicationRepository = createApplicationRepository();
- deployApp(testAppLogServerWithContainer);
- HttpResponse response = applicationRepository.getLogs(applicationId(), Optional.of("host123.fake.yahoo.com"), "");
- assertEquals(200, response.getStatus());
- }
-
@Test
public void deleteUnusedFileReferences() throws IOException {
File fileReferencesDir = temporaryFolder.newFolder();
diff --git a/container-core/src/main/java/com/yahoo/container/handler/LogHandler.java b/container-core/src/main/java/com/yahoo/container/handler/LogHandler.java
index f3149ed4998..b2a156862eb 100644
--- a/container-core/src/main/java/com/yahoo/container/handler/LogHandler.java
+++ b/container-core/src/main/java/com/yahoo/container/handler/LogHandler.java
@@ -35,11 +35,13 @@ public class LogHandler extends ThreadedHttpRequestHandler {
Instant to = Optional.ofNullable(request.getProperty("to"))
.map(Long::valueOf).map(Instant::ofEpochMilli).orElse(Instant.MAX);
+ Optional<String> hostname = Optional.ofNullable(request.getProperty("hostname"));
+
return new HttpResponse(200) {
@Override
public void render(OutputStream outputStream) {
try {
- logReader.writeLogs(outputStream, from, to);
+ logReader.writeLogs(outputStream, from, to, hostname);
}
catch (Throwable t) {
log.log(Level.WARNING, "Failed reading logs from " + from + " to " + to, t);
diff --git a/container-core/src/main/java/com/yahoo/container/handler/LogReader.java b/container-core/src/main/java/com/yahoo/container/handler/LogReader.java
index 3cf849a6835..8e4b9aea9b8 100644
--- a/container-core/src/main/java/com/yahoo/container/handler/LogReader.java
+++ b/container-core/src/main/java/com/yahoo/container/handler/LogReader.java
@@ -27,6 +27,7 @@ import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
+import java.util.Optional;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -57,7 +58,7 @@ class LogReader {
this.logFilePattern = logFilePattern;
}
- void writeLogs(OutputStream out, Instant from, Instant to) {
+ void writeLogs(OutputStream out, Instant from, Instant to, Optional<String> hostname) {
double fromSeconds = from.getEpochSecond() + from.getNano() / 1e9;
double toSeconds = to.getEpochSecond() + to.getNano() / 1e9;
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out));
@@ -67,7 +68,7 @@ class LogReader {
try {
// Logs in each sub-list contain entries covering the same time interval, so do a merge sort while reading
for (Path log : logs)
- logLineIterators.add(new LogLineIterator(log, fromSeconds, toSeconds));
+ logLineIterators.add(new LogLineIterator(log, fromSeconds, toSeconds, hostname));
Iterator<LineWithTimestamp> lines = Iterators.mergeSorted(logLineIterators,
Comparator.comparingDouble(LineWithTimestamp::timestamp));
@@ -96,14 +97,16 @@ class LogReader {
private final BufferedReader reader;
private final double from;
private final double to;
+ private final Optional<String> hostname;
private LineWithTimestamp next;
- private LogLineIterator(Path log, double from, double to) throws IOException {
+ private LogLineIterator(Path log, double from, double to, Optional<String> hostname) throws IOException {
boolean zipped = log.toString().endsWith(".gz");
InputStream in = Files.newInputStream(log);
this.reader = new BufferedReader(new InputStreamReader(zipped ? new GZIPInputStream(in) : in, UTF_8));
this.from = from;
this.to = to;
+ this.hostname = hostname;
this.next = readNext();
}
@@ -131,6 +134,9 @@ class LogReader {
if (parts.length != 7)
continue;
+ if (hostname.map(host -> !host.equals(parts[1])).orElse(false))
+ continue;
+
double timestamp = Double.parseDouble(parts[0]);
if (timestamp > to)
return null;
diff --git a/container-core/src/test/java/com/yahoo/container/handler/LogHandlerTest.java b/container-core/src/test/java/com/yahoo/container/handler/LogHandlerTest.java
index ab0d0d54675..97aa8864eae 100644
--- a/container-core/src/test/java/com/yahoo/container/handler/LogHandlerTest.java
+++ b/container-core/src/test/java/com/yahoo/container/handler/LogHandlerTest.java
@@ -9,6 +9,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.time.Instant;
+import java.util.Optional;
import java.util.concurrent.Executor;
import static org.junit.Assert.assertEquals;
@@ -47,7 +48,7 @@ public class LogHandlerTest {
}
@Override
- protected void writeLogs(OutputStream out, Instant from, Instant to) {
+ protected void writeLogs(OutputStream out, Instant from, Instant to, Optional<String> hostname) {
try {
if (to.isAfter(Instant.ofEpochMilli(1000))) {
out.write("newer log".getBytes());
diff --git a/container-core/src/test/java/com/yahoo/container/handler/LogReaderTest.java b/container-core/src/test/java/com/yahoo/container/handler/LogReaderTest.java
index 3f7a78e13be..ad9398a5eec 100644
--- a/container-core/src/test/java/com/yahoo/container/handler/LogReaderTest.java
+++ b/container-core/src/test/java/com/yahoo/container/handler/LogReaderTest.java
@@ -5,7 +5,6 @@ import com.yahoo.vespa.test.file.TestFileSystem;
import org.junit.Before;
import org.junit.Test;
-import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@@ -14,8 +13,8 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.time.Instant;
+import java.util.Optional;
import java.util.regex.Pattern;
-import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -26,12 +25,12 @@ public class LogReaderTest {
private final FileSystem fileSystem = TestFileSystem.create();
private final Path logDirectory = fileSystem.getPath("/opt/vespa/logs");
- private static final String logv11 = "3600.2\t17491290-v6-1.ostk.bm2.prod.ne1.yahoo.com\t5480\tcontainer\tstdout\tinfo\tfourth\n";
- private static final String logv = "90000.1\t17491290-v6-1.ostk.bm2.prod.ne1.yahoo.com\t5480\tcontainer\tstdout\tinfo\tlast\n";
- private static final String log100 = "0.2\t17491290-v6-1.ostk.bm2.prod.ne1.yahoo.com\t5480\tcontainer\tstdout\tinfo\tsecond\n";
- private static final String log101 = "0.1\t17491290-v6-1.ostk.bm2.prod.ne1.yahoo.com\t5480\tcontainer\tstdout\tinfo\tERROR: Bundle canary-application [71] Unable to get module class path. (java.lang.NullPointerException)\n";
- private static final String log110 = "3600.1\t17491290-v6-1.ostk.bm2.prod.ne1.yahoo.com\t5480\tcontainer\tstderr\twarning\tthird\n";
- private static final String log200 = "86400.1\t17491290-v6-1.ostk.bm2.prod.ne1.yahoo.com\t5480\tcontainer\tstderr\twarning\tjava.lang.NullPointerException\\n\\tat org.apache.felix.framework.BundleRevisionImpl.calculateContentPath(BundleRevisionImpl.java:438)\\n\\tat org.apache.felix.framework.BundleRevisionImpl.initializeContentPath(BundleRevisionImpl.java:371)\n";
+ private static final String logv11 = "3600.2\tnode1.com\t5480\tcontainer\tstdout\tinfo\tfourth\n";
+ private static final String logv = "90000.1\tnode1.com\t5480\tcontainer\tstdout\tinfo\tlast\n";
+ private static final String log100 = "0.2\tnode2.com\t5480\tcontainer\tstdout\tinfo\tsecond\n";
+ private static final String log101 = "0.1\tnode2.com\t5480\tcontainer\tstdout\tinfo\tERROR: Bundle canary-application [71] Unable to get module class path. (java.lang.NullPointerException)\n";
+ private static final String log110 = "3600.1\tnode1.com\t5480\tcontainer\tstderr\twarning\tthird\n";
+ private static final String log200 = "86400.1\tnode2.com\t5480\tcontainer\tstderr\twarning\tjava.lang.NullPointerException\\n\\tat org.apache.felix.framework.BundleRevisionImpl.calculateContentPath(BundleRevisionImpl.java:438)\\n\\tat org.apache.felix.framework.BundleRevisionImpl.initializeContentPath(BundleRevisionImpl.java:371)\n";
@Before
public void setup() throws IOException {
@@ -52,32 +51,41 @@ public class LogReaderTest {
}
@Test
- public void testThatLogsOutsideRangeAreExcluded() throws Exception {
+ public void testThatLogsOutsideRangeAreExcluded() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
LogReader logReader = new LogReader(logDirectory, Pattern.compile(".*"));
- logReader.writeLogs(baos, Instant.ofEpochMilli(150), Instant.ofEpochMilli(3601050));
+ logReader.writeLogs(baos, Instant.ofEpochMilli(150), Instant.ofEpochMilli(3601050), Optional.empty());
assertEquals(log100 + logv11 + log110, baos.toString(UTF_8));
}
@Test
- public void testThatLogsNotMatchingRegexAreExcluded() throws Exception {
+ public void testThatLogsNotMatchingRegexAreExcluded() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
LogReader logReader = new LogReader(logDirectory, Pattern.compile(".*-1.*"));
- logReader.writeLogs(baos, Instant.EPOCH, Instant.EPOCH.plus(Duration.ofDays(2)));
+ logReader.writeLogs(baos, Instant.EPOCH, Instant.EPOCH.plus(Duration.ofDays(2)), Optional.empty());
assertEquals(log101 + logv11, baos.toString(UTF_8));
}
@Test
- public void testZippedStreaming() throws IOException {
+ public void testZippedStreaming() {
ByteArrayOutputStream zippedBaos = new ByteArrayOutputStream();
LogReader logReader = new LogReader(logDirectory, Pattern.compile(".*"));
- logReader.writeLogs(zippedBaos, Instant.EPOCH, Instant.EPOCH.plus(Duration.ofDays(2)));
+ logReader.writeLogs(zippedBaos, Instant.EPOCH, Instant.EPOCH.plus(Duration.ofDays(2)), Optional.empty());
assertEquals(log101 + log100 + logv11 + log110 + log200 + logv, zippedBaos.toString(UTF_8));
}
+ @Test
+ public void logsForSingeNodeIsRetrieved() {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ LogReader logReader = new LogReader(logDirectory, Pattern.compile(".*"));
+ logReader.writeLogs(baos, Instant.EPOCH, Instant.EPOCH.plus(Duration.ofDays(2)), Optional.of("node2.com"));
+
+ assertEquals(log101 + log100 + log200, baos.toString(UTF_8));
+ }
+
private byte[] compress(String input) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStream zip = new GZIPOutputStream(baos);
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/jira/Jira.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/jira/Jira.java
index 30bf23f18a9..6848c67fed2 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/jira/Jira.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/jira/Jira.java
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller.api.integration.jira;
+import java.io.InputStream;
import java.util.List;
/**
@@ -14,5 +15,5 @@ public interface Jira {
void commentIssue(JiraIssue issue, JiraComment comment);
- void addAttachment(JiraIssue issue, String filename, String fileContent);
+ void addAttachment(JiraIssue issue, String filename, InputStream fileContent);
}
diff --git a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
index 818fd4db5cd..cc3cb3adc85 100644
--- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
+++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
@@ -71,7 +71,8 @@ public class Flags {
public static final UnboundListFlag<String> DISABLED_HOST_ADMIN_TASKS = defineListFlag(
"disabled-host-admin-tasks", List.of(), String.class,
- "List of host-admin task names (as they appear in the log, e.g. root>main>UpgradeTask) that should be skipped",
+ "List of host-admin task names (as they appear in the log, e.g. root>main>UpgradeTask), or some node-agent " +
+ "functionality (see NodeAgentTask), that should be skipped",
"Takes effect on next host admin tick",
HOSTNAME, NODE_TYPE);
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/StorageMaintainer.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/StorageMaintainer.java
index 30ca2e0d218..a5efec1dcb7 100644
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/StorageMaintainer.java
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/StorageMaintainer.java
@@ -5,7 +5,6 @@ import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.yahoo.config.provision.DockerImage;
import com.yahoo.config.provision.NodeType;
-import java.util.logging.Level;
import com.yahoo.vespa.hosted.dockerapi.Container;
import com.yahoo.vespa.hosted.dockerapi.ContainerName;
import com.yahoo.vespa.hosted.node.admin.component.TaskContext;
@@ -16,8 +15,9 @@ import com.yahoo.vespa.hosted.node.admin.maintenance.disk.DiskCleanupRule;
import com.yahoo.vespa.hosted.node.admin.maintenance.disk.LinearCleanupRule;
import com.yahoo.vespa.hosted.node.admin.nodeadmin.ConvergenceException;
import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContext;
-import com.yahoo.vespa.hosted.node.admin.task.util.file.FileFinder;
+import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentTask;
import com.yahoo.vespa.hosted.node.admin.task.util.file.DiskSize;
+import com.yahoo.vespa.hosted.node.admin.task.util.file.FileFinder;
import com.yahoo.vespa.hosted.node.admin.task.util.file.UnixPath;
import com.yahoo.vespa.hosted.node.admin.task.util.process.Terminal;
@@ -37,8 +37,8 @@ import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
+import java.util.logging.Level;
import java.util.logging.Logger;
-import java.util.stream.Stream;
import static com.yahoo.vespa.hosted.node.admin.maintenance.disk.DiskCleanupRule.Priority;
import static com.yahoo.yolean.Exceptions.uncheck;
@@ -107,6 +107,8 @@ public class StorageMaintainer {
}
public boolean cleanDiskIfFull(NodeAgentContext context) {
+ if (context.isDisabled(NodeAgentTask.DiskCleanup)) return false;
+
double totalBytes = context.node().diskSize().bytes();
// Delete enough bytes to get below 70% disk usage, but only if we are already using more than 80% disk
long bytesToRemove = diskUsageFor(context)
@@ -148,6 +150,7 @@ public class StorageMaintainer {
/** Checks if container has any new coredumps, reports and archives them if so */
public void handleCoreDumpsForContainer(NodeAgentContext context, Optional<Container> container) {
+ if (context.isDisabled(NodeAgentTask.CoreDumps)) return;
coredumpHandler.converge(context, () -> getCoredumpNodeAttributes(context, container));
}
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/acl/AclMaintainer.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/acl/AclMaintainer.java
index 360cea8a60d..fe6b29402b5 100644
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/acl/AclMaintainer.java
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/acl/AclMaintainer.java
@@ -2,9 +2,9 @@
package com.yahoo.vespa.hosted.node.admin.maintenance.acl;
import com.google.common.net.InetAddresses;
-import java.util.logging.Level;
import com.yahoo.vespa.hosted.node.admin.docker.DockerOperations;
import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContext;
+import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentTask;
import com.yahoo.vespa.hosted.node.admin.task.util.file.Editor;
import com.yahoo.vespa.hosted.node.admin.task.util.file.LineEditor;
import com.yahoo.vespa.hosted.node.admin.task.util.network.IPAddresses;
@@ -18,6 +18,7 @@ import java.nio.file.Path;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
+import java.util.logging.Level;
import java.util.logging.Logger;
import static com.yahoo.yolean.Exceptions.uncheck;
@@ -51,6 +52,8 @@ public class AclMaintainer {
// ip(6)tables operate while having the xtables lock, run with synchronized to prevent multiple NodeAgents
// invoking ip(6)tables concurrently.
public synchronized void converge(NodeAgentContext context) {
+ if (context.isDisabled(NodeAgentTask.AclMaintainer)) return;
+
// Apply acl to the filter table
editFlushOnError(context, IPVersion.IPv4, "filter", FilterTableLineEditor.from(context.acl(), IPVersion.IPv4));
editFlushOnError(context, IPVersion.IPv6, "filter", FilterTableLineEditor.from(context.acl(), IPVersion.IPv6));
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/identity/AthenzCredentialsMaintainer.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/identity/AthenzCredentialsMaintainer.java
index 3320851a36c..d6c08a820cd 100644
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/identity/AthenzCredentialsMaintainer.java
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/identity/AthenzCredentialsMaintainer.java
@@ -1,7 +1,6 @@
// 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.maintenance.identity;
-import java.util.logging.Level;
import com.yahoo.security.KeyAlgorithm;
import com.yahoo.security.KeyStoreType;
import com.yahoo.security.KeyUtils;
@@ -24,6 +23,7 @@ import com.yahoo.vespa.athenz.utils.SiaUtils;
import com.yahoo.vespa.hosted.dockerapi.ContainerName;
import com.yahoo.vespa.hosted.node.admin.component.ConfigServerInfo;
import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContext;
+import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentTask;
import com.yahoo.vespa.hosted.node.admin.task.util.file.FileFinder;
import com.yahoo.vespa.hosted.node.admin.task.util.file.UnixPath;
@@ -46,6 +46,7 @@ import java.time.Instant;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
import java.util.logging.Logger;
/**
@@ -108,6 +109,8 @@ public class AthenzCredentialsMaintainer implements CredentialsMaintainer {
}
public boolean converge(NodeAgentContext context) {
+ if (context.isDisabled(NodeAgentTask.CredentialsMaintainer)) return false;
+
try {
context.log(logger, Level.FINE, "Checking certificate");
Path containerSiaDirectory = context.pathOnHostFromPathInNode(CONTAINER_SIA_DIRECTORY);
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContext.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContext.java
index d589000c07e..872b8a8096b 100644
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContext.java
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContext.java
@@ -44,6 +44,10 @@ public interface NodeAgentContext extends TaskContext {
String vespaUserOnHost();
+ default boolean isDisabled(NodeAgentTask task) {
+ return false;
+ };
+
/**
* The vcpu value in NodeSpec is multiplied by the speedup factor per cpu core compared to a historical baseline
* for a particular cpu generation of the host (see flavors.def cpuSpeedup).
@@ -52,7 +56,7 @@ public interface NodeAgentContext extends TaskContext {
*/
double unscaledVcpu();
- /** The file system used by the NodeAgentContext. All paths must have the same provider. */
+ /** The file system used by the NodeAgentContext. All paths must have the same provider. */
FileSystem fileSystem();
/**
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImpl.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImpl.java
index 9f0c8d47d64..c7c0675c30e 100644
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImpl.java
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImpl.java
@@ -7,6 +7,10 @@ import com.yahoo.config.provision.zone.ZoneApi;
import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.vespa.athenz.api.AthenzIdentity;
import com.yahoo.vespa.athenz.api.AthenzService;
+import com.yahoo.vespa.flags.FetchVector;
+import com.yahoo.vespa.flags.FlagSource;
+import com.yahoo.vespa.flags.Flags;
+import com.yahoo.vespa.flags.InMemoryFlagSource;
import com.yahoo.vespa.hosted.dockerapi.ContainerName;
import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.Acl;
import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeSpec;
@@ -18,6 +22,7 @@ import java.nio.file.Path;
import java.nio.file.ProviderMismatchException;
import java.util.Objects;
import java.util.Optional;
+import java.util.Set;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -40,10 +45,11 @@ public class NodeAgentContextImpl implements NodeAgentContext {
private final String vespaUser;
private final String vespaUserOnHost;
private final double cpuSpeedup;
+ private final Set<NodeAgentTask> disabledNodeAgentTasks;
public NodeAgentContextImpl(NodeSpec node, Acl acl, AthenzIdentity identity,
DockerNetworking dockerNetworking, ZoneApi zone,
- FileSystem fileSystem,
+ FileSystem fileSystem, FlagSource flagSource,
Path pathToContainerStorage, Path pathToVespaHome,
String vespaUser, String vespaUserOnHost, double cpuSpeedup) {
if (cpuSpeedup <= 0)
@@ -55,13 +61,15 @@ public class NodeAgentContextImpl implements NodeAgentContext {
this.identity = Objects.requireNonNull(identity);
this.dockerNetworking = Objects.requireNonNull(dockerNetworking);
this.zone = Objects.requireNonNull(zone);
- this.fileSystem = fileSystem;
+ this.fileSystem = Objects.requireNonNull(fileSystem);
this.pathToNodeRootOnHost = requireValidPath(pathToContainerStorage).resolve(containerName.asString());
this.pathToVespaHome = requireValidPath(pathToVespaHome);
this.logPrefix = containerName.asString() + ": ";
this.vespaUser = vespaUser;
this.vespaUserOnHost = vespaUserOnHost;
this.cpuSpeedup = cpuSpeedup;
+ this.disabledNodeAgentTasks = NodeAgentTask.fromString(
+ Flags.DISABLED_HOST_ADMIN_TASKS.bindTo(flagSource).with(FetchVector.Dimension.HOSTNAME, node.hostname()).value());
}
@Override
@@ -105,6 +113,11 @@ public class NodeAgentContextImpl implements NodeAgentContext {
}
@Override
+ public boolean isDisabled(NodeAgentTask task) {
+ return disabledNodeAgentTasks.contains(task);
+ }
+
+ @Override
public double unscaledVcpu() {
return node.vcpu() / cpuSpeedup;
}
@@ -212,6 +225,7 @@ public class NodeAgentContextImpl implements NodeAgentContext {
private String vespaUser;
private String vespaUserOnHost;
private FileSystem fileSystem = FileSystems.getDefault();
+ private FlagSource flagSource;
private double cpuSpeedUp = 1;
public Builder(NodeSpec node) {
@@ -268,6 +282,11 @@ public class NodeAgentContextImpl implements NodeAgentContext {
return this;
}
+ public Builder flagSource(FlagSource flagSource) {
+ this.flagSource = flagSource;
+ return this;
+ }
+
public Builder cpuSpeedUp(double cpuSpeedUp) {
this.cpuSpeedUp = cpuSpeedUp;
return this;
@@ -301,6 +320,7 @@ public class NodeAgentContextImpl implements NodeAgentContext {
}
}),
fileSystem,
+ Optional.ofNullable(flagSource).orElseGet(InMemoryFlagSource::new),
fileSystem.getPath("/home/docker/container-storage"),
fileSystem.getPath("/opt/vespa"),
Optional.ofNullable(vespaUser).orElse("vespa"),
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentTask.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentTask.java
new file mode 100644
index 00000000000..d57c680e190
--- /dev/null
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentTask.java
@@ -0,0 +1,30 @@
+package com.yahoo.vespa.hosted.node.admin.nodeagent;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public enum NodeAgentTask {
+
+ // The full task name is prefixed with 'node>', e.g. 'node>DiskCleanup'
+ DiskCleanup,
+ CoreDumps,
+ CredentialsMaintainer,
+ AclMaintainer;
+
+ private static final Map<String, NodeAgentTask> tasksByName = Arrays.stream(NodeAgentTask.values())
+ .collect(Collectors.toUnmodifiableMap(NodeAgentTask::taskName, n -> n));
+
+ private final String taskName;
+ NodeAgentTask() {
+ this.taskName = "node>" + name();
+ }
+
+ public String taskName() { return taskName; }
+
+ public static Set<NodeAgentTask> fromString(List<String> tasks) {
+ return tasks.stream().filter(tasksByName::containsKey).map(tasksByName::get).collect(Collectors.toUnmodifiableSet());
+ }
+}
diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImplTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImplTest.java
index 9bcbce849af..b7e0a2a1d97 100644
--- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImplTest.java
+++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImplTest.java
@@ -2,14 +2,19 @@
package com.yahoo.vespa.hosted.node.admin.nodeagent;
import com.yahoo.config.provision.DockerImage;
+import com.yahoo.vespa.flags.Flags;
+import com.yahoo.vespa.flags.InMemoryFlagSource;
import com.yahoo.vespa.test.file.TestFileSystem;
import org.junit.Test;
import java.nio.file.FileSystem;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.List;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
/**
* @author freva
@@ -84,6 +89,23 @@ public class NodeAgentContextImplTest {
assertRewrite("docker.tld/vespa/hosted:1.2.3", "/opt/vespa/log", "/opt/vespa/log");
}
+ @Test
+ public void disabledTasksTest() {
+ NodeAgentContext context1 = createContextWithDisabledTasks();
+ assertFalse(context1.isDisabled(NodeAgentTask.DiskCleanup));
+ assertFalse(context1.isDisabled(NodeAgentTask.CoreDumps));
+
+ NodeAgentContext context2 = createContextWithDisabledTasks("root>UpgradeTask", "DiskCleanup", "node>CoreDumps");
+ assertFalse(context2.isDisabled(NodeAgentTask.DiskCleanup));
+ assertTrue(context2.isDisabled(NodeAgentTask.CoreDumps));
+ }
+
+ private static NodeAgentContext createContextWithDisabledTasks(String... tasks) {
+ InMemoryFlagSource flagSource = new InMemoryFlagSource();
+ flagSource.withListFlag(Flags.DISABLED_HOST_ADMIN_TASKS.id(), List.of(tasks), String.class);
+ return new NodeAgentContextImpl.Builder("node123").flagSource(flagSource).build();
+ }
+
private static void assertRewrite(String dockerImage, String path, String expected) {
NodeAgentContext context = new NodeAgentContextImpl.Builder("node123")
.nodeSpecBuilder(ns -> ns.wantedDockerImage(DockerImage.fromString(dockerImage)))
diff --git a/storage/src/vespa/storage/distributor/operations/external/twophaseupdateoperation.cpp b/storage/src/vespa/storage/distributor/operations/external/twophaseupdateoperation.cpp
index 43cf43b02b6..73788d0affe 100644
--- a/storage/src/vespa/storage/distributor/operations/external/twophaseupdateoperation.cpp
+++ b/storage/src/vespa/storage/distributor/operations/external/twophaseupdateoperation.cpp
@@ -277,8 +277,8 @@ TwoPhaseUpdateOperation::schedulePutsWithUpdatedDocument(std::shared_ptr<documen
op.start(intermediate, _manager.getClock().getTimeInMillis());
transitionTo(SendState::PUTS_SENT);
- LOG(debug, "Update(%s): sending Put commands with doc %s",
- update_doc_id().c_str(), doc->toString(true).c_str());
+ LOG(debug, "Update(%s): sending Puts at timestamp %" PRIu64, update_doc_id().c_str(), putTimestamp);
+ LOG(spam, "Update(%s): Put document is: %s", update_doc_id().c_str(), doc->toString(true).c_str());
if (intermediate._reply.get()) {
sendReplyWithResult(sender, intermediate._reply->getResult());