summaryrefslogtreecommitdiffstats
path: root/node-admin/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'node-admin/src/main/java')
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/Acl.java13
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdmin.java10
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminImpl.java30
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminStateUpdater.java65
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextFactory.java3
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImpl.java3
6 files changed, 83 insertions, 41 deletions
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/Acl.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/Acl.java
index f377a603ab6..8f39fddfa1f 100644
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/Acl.java
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/Acl.java
@@ -5,12 +5,12 @@ import com.google.common.net.InetAddresses;
import com.yahoo.vespa.hosted.node.admin.task.util.network.IPVersion;
import java.net.InetAddress;
-import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@@ -22,6 +22,8 @@ import java.util.stream.Collectors;
*/
public class Acl {
+ public static final Acl EMPTY = new Acl(Set.of(), Set.of(), Set.of());
+
private final Set<Node> trustedNodes;
private final Set<Integer> trustedPorts;
private final Set<String> trustedNetworks;
@@ -38,7 +40,7 @@ public class Acl {
}
public Acl(Set<Integer> trustedPorts, Set<Node> trustedNodes) {
- this(trustedPorts, trustedNodes, Collections.emptySet());
+ this(trustedPorts, trustedNodes, Set.of());
}
public List<String> toRules(IPVersion ipVersion) {
@@ -131,10 +133,7 @@ public class Acl {
}
private static <T> Set<T> copyOfNullable(Set<T> set) {
- if (set == null) {
- return Collections.emptySet();
- }
- return Set.copyOf(set);
+ return Optional.ofNullable(set).map(Set::copyOf).orElseGet(Set::of);
}
public static class Node {
@@ -213,7 +212,7 @@ public class Acl {
}
public Builder withTrustedPorts(Integer... ports) {
- trustedPorts.addAll(Arrays.asList(ports));
+ trustedPorts.addAll(List.of(ports));
return this;
}
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdmin.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdmin.java
index 456391c65c2..6002e7bcd89 100644
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdmin.java
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdmin.java
@@ -1,10 +1,11 @@
// 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.node.admin.nodeadmin;
-import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeSpec;
+import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContext;
import java.time.Duration;
import java.util.List;
+import java.util.Set;
/**
* NodeAdmin manages the life cycle of NodeAgents.
@@ -12,11 +13,8 @@ import java.util.List;
*/
public interface NodeAdmin {
- /**
- * Calling this will cause NodeAdmin to move to the state containersToRun by adding or removing nodes.
- * @param containersToRun this is the wanted state.
- */
- void refreshContainersToRun(final List<NodeSpec> containersToRun);
+ /** Start/stop NodeAgents and schedule next NodeAgent ticks with the given NodeAgentContexts */
+ void refreshContainersToRun(Set<NodeAgentContext> nodeAgentContexts);
/** Gather node agent and its docker container metrics and forward them to the {@code MetricReceiverWrapper} */
void updateNodeAgentMetrics();
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminImpl.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminImpl.java
index 792656ca19f..546bf111e39 100644
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminImpl.java
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminImpl.java
@@ -1,19 +1,15 @@
// 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.node.admin.nodeadmin;
-import com.yahoo.concurrent.ThreadFactoryFactory;
import com.yahoo.vespa.hosted.dockerapi.metrics.CounterWrapper;
import com.yahoo.vespa.hosted.dockerapi.metrics.Dimensions;
import com.yahoo.vespa.hosted.dockerapi.metrics.GaugeWrapper;
import com.yahoo.vespa.hosted.dockerapi.metrics.MetricReceiverWrapper;
-import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeSpec;
import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgent;
import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContext;
-import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContextFactory;
import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContextManager;
import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentFactory;
import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentScheduler;
-import com.yahoo.vespa.hosted.node.admin.util.PrefixLogger;
import java.time.Clock;
import java.time.Duration;
@@ -23,6 +19,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
import java.util.stream.Collectors;
/**
@@ -31,12 +28,10 @@ import java.util.stream.Collectors;
* @author stiankri
*/
public class NodeAdminImpl implements NodeAdmin {
- private static final PrefixLogger logger = PrefixLogger.getNodeAdminLogger(NodeAdmin.class);
private static final Duration NODE_AGENT_FREEZE_TIMEOUT = Duration.ofSeconds(5);
private static final Duration NODE_AGENT_SPREAD = Duration.ofSeconds(3);
private final NodeAgentWithSchedulerFactory nodeAgentWithSchedulerFactory;
- private final NodeAgentContextFactory nodeAgentContextFactory;
private final Clock clock;
private final Duration freezeTimeout;
@@ -50,25 +45,20 @@ public class NodeAdminImpl implements NodeAdmin {
private final GaugeWrapper numberOfContainersInLoadImageState;
private final CounterWrapper numberOfUnhandledExceptionsInNodeAgent;
- public NodeAdminImpl(NodeAgentFactory nodeAgentFactory,
- NodeAgentContextFactory nodeAgentContextFactory,
- MetricReceiverWrapper metricReceiver,
- Clock clock) {
+ public NodeAdminImpl(NodeAgentFactory nodeAgentFactory, MetricReceiverWrapper metricReceiver, Clock clock) {
this((NodeAgentWithSchedulerFactory) nodeAgentContext -> create(clock, nodeAgentFactory, nodeAgentContext),
- nodeAgentContextFactory, metricReceiver, clock, NODE_AGENT_FREEZE_TIMEOUT, NODE_AGENT_SPREAD);
+ metricReceiver, clock, NODE_AGENT_FREEZE_TIMEOUT, NODE_AGENT_SPREAD);
}
- public NodeAdminImpl(NodeAgentFactory nodeAgentFactory, NodeAgentContextFactory nodeAgentContextFactory,
- MetricReceiverWrapper metricReceiver, Clock clock, Duration freezeTimeout, Duration spread) {
+ public NodeAdminImpl(NodeAgentFactory nodeAgentFactory, MetricReceiverWrapper metricReceiver,
+ Clock clock, Duration freezeTimeout, Duration spread) {
this((NodeAgentWithSchedulerFactory) nodeAgentContext -> create(clock, nodeAgentFactory, nodeAgentContext),
- nodeAgentContextFactory, metricReceiver, clock, freezeTimeout, spread);
+ metricReceiver, clock, freezeTimeout, spread);
}
NodeAdminImpl(NodeAgentWithSchedulerFactory nodeAgentWithSchedulerFactory,
- NodeAgentContextFactory nodeAgentContextFactory, MetricReceiverWrapper metricReceiver,
- Clock clock, Duration freezeTimeout, Duration spread) {
+ MetricReceiverWrapper metricReceiver, Clock clock, Duration freezeTimeout, Duration spread) {
this.nodeAgentWithSchedulerFactory = nodeAgentWithSchedulerFactory;
- this.nodeAgentContextFactory = nodeAgentContextFactory;
this.clock = clock;
this.freezeTimeout = freezeTimeout;
@@ -83,9 +73,9 @@ public class NodeAdminImpl implements NodeAdmin {
}
@Override
- public void refreshContainersToRun(List<NodeSpec> containersToRun) {
- final Map<String, NodeAgentContext> nodeAgentContextsByHostname = containersToRun.stream()
- .collect(Collectors.toMap(NodeSpec::getHostname, nodeAgentContextFactory::create));
+ public void refreshContainersToRun(Set<NodeAgentContext> nodeAgentContexts) {
+ Map<String, NodeAgentContext> nodeAgentContextsByHostname = nodeAgentContexts.stream()
+ .collect(Collectors.toMap(nac -> nac.hostname().value(), Function.identity()));
// Stop and remove NodeAgents that should no longer be running
diff(nodeAgentWithSchedulerByHostname.keySet(), nodeAgentContextsByHostname.keySet())
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminStateUpdater.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminStateUpdater.java
index 18c3a836e41..eb306036416 100644
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminStateUpdater.java
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminStateUpdater.java
@@ -4,18 +4,28 @@ package com.yahoo.vespa.hosted.node.admin.nodeadmin;
import com.yahoo.concurrent.ThreadFactoryFactory;
import com.yahoo.config.provision.HostName;
import com.yahoo.log.LogLevel;
+import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.Acl;
import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeSpec;
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.nodeagent.NodeAgentContext;
+import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContextFactory;
import com.yahoo.vespa.hosted.provision.Node;
+import java.time.Clock;
import java.time.Duration;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
@@ -37,6 +47,8 @@ public class NodeAdminStateUpdater {
private final ScheduledExecutorService metricsScheduler =
Executors.newScheduledThreadPool(1, ThreadFactoryFactory.getDaemonThreadFactory("metricsscheduler"));
+ private final CachedSupplier<Map<String, Acl>> cachedAclSupplier;
+ private final NodeAgentContextFactory nodeAgentContextFactory;
private final NodeRepository nodeRepository;
private final Orchestrator orchestrator;
private final NodeAdmin nodeAdmin;
@@ -47,14 +59,18 @@ public class NodeAdminStateUpdater {
private volatile State currentState = SUSPENDED_NODE_ADMIN;
public NodeAdminStateUpdater(
+ NodeAgentContextFactory nodeAgentContextFactory,
NodeRepository nodeRepository,
Orchestrator orchestrator,
NodeAdmin nodeAdmin,
- HostName hostHostname) {
+ HostName hostHostname,
+ Clock clock) {
+ this.nodeAgentContextFactory = nodeAgentContextFactory;
this.nodeRepository = nodeRepository;
this.orchestrator = orchestrator;
this.nodeAdmin = nodeAdmin;
this.hostHostname = hostHostname.value();
+ this.cachedAclSupplier = new CachedSupplier<>(clock, Duration.ofSeconds(115), () -> nodeRepository.getAcls(this.hostHostname));
}
public void start() {
@@ -145,11 +161,21 @@ public class NodeAdminStateUpdater {
currentState = wantedState;
}
- private void adjustNodeAgentsToRunFromNodeRepository() {
+ void adjustNodeAgentsToRunFromNodeRepository() {
try {
- final List<NodeSpec> containersToRun = nodeRepository.getNodes(hostHostname);
- nodeAdmin.refreshContainersToRun(containersToRun);
- } catch (Exception e) {
+ Map<String, NodeSpec> nodeSpecByHostname = nodeRepository.getNodes(hostHostname).stream()
+ .collect(Collectors.toMap(NodeSpec::getHostname, Function.identity()));
+ Map<String, Acl> aclByHostname = Optional.of(cachedAclSupplier.get())
+ .filter(acls -> acls.keySet().containsAll(nodeSpecByHostname.keySet()))
+ .orElseGet(cachedAclSupplier::invalidateAndGet);
+
+ Set<NodeAgentContext> nodeAgentContexts = nodeSpecByHostname.keySet().stream()
+ .map(hostname -> nodeAgentContextFactory.create(
+ nodeSpecByHostname.get(hostname),
+ aclByHostname.getOrDefault(hostname, Acl.EMPTY)))
+ .collect(Collectors.toSet());
+ nodeAdmin.refreshContainersToRun(nodeAgentContexts);
+ } catch (RuntimeException e) {
log.log(LogLevel.WARNING, "Failed to update which containers should be running", e);
}
}
@@ -161,4 +187,33 @@ public class NodeAdminStateUpdater {
.map(NodeSpec::getHostname)
.collect(Collectors.toList());
}
+
+ private static class CachedSupplier<T> implements Supplier<T> {
+ private final Clock clock;
+ private final Duration expiration;
+ private final Supplier<T> supplier;
+ private Instant refreshAt;
+ private T cachedValue;
+
+ private CachedSupplier(Clock clock, Duration expiration, Supplier<T> supplier) {
+ this.clock = clock;
+ this.expiration = expiration;
+ this.supplier = supplier;
+ this.refreshAt = Instant.MIN;
+ }
+
+ @Override
+ public T get() {
+ if (! clock.instant().isBefore(refreshAt)) {
+ cachedValue = supplier.get();
+ refreshAt = clock.instant().plus(expiration);
+ }
+ return cachedValue;
+ }
+
+ private T invalidateAndGet() {
+ refreshAt = Instant.MIN;
+ return get();
+ }
+ }
}
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextFactory.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextFactory.java
index 0cfafe34717..3e0991d4357 100644
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextFactory.java
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextFactory.java
@@ -1,6 +1,7 @@
// 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.nodeagent;
+import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.Acl;
import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeSpec;
/**
@@ -8,5 +9,5 @@ import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeSpec;
*/
@FunctionalInterface
public interface NodeAgentContextFactory {
- NodeAgentContext create(NodeSpec nodeSpec);
+ NodeAgentContext create(NodeSpec nodeSpec, Acl acl);
}
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 e3872d9cf31..804450f05ff 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
@@ -15,7 +15,6 @@ import com.yahoo.vespa.hosted.provision.Node;
import java.nio.file.FileSystem;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.Collections;
import java.util.Objects;
import java.util.Optional;
import java.util.logging.Level;
@@ -235,7 +234,7 @@ public class NodeAgentContextImpl implements NodeAgentContext {
public NodeAgentContextImpl build() {
return new NodeAgentContextImpl(
nodeSpecBuilder.build(),
- Optional.ofNullable(acl).orElseGet(() -> new Acl(Collections.emptySet(), Collections.emptySet())),
+ Optional.ofNullable(acl).orElse(Acl.EMPTY),
Optional.ofNullable(identity).orElseGet(() -> new AthenzService("domain", "service")),
Optional.ofNullable(dockerNetworking).orElse(DockerNetworking.HOST_NETWORK),
Optional.ofNullable(zoneId).orElseGet(() -> new ZoneId(SystemName.dev, Environment.dev, RegionName.defaultName())),