summaryrefslogtreecommitdiffstats
path: root/node-repository
diff options
context:
space:
mode:
authorHåkon Hallingstad <hakon@verizonmedia.com>2019-01-31 17:46:48 +0100
committerHåkon Hallingstad <hakon@verizonmedia.com>2019-01-31 17:46:48 +0100
commit025fb0323fda34617204125878be903e1a019f43 (patch)
treede61a9512086446d61c9bdc4dba70eb43bb42c74 /node-repository
parentfa0cf4a8a3a16c565e9315dba8737cbf39b530e9 (diff)
parent55cf60201e329604e19ef0ff7ac1f5300716742a (diff)
Merge branch 'master' into hakonhall/support-node-reports-in-node-repository
Diffstat (limited to 'node-repository')
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/Node.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java7
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostDeprovisionMaintainer.java64
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostProvisionMaintainer.java70
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java14
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Generation.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/IP.java6
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Status.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/DockerHostCapacity.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/FatalProvisioningException.java19
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostProvisioner.java37
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java4
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostDeprovisionMaintainerTest.java98
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostProvisionMaintainerTest.java157
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/monitoring/MetricsReporterTest.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AllocationSimulator.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AllocationVisualizer.java4
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java6
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/MultigroupProvisioningTest.java6
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java4
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/filter/NodeIdentifierTest.java2
22 files changed, 484 insertions, 30 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/Node.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/Node.java
index 79966c8c529..b2597e9cc50 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/Node.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/Node.java
@@ -73,7 +73,6 @@ public final class Node {
Flavor flavor, Status status, State state, Optional<Allocation> allocation, History history, NodeType type,
Reports reports) {
Objects.requireNonNull(id, "A node must have an ID");
- requireNonEmpty(ipAddresses, "A node must have at least one valid IP address");
requireNonEmptyString(hostname, "A node must have a hostname");
requireNonEmptyString(parentHostname, "A parent host name must be a proper value");
Objects.requireNonNull(flavor, "A node must have a flavor");
@@ -84,6 +83,9 @@ public final class Node {
Objects.requireNonNull(type, "A null node type is not permitted");
Objects.requireNonNull(reports, "A null reports is not permitted");
+ if (state == State.active)
+ requireNonEmpty(ipAddresses, "An active node must have at least one valid IP address");
+
this.ipAddresses = ImmutableSet.copyOf(ipAddresses);
this.ipAddressPool = new IP.AddressPool(this, ipAddressPool);
this.hostname = hostname;
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java
index cbce0f38c43..601ef555cab 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java
@@ -7,6 +7,7 @@ import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.NodeType;
import java.util.Collection;
+import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
@@ -20,7 +21,7 @@ import static java.util.stream.Collectors.collectingAndThen;
* @author bratseth
* @author mpolden
*/
-public class NodeList {
+public class NodeList implements Iterable<Node> {
private final List<Node> nodes;
@@ -103,4 +104,8 @@ public class NodeList {
return nodes.stream().filter(predicate).collect(collectingAndThen(Collectors.toList(), NodeList::new));
}
+ @Override
+ public Iterator<Node> iterator() {
+ return nodes.iterator();
+ }
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostDeprovisionMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostDeprovisionMaintainer.java
new file mode 100644
index 00000000000..1e4016f2112
--- /dev/null
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostDeprovisionMaintainer.java
@@ -0,0 +1,64 @@
+// 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.provision.maintenance;
+
+import com.yahoo.config.provision.NodeType;
+import com.yahoo.transaction.Mutex;
+import com.yahoo.vespa.hosted.provision.Node;
+import com.yahoo.vespa.hosted.provision.NodeList;
+import com.yahoo.vespa.hosted.provision.NodeRepository;
+import com.yahoo.vespa.hosted.provision.provisioning.HostProvisioner;
+
+import java.time.Duration;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+
+/**
+ * @author freva
+ */
+public class HostDeprovisionMaintainer extends Maintainer {
+
+ private static final Logger log = Logger.getLogger(HostDeprovisionMaintainer.class.getName());
+
+ private final HostProvisioner hostProvisioner;
+
+ public HostDeprovisionMaintainer(
+ NodeRepository nodeRepository, Duration interval, JobControl jobControl, HostProvisioner hostProvisioner) {
+ super(nodeRepository, interval, jobControl);
+ this.hostProvisioner = hostProvisioner;
+ }
+
+ @Override
+ protected void maintain() {
+ try (Mutex lock = nodeRepository().lockUnallocated()) {
+ NodeList nodes = nodeRepository().list();
+
+ for (Node node : candidates(nodes)) {
+ try {
+ hostProvisioner.deprovision(node);
+ nodeRepository().removeRecursively(node.hostname());
+ } catch (RuntimeException e) {
+ log.log(Level.WARNING, "Failed to deprovision " + node.hostname() + ", will retry in " + interval(), e);
+ }
+ }
+ }
+ }
+
+ /** @return Nodes of type host, in any state, that have no children with allocation */
+ static Set<Node> candidates(NodeList nodes) {
+ Map<String, Node> hostsByHostname = nodes.nodeType(NodeType.host)
+ .asList().stream()
+ .collect(Collectors.toMap(Node::hostname, Function.identity()));
+
+ nodes.asList().stream()
+ .filter(node -> node.allocation().isPresent())
+ .flatMap(node -> node.parentHostname().stream())
+ .distinct()
+ .forEach(hostsByHostname::remove);
+
+ return Set.copyOf(hostsByHostname.values());
+ }
+}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostProvisionMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostProvisionMaintainer.java
new file mode 100644
index 00000000000..0479f20ba37
--- /dev/null
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostProvisionMaintainer.java
@@ -0,0 +1,70 @@
+// 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.provision.maintenance;
+
+import com.yahoo.config.provision.NodeType;
+import com.yahoo.transaction.Mutex;
+import com.yahoo.vespa.hosted.provision.Node;
+import com.yahoo.vespa.hosted.provision.NodeList;
+import com.yahoo.vespa.hosted.provision.NodeRepository;
+import com.yahoo.vespa.hosted.provision.node.Agent;
+import com.yahoo.vespa.hosted.provision.provisioning.HostProvisioner;
+import com.yahoo.vespa.hosted.provision.provisioning.FatalProvisioningException;
+
+import java.time.Duration;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+
+/**
+ * @author freva
+ */
+public class HostProvisionMaintainer extends Maintainer {
+
+ private static final Logger log = Logger.getLogger(HostProvisionMaintainer.class.getName());
+
+ private final HostProvisioner hostProvisioner;
+
+ public HostProvisionMaintainer(
+ NodeRepository nodeRepository, Duration interval, JobControl jobControl, HostProvisioner hostProvisioner) {
+ super(nodeRepository, interval, jobControl);
+ this.hostProvisioner = hostProvisioner;
+ }
+
+ @Override
+ protected void maintain() {
+ try (Mutex lock = nodeRepository().lockUnallocated()) {
+ NodeList nodes = nodeRepository().list();
+
+ candidates(nodes).forEach((host, children) -> {
+ try {
+ List<Node> updatedNodes = hostProvisioner.provision(host, children);
+ nodeRepository().write(updatedNodes);
+ } catch (FatalProvisioningException e) {
+ log.log(Level.SEVERE, "Failed to provision " + host.hostname() + ", failing out the host recursively", e);
+ // Fail out as operator to force a quick redeployment
+ nodeRepository().failRecursively(
+ host.hostname(), Agent.operator, "Failed by HostProvisioner due to provisioning failure");
+ } catch (RuntimeException e) {
+ log.log(Level.WARNING, "Failed to provision " + host.hostname() + ", will retry in " + interval(), e);
+ }
+ });
+ }
+ }
+
+ /** @return map of set of children by parent Node, where parent is of type host and in state provisioned */
+ static Map<Node, Set<Node>> candidates(NodeList nodes) {
+ Map<String, Node> provisionedHostsByHostname = nodes.state(Node.State.provisioned).nodeType(NodeType.host)
+ .asList().stream()
+ .collect(Collectors.toMap(Node::hostname, Function.identity()));
+
+ return nodes.asList().stream()
+ .filter(node -> node.parentHostname().map(parent -> provisionedHostsByHostname.keySet().contains(parent)).orElse(false))
+ .collect(Collectors.groupingBy(
+ node -> provisionedHostsByHostname.get(node.parentHostname().get()),
+ Collectors.toSet()));
+ }
+}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java
index 17351ab3c10..80f6f5ccea5 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java
@@ -298,7 +298,7 @@ public class NodeFailer extends Maintainer {
// the children nodes running on it before we fail the host
boolean allTenantNodesFailedOutSuccessfully = true;
String reasonForChildFailure = "Failing due to parent host " + node.hostname() + " failure: " + reason;
- for (Node failingTenantNode : nodeRepository().list().childrenOf(node).asList()) {
+ for (Node failingTenantNode : nodeRepository().list().childrenOf(node)) {
if (failingTenantNode.state() == Node.State.active) {
allTenantNodesFailedOutSuccessfully &= failActive(failingTenantNode, reasonForChildFailure);
} else {
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java
index bf2e2dd5e74..5774176956a 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java
@@ -52,6 +52,8 @@ public class NodeRepositoryMaintenance extends AbstractComponent {
private final MetricsReporter metricsReporter;
private final InfrastructureProvisioner infrastructureProvisioner;
private final Optional<LoadBalancerExpirer> loadBalancerExpirer;
+ private final Optional<HostProvisionMaintainer> hostProvisionMaintainer;
+ private final Optional<HostDeprovisionMaintainer> hostDeprovisionMaintainer;
private final JobControl jobControl;
private final InfrastructureVersions infrastructureVersions;
@@ -90,6 +92,10 @@ public class NodeRepositoryMaintenance extends AbstractComponent {
infrastructureProvisioner = new InfrastructureProvisioner(provisioner, nodeRepository, infrastructureVersions, durationFromEnv("infrastructure_provision_interval").orElse(defaults.infrastructureProvisionInterval), jobControl, duperModelInfraApi);
loadBalancerExpirer = provisionServiceProvider.getLoadBalancerService().map(lbService ->
new LoadBalancerExpirer(nodeRepository, durationFromEnv("load_balancer_expiry").orElse(defaults.loadBalancerExpiry), jobControl, lbService));
+ hostProvisionMaintainer = provisionServiceProvider.getHostProvisioner().map(hostProvisioner ->
+ new HostProvisionMaintainer(nodeRepository, durationFromEnv("host_provisioner_interval").orElse(defaults.hostProvisionerInterval), jobControl, hostProvisioner));
+ hostDeprovisionMaintainer = provisionServiceProvider.getHostProvisioner().map(hostProvisioner ->
+ new HostDeprovisionMaintainer(nodeRepository, durationFromEnv("host_deprovisioner_interval").orElse(defaults.hostDeprovisionerInterval), jobControl, hostProvisioner));
// The DuperModel is filled with infrastructure applications by the infrastructure provisioner, so explicitly run that now
infrastructureProvisioner.maintain();
@@ -115,7 +121,9 @@ public class NodeRepositoryMaintenance extends AbstractComponent {
provisionedExpirer.deconstruct();
metricsReporter.deconstruct();
infrastructureProvisioner.deconstruct();
- loadBalancerExpirer.ifPresent(LoadBalancerExpirer::deconstruct);
+ loadBalancerExpirer.ifPresent(Maintainer::deconstruct);
+ hostProvisionMaintainer.ifPresent(Maintainer::deconstruct);
+ hostDeprovisionMaintainer.ifPresent(Maintainer::deconstruct);
}
public JobControl jobControl() { return jobControl; }
@@ -164,6 +172,8 @@ public class NodeRepositoryMaintenance extends AbstractComponent {
private final Duration retiredInterval;
private final Duration infrastructureProvisionInterval;
private final Duration loadBalancerExpiry;
+ private final Duration hostProvisionerInterval;
+ private final Duration hostDeprovisionerInterval;
private final NodeFailer.ThrottlePolicy throttlePolicy;
@@ -181,6 +191,8 @@ public class NodeRepositoryMaintenance extends AbstractComponent {
throttlePolicy = NodeFailer.ThrottlePolicy.hosted;
loadBalancerExpiry = Duration.ofHours(1);
reservationExpiry = Duration.ofMinutes(20); // Need to be long enough for deployment to be finished for all config model versions
+ hostProvisionerInterval = Duration.ofMinutes(5);
+ hostDeprovisionerInterval = Duration.ofMinutes(5);
if (zone.environment().equals(Environment.prod) && zone.system() != SystemName.cd) {
inactiveExpiry = Duration.ofHours(4); // enough time for the application owner to discover and redeploy
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Generation.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Generation.java
index e29d10f4c1f..77d0edd9d2e 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Generation.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Generation.java
@@ -43,6 +43,6 @@ public class Generation {
}
/** Returns the initial generation (0, 0) */
- public static Generation inital() { return new Generation(0, 0); }
+ public static Generation initial() { return new Generation(0, 0); }
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/IP.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/IP.java
index 14609809f54..1b438ef2bd6 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/IP.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/IP.java
@@ -207,14 +207,10 @@ public class IP {
/** Validates and returns the given set of IP addresses */
public static Set<String> requireAddresses(Set<String> addresses) {
- String message = "A node must have at least one valid IP address";
- if (addresses.isEmpty()) {
- throw new IllegalArgumentException(message);
- }
try {
addresses.forEach(InetAddresses::forString);
} catch (IllegalArgumentException e) {
- throw new IllegalArgumentException(message, e);
+ throw new IllegalArgumentException("A node must have at least one valid IP address", e);
}
return addresses;
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Status.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Status.java
index 82470787f5b..ff74e92b722 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Status.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Status.java
@@ -128,7 +128,7 @@ public class Status {
/** Returns the initial status of a newly provisioned node */
public static Status initial() {
- return new Status(Generation.inital(), Optional.empty(), 0, Optional.empty(), false,
+ return new Status(Generation.initial(), Optional.empty(), 0, Optional.empty(), false,
false, Optional.empty(), Optional.empty(), Optional.empty());
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/DockerHostCapacity.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/DockerHostCapacity.java
index c7bfb9178ce..2fcb26ea25b 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/DockerHostCapacity.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/DockerHostCapacity.java
@@ -117,7 +117,7 @@ public class DockerHostCapacity {
if (!dockerHost.type().equals(NodeType.host)) return new ResourceCapacity();
ResourceCapacity hostCapacity = new ResourceCapacity(dockerHost);
- for (Node container : allNodes.childrenOf(dockerHost).asList()) {
+ for (Node container : allNodes.childrenOf(dockerHost)) {
boolean isUsedCapacity = !(treatInactiveOrRetiredAsUnusedCapacity && isInactiveOrRetired(container));
if (isUsedCapacity) {
hostCapacity.subtract(container);
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/FatalProvisioningException.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/FatalProvisioningException.java
new file mode 100644
index 00000000000..1f38ef9b3e2
--- /dev/null
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/FatalProvisioningException.java
@@ -0,0 +1,19 @@
+// 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.provision.provisioning;
+
+/**
+ * Thrown by {@link HostProvisioner} to indicate that the provisioning of a host has
+ * irrecoverably failed. The host should be deprovisioned and (together with its children)
+ * removed from the node-repository.
+ *
+ * @author freva
+ */
+public class FatalProvisioningException extends RuntimeException {
+ public FatalProvisioningException(String message) {
+ super(message);
+ }
+
+ public FatalProvisioningException(String message, Exception cause) {
+ super(message, cause);
+ }
+}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostProvisioner.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostProvisioner.java
index d905282ef0b..d82e3900e76 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostProvisioner.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostProvisioner.java
@@ -5,15 +5,46 @@ import com.yahoo.config.provision.Flavor;
import com.yahoo.vespa.hosted.provision.Node;
import java.util.List;
+import java.util.Set;
/**
+ * Service for provisioning physical docker tenant hosts inside the zone.
+ *
* @author freva
*/
public interface HostProvisioner {
- List<Node> provisionHosts(int numHosts, Flavor nodeFlavor, int numNodesOnHost);
+ /**
+ * Schedule provisioning of a given number of hosts.
+ *
+ * @param numHosts number of hosts to provision
+ * @param nodeFlavor Vespa flavor of the node that will run on this host. The resulting provisioned host
+ * will be of a flavor that is at least as big or bigger than this.
+ * @return list of nodes that should be added to the node-repo, the list will contain exactly 2 elements:
+ * the provisioned host, and a docker container on that host with flavor {@code nodeFlavor}
+ */
+ List<Node> provisionHosts(int numHosts, Flavor nodeFlavor);
- void provisioning(Node node);
+ /**
+ * Continue provisioning of given list of Nodes.
+ *
+ * @param host the host to provision
+ * @param children list of all the nodes that run on the given host
+ * @return a subset of {@code host} and {@code children} where the values have been modified and should
+ * be written back to node-repository.
+ * @throws FatalProvisioningException if the provisioning has irrecoverably failed and the input nodes
+ * should be deleted from node-repo.
+ */
+ List<Node> provision(Node host, Set<Node> children) throws FatalProvisioningException;
- void deprovision(Node node);
+ /**
+ * Deprovisions a given host and resources associated with it and its children (such as DNS entries).
+ * This method will only perform the actual deprovisioning of the host and does NOT:
+ * - verify whether it is safe to do
+ * - clean up config server references to this node or any of its children
+ * Therefore, this method should probably only be called for hosts that have no children.
+ *
+ * @param host host to deprovision.
+ */
+ void deprovision(Node host);
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java
index 5e98466fd7c..990cc575178 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java
@@ -161,7 +161,7 @@ class NodeAllocation {
*/
private boolean exclusiveTo(TenantName tenant, Optional<String> parentHostname) {
if ( ! parentHostname.isPresent()) return true;
- for (Node nodeOnHost : nodeRepository.list().childrenOf(parentHostname.get()).asList()) {
+ for (Node nodeOnHost : nodeRepository.list().childrenOf(parentHostname.get())) {
if ( ! nodeOnHost.allocation().isPresent()) continue;
if ( nodeOnHost.allocation().get().membership().cluster().isExclusive() &&
@@ -174,7 +174,7 @@ class NodeAllocation {
private boolean hostsOnly(TenantName tenant, Optional<String> parentHostname) {
if ( ! parentHostname.isPresent()) return true; // yes, as host is exclusive
- for (Node nodeOnHost : nodeRepository.list().childrenOf(parentHostname.get()).asList()) {
+ for (Node nodeOnHost : nodeRepository.list().childrenOf(parentHostname.get())) {
if ( ! nodeOnHost.allocation().isPresent()) continue;
if ( ! nodeOnHost.allocation().get().owner().tenant().equals(tenant))
return false;
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostDeprovisionMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostDeprovisionMaintainerTest.java
new file mode 100644
index 00000000000..95c857527a1
--- /dev/null
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostDeprovisionMaintainerTest.java
@@ -0,0 +1,98 @@
+// 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.provision.maintenance;
+
+import com.yahoo.config.provision.NodeType;
+import com.yahoo.vespa.hosted.provision.Node;
+import com.yahoo.vespa.hosted.provision.NodeList;
+import com.yahoo.vespa.hosted.provision.provisioning.HostProvisioner;
+import org.junit.Test;
+
+import java.time.Duration;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+import static com.yahoo.vespa.hosted.provision.maintenance.HostProvisionMaintainerTest.HostProvisionerTester;
+import static com.yahoo.vespa.hosted.provision.maintenance.HostProvisionMaintainerTest.HostProvisionerTester.createNode;
+import static com.yahoo.vespa.hosted.provision.maintenance.HostProvisionMaintainerTest.HostProvisionerTester.proxyApp;
+import static com.yahoo.vespa.hosted.provision.maintenance.HostProvisionMaintainerTest.HostProvisionerTester.proxyHostApp;
+import static com.yahoo.vespa.hosted.provision.maintenance.HostProvisionMaintainerTest.HostProvisionerTester.tenantApp;
+import static com.yahoo.vespa.hosted.provision.maintenance.HostProvisionMaintainerTest.HostProvisionerTester.tenantHostApp;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+/**
+ * @author freva
+ */
+public class HostDeprovisionMaintainerTest {
+ private final HostProvisionerTester tester = new HostProvisionerTester();
+ private final HostProvisioner hostProvisioner = mock(HostProvisioner.class);
+ private final HostDeprovisionMaintainer maintainer = new HostDeprovisionMaintainer(
+ tester.nodeRepository(), Duration.ofDays(1), tester.jobControl(), hostProvisioner);
+
+ @Test
+ public void removes_nodes_if_successful() {
+ tester.addNode("host1", Optional.empty(), NodeType.host, Node.State.active, Optional.of(tenantHostApp));
+ tester.addNode("host1-1", Optional.of("host1"), NodeType.tenant, Node.State.reserved, Optional.of(tenantApp));
+ tester.addNode("host1-2", Optional.of("host1"), NodeType.tenant, Node.State.failed, Optional.empty());
+ tester.addNode("host4", Optional.empty(), NodeType.host, Node.State.provisioned, Optional.empty());
+ tester.addNode("host4-1", Optional.of("host4"), NodeType.tenant, Node.State.reserved, Optional.of(tenantApp));
+
+ Node host2 = tester.addNode("host2", Optional.empty(), NodeType.host, Node.State.failed, Optional.of(tenantApp));
+ tester.addNode("host2-1", Optional.of("host2"), NodeType.tenant, Node.State.failed, Optional.empty());
+
+ assertEquals(7, tester.nodeRepository().getNodes().size());
+
+ maintainer.maintain();
+
+ assertEquals(5, tester.nodeRepository().getNodes().size());
+ verify(hostProvisioner).deprovision(eq(host2));
+ verifyNoMoreInteractions(hostProvisioner);
+
+ assertTrue(tester.nodeRepository().getNode("host2").isEmpty());
+ assertTrue(tester.nodeRepository().getNode("host2-1").isEmpty());
+ }
+
+ @Test
+ public void does_not_remove_if_failed() {
+ Node host2 = tester.addNode("host2", Optional.empty(), NodeType.host, Node.State.failed, Optional.of(tenantApp));
+ doThrow(new RuntimeException()).when(hostProvisioner).deprovision(eq(host2));
+
+ maintainer.maintain();
+
+ assertEquals(1, tester.nodeRepository().getNodes().size());
+ verify(hostProvisioner).deprovision(eq(host2));
+ verifyNoMoreInteractions(hostProvisioner);
+ }
+
+ @Test
+ public void finds_nodes_that_need_deprovisioning() {
+ Node host2 = createNode("host2", Optional.empty(), NodeType.host, Node.State.failed, Optional.of(tenantApp));
+ Node host21 = createNode("host2-1", Optional.of("host2"), NodeType.tenant, Node.State.failed, Optional.empty());
+ Node host3 = createNode("host3", Optional.empty(), NodeType.host, Node.State.provisioned, Optional.empty());
+
+ List<Node> nodes = List.of(
+ createNode("host1", Optional.empty(), NodeType.host, Node.State.active, Optional.of(tenantHostApp)),
+ createNode("host1-1", Optional.of("host1"), NodeType.tenant, Node.State.reserved, Optional.of(tenantApp)),
+ createNode("host1-2", Optional.of("host1"), NodeType.tenant, Node.State.failed, Optional.empty()),
+
+ host2, host21, host3,
+
+ createNode("host4", Optional.empty(), NodeType.host, Node.State.provisioned, Optional.empty()),
+ createNode("host4-1", Optional.of("host4"), NodeType.tenant, Node.State.reserved, Optional.of(tenantApp)),
+
+ createNode("proxyhost1", Optional.empty(), NodeType.proxyhost, Node.State.provisioned, Optional.empty()),
+
+ createNode("proxyhost2", Optional.empty(), NodeType.proxyhost, Node.State.active, Optional.of(proxyHostApp)),
+ createNode("proxy2", Optional.of("proxyhost2"), NodeType.proxy, Node.State.active, Optional.of(proxyApp)));
+
+ Set<Node> expected = Set.of(host2, host3);
+ Set<Node> actual = HostDeprovisionMaintainer.candidates(new NodeList(nodes));
+ assertEquals(expected, actual);
+ }
+} \ No newline at end of file
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostProvisionMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostProvisionMaintainerTest.java
new file mode 100644
index 00000000000..01c83bbeff4
--- /dev/null
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostProvisionMaintainerTest.java
@@ -0,0 +1,157 @@
+package com.yahoo.vespa.hosted.provision.maintenance;
+
+import com.yahoo.component.Version;
+import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.ClusterMembership;
+import com.yahoo.config.provision.DockerImage;
+import com.yahoo.config.provision.Flavor;
+import com.yahoo.config.provision.NodeFlavors;
+import com.yahoo.config.provision.NodeType;
+import com.yahoo.config.provision.Zone;
+import com.yahoo.test.ManualClock;
+import com.yahoo.vespa.curator.mock.MockCurator;
+import com.yahoo.vespa.hosted.provision.Node;
+import com.yahoo.vespa.hosted.provision.NodeList;
+import com.yahoo.vespa.hosted.provision.NodeRepository;
+import com.yahoo.vespa.hosted.provision.node.Allocation;
+import com.yahoo.vespa.hosted.provision.node.Generation;
+import com.yahoo.vespa.hosted.provision.node.History;
+import com.yahoo.vespa.hosted.provision.node.Status;
+import com.yahoo.vespa.hosted.provision.provisioning.FlavorConfigBuilder;
+import com.yahoo.vespa.hosted.provision.provisioning.HostProvisioner;
+import com.yahoo.vespa.hosted.provision.provisioning.FatalProvisioningException;
+import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver;
+import org.junit.Test;
+
+import java.time.Duration;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static com.yahoo.vespa.hosted.provision.maintenance.HostProvisionMaintainerTest.HostProvisionerTester.createNode;
+import static com.yahoo.vespa.hosted.provision.maintenance.HostProvisionMaintainerTest.HostProvisionerTester.proxyApp;
+import static com.yahoo.vespa.hosted.provision.maintenance.HostProvisionMaintainerTest.HostProvisionerTester.proxyHostApp;
+import static com.yahoo.vespa.hosted.provision.maintenance.HostProvisionMaintainerTest.HostProvisionerTester.tenantApp;
+import static com.yahoo.vespa.hosted.provision.maintenance.HostProvisionMaintainerTest.HostProvisionerTester.tenantHostApp;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author freva
+ */
+public class HostProvisionMaintainerTest {
+
+ private final HostProvisionerTester tester = new HostProvisionerTester();
+ private final HostProvisioner hostProvisioner = mock(HostProvisioner.class);
+ private final HostProvisionMaintainer maintainer = new HostProvisionMaintainer(
+ tester.nodeRepository(), Duration.ofDays(1), tester.jobControl(), hostProvisioner);
+
+ @Test
+ public void delegates_to_host_provisioner_and_writes_back_result() {
+ tester.addNode("host1", Optional.empty(), NodeType.host, Node.State.active, Optional.of(tenantHostApp));
+ tester.addNode("host1-1", Optional.of("host1"), NodeType.tenant, Node.State.reserved, Optional.of(tenantApp));
+ tester.addNode("host1-2", Optional.of("host1"), NodeType.tenant, Node.State.failed, Optional.empty());
+ tester.addNode("host2", Optional.empty(), NodeType.host, Node.State.failed, Optional.of(tenantApp));
+
+ Node host4 = tester.addNode("host4", Optional.empty(), NodeType.host, Node.State.provisioned, Optional.empty());
+ Node host41 = tester.addNode("host4-1", Optional.of("host4"), NodeType.tenant, Node.State.reserved, Optional.of(tenantApp));
+
+ Node host4new = host4.withIpAddresses(Set.of("::2"));
+ Node host41new = host41.withIpAddresses(Set.of("::4", "10.0.0.1"));
+ assertTrue(Stream.of(host4, host41).map(Node::ipAddresses).allMatch(Set::isEmpty));
+ when(hostProvisioner.provision(eq(host4), eq(Set.of(host41)))).thenReturn(List.of(host4new, host41new));
+
+ maintainer.maintain();
+ verify(hostProvisioner).provision(eq(host4), eq(Set.of(host41)));
+ verifyNoMoreInteractions(hostProvisioner);
+
+ assertEquals(Optional.of(host4new), tester.nodeRepository().getNode("host4"));
+ assertEquals(Optional.of(host41new), tester.nodeRepository().getNode("host4-1"));
+ }
+
+ @Test
+ public void correctly_fails_if_irrecoverable_failure() {
+ Node host4 = tester.addNode("host4", Optional.empty(), NodeType.host, Node.State.provisioned, Optional.empty());
+ Node host41 = tester.addNode("host4-1", Optional.of("host4"), NodeType.tenant, Node.State.reserved, Optional.of(tenantApp));
+
+ assertTrue(Stream.of(host4, host41).map(Node::ipAddresses).allMatch(Set::isEmpty));
+ when(hostProvisioner.provision(eq(host4), eq(Set.of(host41)))).thenThrow(new FatalProvisioningException("Fatal"));
+
+ maintainer.maintain();
+
+ assertEquals(Set.of("host4", "host4-1"),
+ tester.nodeRepository().getNodes(Node.State.failed).stream().map(Node::hostname).collect(Collectors.toSet()));
+ }
+
+ @Test
+ public void finds_nodes_that_need_provisioning() {
+ Node host4 = createNode("host4", Optional.empty(), NodeType.host, Node.State.provisioned, Optional.empty());
+ Node host41 = createNode("host4-1", Optional.of("host4"), NodeType.tenant, Node.State.reserved, Optional.of(tenantApp));
+
+ List<Node> nodes = List.of(
+ createNode("host1", Optional.empty(), NodeType.host, Node.State.active, Optional.of(tenantHostApp)),
+ createNode("host1-1", Optional.of("host1"), NodeType.tenant, Node.State.reserved, Optional.of(tenantApp)),
+ createNode("host1-2", Optional.of("host1"), NodeType.tenant, Node.State.failed, Optional.empty()),
+
+ createNode("host2", Optional.empty(), NodeType.host, Node.State.failed, Optional.of(tenantApp)),
+
+ createNode("host3", Optional.empty(), NodeType.host, Node.State.provisioned, Optional.empty()),
+
+ host4, host41,
+
+ createNode("proxyhost1", Optional.empty(), NodeType.proxyhost, Node.State.provisioned, Optional.empty()),
+
+ createNode("proxyhost2", Optional.empty(), NodeType.proxyhost, Node.State.active, Optional.of(proxyHostApp)),
+ createNode("proxy2", Optional.of("proxyhost2"), NodeType.proxy, Node.State.active, Optional.of(proxyApp)));
+
+ Map<Node, Set<Node>> expected = Map.of(host4, Set.of(host41));
+ Map<Node, Set<Node>> actual = HostProvisionMaintainer.candidates(new NodeList(nodes));
+ assertEquals(expected, actual);
+ }
+
+ static class HostProvisionerTester {
+ private static final NodeFlavors nodeFlavors = FlavorConfigBuilder.createDummies("default", "docker");
+ static final ApplicationId tenantApp = ApplicationId.from("mytenant", "myapp", "default");
+ static final ApplicationId tenantHostApp = ApplicationId.from("vespa", "tenant-host", "default");
+ static final ApplicationId proxyHostApp = ApplicationId.from("vespa", "proxy-host", "default");
+ static final ApplicationId proxyApp = ApplicationId.from("vespa", "proxy", "default");
+
+ private final ManualClock clock = new ManualClock();
+ private final NodeRepository nodeRepository = new NodeRepository(
+ nodeFlavors, new MockCurator(), clock, Zone.defaultZone(), new MockNameResolver().mockAnyLookup(), new DockerImage("docker-image"), true);
+
+ Node addNode(String hostname, Optional<String> parentHostname, NodeType nodeType, Node.State state, Optional<ApplicationId> application) {
+ Node node = createNode(hostname, parentHostname, nodeType, state, application);
+ return nodeRepository.database().addNodesInState(List.of(node), node.state()).get(0);
+ }
+
+ static Node createNode(String hostname, Optional<String> parentHostname, NodeType nodeType, Node.State state, Optional<ApplicationId> application) {
+ Flavor flavor = nodeFlavors.getFlavor(parentHostname.isPresent() ? "docker" : "default").orElseThrow();
+ Optional<Allocation> allocation = application
+ .map(app -> new Allocation(
+ app,
+ ClusterMembership.from("container/default/0/0", Version.fromString("7.3")),
+ Generation.initial(),
+ false));
+ Set<String> ips = state == Node.State.active ? Set.of("::1") : Set.of();
+ return new Node("fake-id-" + hostname, ips, Set.of(), hostname,
+ parentHostname, flavor, Status.initial(), state, allocation, History.empty(), nodeType);
+ }
+
+ NodeRepository nodeRepository() {
+ return nodeRepository;
+ }
+
+ JobControl jobControl() {
+ return new JobControl(nodeRepository.database());
+ }
+ }
+} \ No newline at end of file
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/monitoring/MetricsReporterTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/monitoring/MetricsReporterTest.java
index de181c2d7e1..6b45352adba 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/monitoring/MetricsReporterTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/monitoring/MetricsReporterTest.java
@@ -198,7 +198,7 @@ public class MetricsReporterTest {
if (tenant.isPresent()) {
Allocation allocation = new Allocation(app(tenant.get()),
ClusterMembership.from("container/id1/0/3", new Version()),
- Generation.inital(),
+ Generation.initial(),
false);
return Optional.of(allocation);
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AllocationSimulator.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AllocationSimulator.java
index 134448971fb..dc936b0f29f 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AllocationSimulator.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AllocationSimulator.java
@@ -96,7 +96,7 @@ public class AllocationSimulator {
if (tenant.isPresent()) {
Allocation allocation = new Allocation(app(tenant.get()),
ClusterMembership.from("container/id1/3", new Version()),
- Generation.inital(),
+ Generation.initial(),
false);
return Optional.of(allocation);
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AllocationVisualizer.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AllocationVisualizer.java
index 24011bd4b49..61e14be53d8 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AllocationVisualizer.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AllocationVisualizer.java
@@ -76,14 +76,14 @@ public class AllocationVisualizer extends JPanel {
// Draw the docker hosts - and color each container according to application
AllocationSnapshot simStep = steps.get(step);
NodeList hosts = simStep.nodes.nodeType(NodeType.host);
- for (Node host : hosts.asList()) {
+ for (Node host : hosts) {
// Paint the host
paintNode(host, g, nodeX, nodeY, true);
// Paint containers
NodeList containers = simStep.nodes.childrenOf(host);
- for (Node container : containers.asList()) {
+ for (Node container : containers) {
nodeY = paintNode(container, g, nodeX, nodeY, false);
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java
index 85ecf9c5073..0003e4f23cc 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java
@@ -166,17 +166,17 @@ public class DockerProvisioningTest {
ApplicationId application1 = tester.makeApplicationId();
prepareAndActivate(application1, 2, false, tester);
- for (Node node : tester.getNodes(application1, Node.State.active).asList())
+ for (Node node : tester.getNodes(application1, Node.State.active))
assertFalse(node.allocation().get().membership().cluster().isExclusive());
prepareAndActivate(application1, 2, true, tester);
assertEquals(setOf("host1", "host2"), hostsOf(tester.getNodes(application1, Node.State.active)));
- for (Node node : tester.getNodes(application1, Node.State.active).asList())
+ for (Node node : tester.getNodes(application1, Node.State.active))
assertTrue(node.allocation().get().membership().cluster().isExclusive());
prepareAndActivate(application1, 2, false, tester);
assertEquals(setOf("host1", "host2"), hostsOf(tester.getNodes(application1, Node.State.active)));
- for (Node node : tester.getNodes(application1, Node.State.active).asList())
+ for (Node node : tester.getNodes(application1, Node.State.active))
assertFalse(node.allocation().get().membership().cluster().isExclusive());
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/MultigroupProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/MultigroupProvisioningTest.java
index 86daf636875..308127c7f39 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/MultigroupProvisioningTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/MultigroupProvisioningTest.java
@@ -166,7 +166,7 @@ public class MultigroupProvisioningTest {
// Check invariants for all nodes
Set<Integer> allIndexes = new HashSet<>();
- for (Node node : tester.getNodes(application, Node.State.active).asList()) {
+ for (Node node : tester.getNodes(application, Node.State.active)) {
// Node indexes must be unique
int index = node.allocation().get().membership().index();
assertFalse("Node indexes are unique", allIndexes.contains(index));
@@ -178,7 +178,7 @@ public class MultigroupProvisioningTest {
// Count unretired nodes and groups of the requested flavor
Set<Integer> indexes = new HashSet<>();
Map<ClusterSpec.Group, Integer> nonretiredGroups = new HashMap<>();
- for (Node node : tester.getNodes(application, Node.State.active).nonretired().flavor(flavor).asList()) {
+ for (Node node : tester.getNodes(application, Node.State.active).nonretired().flavor(flavor)) {
indexes.add(node.allocation().get().membership().index());
ClusterSpec.Group group = node.allocation().get().membership().cluster().group().get();
@@ -193,7 +193,7 @@ public class MultigroupProvisioningTest {
assertEquals("Group size", (long)nodeCount / wantedGroups, (long)groupSize);
Map<ClusterSpec.Group, Integer> allGroups = new HashMap<>();
- for (Node node : tester.getNodes(application, Node.State.active).flavor(flavor).asList()) {
+ for (Node node : tester.getNodes(application, Node.State.active).flavor(flavor)) {
ClusterSpec.Group group = node.allocation().get().membership().cluster().group().get();
allGroups.put(group, nonretiredGroups.getOrDefault(group, 0) + 1);
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java
index 0f86b072d4d..fabc842c377 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java
@@ -279,8 +279,8 @@ public class ProvisioningTest {
SystemState state2 = prepare(application1, 2, 2, 4, 4, "dockerSmall", tester);
tester.activate(application1, state2.allHosts);
- assertEquals(12, tester.getNodes(application1, Node.State.active).asList().size());
- for (Node node : tester.getNodes(application1, Node.State.active).asList())
+ assertEquals(12, tester.getNodes(application1, Node.State.active).size());
+ for (Node node : tester.getNodes(application1, Node.State.active))
assertEquals("Node changed flavor in place", "dockerSmall", node.flavor().name());
assertEquals("No nodes are retired",
0, tester.getNodes(application1, Node.State.active).retired().size());
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/filter/NodeIdentifierTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/filter/NodeIdentifierTest.java
index 624845cc5e0..c3d320119f4 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/filter/NodeIdentifierTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/filter/NodeIdentifierTest.java
@@ -245,7 +245,7 @@ public class NodeIdentifierTest {
Version.emptyVersion,
false),
clusterIndex),
- Generation.inital(),
+ Generation.initial(),
false));
}