summaryrefslogtreecommitdiffstats
path: root/node-repository
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2020-10-22 11:19:21 +0200
committerMartin Polden <mpolden@mpolden.no>2020-10-22 11:59:36 +0200
commit39591a2bc7fc65ecfca542408dceed009ea761dd (patch)
tree596fe4431f0e69624cf4cc5db750c44436f40ebc /node-repository
parent56711cbcb5e54ffe5fc515247b5855f3226f328e (diff)
Require non-empty IP address pool when readying tenant host
Diffstat (limited to 'node-repository')
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/Node.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooter.java3
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/IP.java4
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java45
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceTester.java81
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java20
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java44
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooterTest.java102
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OperatorChangeApplicationMaintainerTest.java93
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java76
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ReservationExpirerTest.java47
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java99
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java24
15 files changed, 173 insertions, 471 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 21f28f8385a..e288f08a681 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
@@ -89,7 +89,7 @@ public final class Node implements Nodelike {
requireNonEmpty(ipConfig.primary(), "Active node " + hostname + " must have at least one valid IP address");
if (parentHostname.isPresent()) {
- if (!ipConfig.pool().asSet().isEmpty()) throw new IllegalArgumentException("A child node cannot have an IP address pool");
+ if (!ipConfig.pool().isEmpty()) throw new IllegalArgumentException("A child node cannot have an IP address pool");
if (modelName.isPresent()) throw new IllegalArgumentException("A child node cannot have model name set");
if (switchHostname.isPresent()) throw new IllegalArgumentException("A child node cannot have switch hostname set");
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java
index 71d88dca027..fd7dbc9716b 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java
@@ -460,6 +460,8 @@ public class NodeRepository extends AbstractComponent {
.map(node -> {
if (node.state() != State.provisioned && node.state() != State.dirty)
illegal("Can not set " + node + " ready. It is not provisioned or dirty.");
+ if (node.type() == NodeType.host && node.ipConfig().pool().isEmpty())
+ illegal("Can not set host " + node + " ready. Its IP address pool is empty.");
return node.withWantToRetire(false, false, Agent.system, clock.instant());
})
.collect(Collectors.toList());
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooter.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooter.java
index f64f27b1219..c76239527bd 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooter.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooter.java
@@ -1,7 +1,6 @@
// 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.provision.maintenance;
-import com.yahoo.config.provision.Flavor;
import com.yahoo.jdisc.Metric;
import com.yahoo.vespa.flags.FlagSource;
import com.yahoo.vespa.flags.Flags;
@@ -44,7 +43,7 @@ public class NodeRebooter extends NodeRepositoryMaintainer {
protected boolean maintain() {
// Reboot candidates: Nodes in long-term states, where we know we can safely orchestrate a reboot
List<Node> nodesToReboot = nodeRepository().getNodes(Node.State.active, Node.State.ready).stream()
- .filter(node -> node.flavor().getType() != Flavor.Type.DOCKER_CONTAINER)
+ .filter(node -> node.type().isHost())
.filter(this::shouldReboot)
.collect(Collectors.toList());
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 b632d3d4342..6b2e1da0432 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
@@ -258,6 +258,10 @@ public class IP {
return addresses.asSet();
}
+ public boolean isEmpty() {
+ return asSet().isEmpty();
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java
index 0a78ead5ca9..58a8edb4631 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java
@@ -6,7 +6,6 @@ import com.yahoo.config.provision.ApplicationName;
import com.yahoo.config.provision.Capacity;
import com.yahoo.config.provision.ClusterResources;
import com.yahoo.config.provision.ClusterSpec;
-import com.yahoo.config.provision.DockerImage;
import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.Flavor;
import com.yahoo.config.provision.HostSpec;
@@ -20,19 +19,16 @@ import com.yahoo.config.provision.TenantName;
import com.yahoo.config.provision.Zone;
import com.yahoo.test.ManualClock;
import com.yahoo.transaction.NestedTransaction;
-import com.yahoo.vespa.curator.mock.MockCurator;
+import com.yahoo.vespa.curator.Curator;
import com.yahoo.vespa.curator.transaction.CuratorTransaction;
-import com.yahoo.vespa.flags.InMemoryFlagSource;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.node.Report;
import com.yahoo.vespa.hosted.provision.node.Reports;
-import com.yahoo.vespa.hosted.provision.provisioning.EmptyProvisionServiceProvider;
import com.yahoo.vespa.hosted.provision.provisioning.FlavorConfigBuilder;
import com.yahoo.vespa.hosted.provision.provisioning.NodeRepositoryProvisioner;
-import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver;
-import com.yahoo.vespa.hosted.provision.testutils.MockProvisionServiceProvider;
+import com.yahoo.vespa.hosted.provision.provisioning.ProvisioningTester;
import org.junit.Test;
import java.time.Duration;
@@ -40,7 +36,6 @@ import java.time.Instant;
import java.util.List;
import java.util.Optional;
import java.util.Set;
-import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -239,8 +234,8 @@ public class FailedExpirerTest {
public static final NodeResources defaultFlavor = new NodeResources(2, 8, 100, 2);
public static final NodeResources dockerFlavor = new NodeResources(1, 4, 50, 1);
- private final MockCurator curator = new MockCurator();
- private final ManualClock clock = new ManualClock();
+ private final Curator curator;
+ private final ManualClock clock;
private final ApplicationId applicationId = ApplicationId.from(TenantName.from("foo"),
ApplicationName.from("bar"),
InstanceName.from("default"));
@@ -248,20 +243,17 @@ public class FailedExpirerTest {
private final NodeRepository nodeRepository;
private final NodeRepositoryProvisioner provisioner;
private final FailedExpirer expirer;
+ private final ProvisioningTester tester;
public FailureScenario(SystemName system, Environment environment) {
Zone zone = new Zone(system, environment, RegionName.defaultName());
- this.nodeRepository = new NodeRepository(nodeFlavors,
- new EmptyProvisionServiceProvider(),
- curator,
- clock,
- zone,
- new MockNameResolver().mockAnyLookup(),
- DockerImage.fromString("registry.example.com/docker-image"),
- new InMemoryFlagSource(),
- true,
- 0, 1000);
- this.provisioner = new NodeRepositoryProvisioner(nodeRepository, zone, new MockProvisionServiceProvider(), new InMemoryFlagSource());
+ this.tester = new ProvisioningTester.Builder().zone(zone)
+ .flavors(nodeFlavors.getFlavors())
+ .build();
+ this.curator = tester.getCurator();
+ this.clock = tester.clock();
+ this.nodeRepository = tester.nodeRepository();
+ this.provisioner = tester.provisioner();
this.expirer = new FailedExpirer(nodeRepository, zone, clock, Duration.ofMinutes(30), new TestMetric());
}
@@ -278,13 +270,12 @@ public class FailedExpirerTest {
.orElseThrow(() -> new IllegalArgumentException("No such node: " + hostname));
}
- public FailureScenario withNode(NodeType type, NodeResources flavor, String hostname, String parentHostname) {
- nodeRepository.addNodes(List.of(nodeRepository.createNode(UUID.randomUUID().toString(),
- hostname,
- Optional.ofNullable(parentHostname),
- new Flavor(flavor),
- type)),
- Agent.system);
+ public FailureScenario withNode(NodeType type, NodeResources resources, String hostname, String parentHostname) {
+ if (parentHostname != null) {
+ tester.makeReadyVirtualNodes(1, 0, resources, Optional.of(parentHostname), (index) -> hostname);
+ } else {
+ tester.makeProvisionedNodes(1, (index) -> hostname, new Flavor(resources), Optional.empty(), type, 0, false);
+ }
return this;
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceTester.java
deleted file mode 100644
index 106d1b11a13..00000000000
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceTester.java
+++ /dev/null
@@ -1,81 +0,0 @@
-// 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.provision.maintenance;
-
-import com.yahoo.config.provision.DockerImage;
-import com.yahoo.config.provision.Environment;
-import com.yahoo.config.provision.NodeFlavors;
-import com.yahoo.config.provision.NodeType;
-import com.yahoo.config.provision.RegionName;
-import com.yahoo.config.provision.Zone;
-import com.yahoo.test.ManualClock;
-import com.yahoo.vespa.curator.mock.MockCurator;
-import com.yahoo.vespa.flags.InMemoryFlagSource;
-import com.yahoo.vespa.hosted.provision.Node;
-import com.yahoo.vespa.hosted.provision.NodeRepository;
-import com.yahoo.vespa.hosted.provision.node.Agent;
-import com.yahoo.vespa.hosted.provision.provisioning.EmptyProvisionServiceProvider;
-import com.yahoo.vespa.hosted.provision.provisioning.FlavorConfigBuilder;
-import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver;
-
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-/**
- * Generic maintenance tester
- *
- * @author bratseth
- */
-public class MaintenanceTester {
-
- private final MockCurator curator = new MockCurator();
- public final ManualClock clock = new ManualClock(Instant.ofEpochMilli(0L)); // determinism
- private final Zone zone = new Zone(Environment.prod, RegionName.from("us-east"));
- private final NodeFlavors nodeFlavors = FlavorConfigBuilder.createDummies("default");
- public final NodeRepository nodeRepository = new NodeRepository(nodeFlavors,
- new EmptyProvisionServiceProvider(),
- curator,
- clock,
- zone,
- new MockNameResolver().mockAnyLookup(),
- DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"),
- new InMemoryFlagSource(),
- true,
- 0, 1000);
-
- public MaintenanceTester() {
- curator.setZooKeeperEnsembleConnectionSpec("zk1.host:1,zk2.host:2,zk3.host:3");
- }
-
- public NodeRepository nodeRepository() { return nodeRepository; }
-
- public void createReadyTenantNodes(int count) {
- List<Node> nodes = new ArrayList<>(count);
- for (int i = 0; i < count; i++)
- nodes.add(nodeRepository.createNode("node" + i, "host" + i, Optional.empty(), nodeFlavors.getFlavorOrThrow("default"), NodeType.tenant));
- nodes = nodeRepository.addNodes(nodes, Agent.system);
- nodes = nodeRepository.setDirty(nodes, Agent.system, getClass().getSimpleName());
- nodes = simulateInitialReboot(nodes);
- nodeRepository.setReady(nodes, Agent.system, getClass().getSimpleName());
- }
-
- public void createReadyHostNodes(int count) {
- List<Node> nodes = new ArrayList<>(count);
- for (int i = 0; i < count; i++)
- nodes.add(nodeRepository.createNode("hostNode" + i, "realHost" + i, Optional.empty(), nodeFlavors.getFlavorOrThrow("default"), NodeType.host));
- nodes = nodeRepository.addNodes(nodes, Agent.system);
- nodes = nodeRepository.setDirty(nodes, Agent.system, getClass().getSimpleName());
- nodes = simulateInitialReboot(nodes);
- nodeRepository.setReady(nodes, Agent.system, getClass().getSimpleName());
- }
-
- /** Simulate the initial reboot the node performs when it's in dirty */
- private List<Node> simulateInitialReboot(List<Node> nodes) {
- return nodes.stream()
- .map(n -> n.withCurrentRebootGeneration(n.status().reboot().wanted(), Instant.now(clock)))
- .collect(Collectors.toList());
- }
-
-}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java
index 6ae5e667134..a7c04636662 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java
@@ -28,6 +28,7 @@ import com.yahoo.vespa.hosted.provision.node.Generation;
import com.yahoo.vespa.hosted.provision.node.IP;
import com.yahoo.vespa.hosted.provision.provisioning.EmptyProvisionServiceProvider;
import com.yahoo.vespa.hosted.provision.provisioning.FlavorConfigBuilder;
+import com.yahoo.vespa.hosted.provision.provisioning.ProvisioningTester;
import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver;
import com.yahoo.vespa.orchestrator.Orchestrator;
import com.yahoo.vespa.orchestrator.status.HostInfo;
@@ -80,21 +81,10 @@ public class MetricsReporterTest {
@Test
public void test_registered_metric() {
NodeFlavors nodeFlavors = FlavorConfigBuilder.createDummies("default");
- Curator curator = new MockCurator();
- NodeRepository nodeRepository = new NodeRepository(nodeFlavors,
- new EmptyProvisionServiceProvider(),
- curator,
- Clock.systemUTC(),
- Zone.defaultZone(),
- new MockNameResolver().mockAnyLookup(),
- DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"),
- new InMemoryFlagSource(),
- true,
- 0, 1000);
- Node node = nodeRepository.createNode("openStackId", "hostname", Optional.empty(), nodeFlavors.getFlavorOrThrow("default"), NodeType.tenant);
- nodeRepository.addNodes(List.of(node), Agent.system);
- Node hostNode = nodeRepository.createNode("openStackId2", "parent", Optional.empty(), nodeFlavors.getFlavorOrThrow("default"), NodeType.proxy);
- nodeRepository.addNodes(List.of(hostNode), Agent.system);
+ ProvisioningTester tester = new ProvisioningTester.Builder().flavors(nodeFlavors.getFlavors()).build();
+ NodeRepository nodeRepository = tester.nodeRepository();
+ tester.makeProvisionedNodes(1, "default", NodeType.tenant, 0);
+ tester.makeProvisionedNodes(1, "default", NodeType.proxy, 0);
Map<String, Number> expectedMetrics = new TreeMap<>();
expectedMetrics.put("hostedVespa.provisionedHosts", 1);
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java
index 1c044a8dfa6..5117a7b7397 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java
@@ -5,31 +5,24 @@ import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.Capacity;
import com.yahoo.config.provision.ClusterResources;
import com.yahoo.config.provision.ClusterSpec;
-import com.yahoo.config.provision.DockerImage;
-import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.Flavor;
import com.yahoo.config.provision.HostSpec;
import com.yahoo.config.provision.NodeFlavors;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
-import com.yahoo.config.provision.RegionName;
-import com.yahoo.config.provision.Zone;
import com.yahoo.test.ManualClock;
import com.yahoo.transaction.NestedTransaction;
import com.yahoo.vespa.applicationmodel.HostName;
import com.yahoo.vespa.curator.Curator;
-import com.yahoo.vespa.curator.mock.MockCurator;
import com.yahoo.vespa.curator.transaction.CuratorTransaction;
-import com.yahoo.vespa.flags.InMemoryFlagSource;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.node.Agent;
-import com.yahoo.vespa.hosted.provision.provisioning.EmptyProvisionServiceProvider;
+import com.yahoo.vespa.hosted.provision.node.IP;
import com.yahoo.vespa.hosted.provision.provisioning.FlavorConfigBuilder;
import com.yahoo.vespa.hosted.provision.provisioning.NodeRepositoryProvisioner;
+import com.yahoo.vespa.hosted.provision.provisioning.ProvisioningTester;
import com.yahoo.vespa.hosted.provision.testutils.MockDeployer;
-import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver;
-import com.yahoo.vespa.hosted.provision.testutils.MockProvisionServiceProvider;
import com.yahoo.vespa.hosted.provision.testutils.OrchestratorMock;
import com.yahoo.vespa.hosted.provision.testutils.ServiceMonitorStub;
import com.yahoo.vespa.hosted.provision.testutils.TestHostLivenessTracker;
@@ -57,12 +50,12 @@ public class NodeFailTester {
public static final ApplicationId app1 = ApplicationId.from("foo1", "bar", "fuz");
public static final ApplicationId app2 = ApplicationId.from("foo2", "bar", "fuz");
public static final NodeFlavors nodeFlavors = FlavorConfigBuilder.createDummies("default", "docker");
- private static final Zone zone = new Zone(Environment.prod, RegionName.from("us-east"));
private static final Duration downtimeLimitOneHour = Duration.ofMinutes(60);
// Components with state
public final ManualClock clock;
public final NodeRepository nodeRepository;
+ public final ProvisioningTester tester;
public NodeFailer failer;
public ServiceMonitorStub serviceMonitor;
public MockDeployer deployer;
@@ -73,21 +66,13 @@ public class NodeFailTester {
private final Curator curator;
private NodeFailTester() {
- clock = new ManualClock();
- curator = new MockCurator();
- nodeRepository = new NodeRepository(nodeFlavors,
- new EmptyProvisionServiceProvider(),
- curator,
- clock,
- zone,
- new MockNameResolver().mockAnyLookup(),
- DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"),
- new InMemoryFlagSource(),
- true,
- 0, 1000);
- provisioner = new NodeRepositoryProvisioner(nodeRepository, zone, new MockProvisionServiceProvider(), new InMemoryFlagSource());
- hostLivenessTracker = new TestHostLivenessTracker(clock);
orchestrator = new OrchestratorMock();
+ tester = new ProvisioningTester.Builder().orchestrator(orchestrator).flavors(nodeFlavors.getFlavors()).build();
+ clock = tester.clock();
+ curator = tester.getCurator();
+ nodeRepository = tester.nodeRepository();
+ provisioner = tester.provisioner();
+ hostLivenessTracker = new TestHostLivenessTracker(clock);
}
public static NodeFailTester withTwoApplications() {
@@ -123,7 +108,7 @@ public class NodeFailTester {
int nodesPerHost = 3;
List<Node> hosts = tester.createHostNodes(numberOfHosts);
for (int i = 0; i < hosts.size(); i++) {
- tester.createReadyNodes(nodesPerHost, i * nodesPerHost, Optional.of("parent" + i),
+ tester.createReadyNodes(nodesPerHost, i * nodesPerHost, Optional.of("parent" + (i + 1)),
new NodeResources(1, 4, 100, 0.3), NodeType.tenant);
}
@@ -246,7 +231,7 @@ public class NodeFailTester {
private List<Node> createReadyNodes(int count, int startIndex, Optional<String> parentHostname, Flavor flavor, NodeType nodeType) {
List<Node> nodes = new ArrayList<>(count);
for (int i = startIndex; i < startIndex + count; i++)
- nodes.add(nodeRepository.createNode("node" + i, "host" + i, parentHostname, flavor, nodeType));
+ nodes.add(nodeRepository.createNode("node" + i, "host" + i, IP.Config.EMPTY, parentHostname, flavor, Optional.empty(), nodeType));
nodes = nodeRepository.addNodes(nodes, Agent.system);
nodes = nodeRepository.setDirty(nodes, Agent.system, getClass().getSimpleName());
@@ -254,10 +239,9 @@ public class NodeFailTester {
}
private List<Node> createHostNodes(int count) {
- List<Node> nodes = new ArrayList<>(count);
- for (int i = 0; i < count; i++)
- nodes.add(nodeRepository.createNode("parent" + i, "parent" + i, Optional.empty(), nodeFlavors.getFlavorOrThrow("default"), NodeType.host));
- nodes = nodeRepository.addNodes(nodes, Agent.system);
+ List<Node> nodes = tester.makeProvisionedNodes(count, (index) -> "parent" + index,
+ nodeFlavors.getFlavorOrThrow("default"),
+ Optional.empty(), NodeType.host, 10, false);
nodes = nodeRepository.setDirty(nodes, Agent.system, getClass().getSimpleName());
return nodeRepository.setReady(nodes, Agent.system, getClass().getSimpleName());
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooterTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooterTest.java
index 3ff81070516..ebcb4c3e0dc 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooterTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooterTest.java
@@ -2,10 +2,14 @@
package com.yahoo.vespa.hosted.provision.maintenance;
import com.yahoo.component.Version;
+import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
+import com.yahoo.vespa.curator.mock.MockCurator;
import com.yahoo.vespa.flags.Flags;
import com.yahoo.vespa.flags.InMemoryFlagSource;
import com.yahoo.vespa.hosted.provision.Node;
+import com.yahoo.vespa.hosted.provision.NodeRepository;
+import com.yahoo.vespa.hosted.provision.provisioning.ProvisioningTester;
import org.junit.Test;
import java.time.Duration;
@@ -24,68 +28,74 @@ public class NodeRebooterTest {
public void testRebootScheduling() {
var rebootInterval = Duration.ofDays(30);
var flagSource = new InMemoryFlagSource().withIntFlag(Flags.REBOOT_INTERVAL_IN_DAYS.id(), (int) rebootInterval.toDays());
- var tester = new MaintenanceTester();
- tester.createReadyHostNodes(15);
- NodeRebooter rebooter = new NodeRebooter(tester.nodeRepository, tester.clock, flagSource, new TestMetric());
+ var tester = new ProvisioningTester.Builder().flagSource(flagSource).build();
+ ((MockCurator) tester.getCurator()).setZooKeeperEnsembleConnectionSpec("zk1.host:1,zk2.host:2,zk3.host:3");
- assertReadyHosts(15, tester, 0L);
+ makeReadyHosts(15, tester);
+ NodeRepository nodeRepository = tester.nodeRepository();
+ NodeRebooter rebooter = new NodeRebooter(nodeRepository, tester.clock(), flagSource, new TestMetric());
+
+ assertReadyHosts(15, nodeRepository, 0L);
// No reboots within 0x-1x reboot interval
- tester.clock.advance(rebootInterval);
+ tester.clock().advance(rebootInterval);
rebooter.maintain();
- simulateReboot(tester);
- assertReadyHosts(15, tester, 0L);
+ simulateReboot(nodeRepository);
+ assertReadyHosts(15, nodeRepository, 0L);
// All nodes/hosts reboots within 1x-2x reboot interval
- tester.clock.advance(rebootInterval);
+ tester.clock().advance(rebootInterval);
rebooter.maintain();
- simulateReboot(tester);
- assertReadyHosts(15, tester, 1L);
+ simulateReboot(nodeRepository);
+ assertReadyHosts(15, nodeRepository, 1L);
// OS upgrade just before reboots would have been scheduled again
- tester.clock.advance(rebootInterval);
- scheduleOsUpgrade(tester);
- simulateOsUpgrade(tester);
+ tester.clock().advance(rebootInterval);
+ scheduleOsUpgrade(nodeRepository);
+ simulateOsUpgrade(nodeRepository);
rebooter.maintain();
- simulateReboot(tester);
- assertReadyHosts(15, tester, 1L);
+ simulateReboot(nodeRepository);
+ assertReadyHosts(15, nodeRepository, 1L);
// OS upgrade counts as reboot, so within 0x-1x there is no reboots
- tester.clock.advance(rebootInterval);
+ tester.clock().advance(rebootInterval);
rebooter.maintain();
- simulateReboot(tester);
- assertReadyHosts(15, tester, 1L);
+ simulateReboot(nodeRepository);
+ assertReadyHosts(15, nodeRepository, 1L);
// OS upgrade counts as reboot, but within 1x-2x reboots are scheduled again
- tester.clock.advance(rebootInterval);
+ tester.clock().advance(rebootInterval);
rebooter.maintain();
- simulateReboot(tester);
- assertReadyHosts(15, tester, 2L);
+ simulateReboot(nodeRepository);
+ assertReadyHosts(15, nodeRepository, 2L);
}
@Test
public void testRebootScheduledEvenWithSmallProbability() {
Duration rebootInterval = Duration.ofDays(30);
var flagSource = new InMemoryFlagSource().withIntFlag(Flags.REBOOT_INTERVAL_IN_DAYS.id(), (int) rebootInterval.toDays());
- var tester = new MaintenanceTester();
- tester.createReadyHostNodes(2);
- NodeRebooter rebooter = new NodeRebooter(tester.nodeRepository, tester.clock, flagSource, new TestMetric());
+ var tester = new ProvisioningTester.Builder().flagSource(flagSource).build();
+ ((MockCurator) tester.getCurator()).setZooKeeperEnsembleConnectionSpec("zk1.host:1,zk2.host:2,zk3.host:3");
+
+ makeReadyHosts(2, tester);
+ NodeRepository nodeRepository = tester.nodeRepository();
+ NodeRebooter rebooter = new NodeRebooter(nodeRepository, tester.clock(), flagSource, new TestMetric());
- assertReadyHosts(2, tester, 0L);
+ assertReadyHosts(2, nodeRepository, 0L);
// No reboots within 0x-1x reboot interval
- tester.clock.advance(rebootInterval);
+ tester.clock().advance(rebootInterval);
rebooter.maintain();
- simulateReboot(tester);
- assertReadyHosts(2, tester, 0L);
+ simulateReboot(nodeRepository);
+ assertReadyHosts(2, nodeRepository, 0L);
// Advancing just a little bit into the 1x-2x interval, there is a >0 probability of
// rebooting a host. Run until all have been scheduled.
- tester.clock.advance(Duration.ofMinutes(25));
+ tester.clock().advance(Duration.ofMinutes(25));
for (int i = 0;; ++i) {
rebooter.maintain();
- simulateReboot(tester);
- List<Node> nodes = tester.nodeRepository.getNodes(NodeType.host, Node.State.ready);
+ simulateReboot(nodeRepository);
+ List<Node> nodes = nodeRepository.getNodes(NodeType.host, Node.State.ready);
int count = withCurrentRebootGeneration(1L, nodes).size();
if (count == 2) {
break;
@@ -93,33 +103,37 @@ public class NodeRebooterTest {
}
}
- private void assertReadyHosts(int expectedCount, MaintenanceTester tester, long generation) {
- List<Node> nodes = tester.nodeRepository.getNodes(NodeType.host, Node.State.ready);
+ private void assertReadyHosts(int expectedCount, NodeRepository nodeRepository, long generation) {
+ List<Node> nodes = nodeRepository.getNodes(NodeType.host, Node.State.ready);
assertEquals(expectedCount, withCurrentRebootGeneration(generation, nodes).size());
}
+ private void makeReadyHosts(int count, ProvisioningTester tester) {
+ List<Node> hosts = tester.makeReadyNodes(count, new NodeResources(64, 256, 1000, 10), NodeType.host, 10);
+ }
+
/** Set current reboot generation to the wanted reboot generation whenever it is larger (i.e record a reboot) */
- private void simulateReboot(MaintenanceTester tester) {
- for (Node node : tester.nodeRepository.getNodes(Node.State.ready, Node.State.active)) {
+ private void simulateReboot(NodeRepository nodeRepository) {
+ for (Node node : nodeRepository.getNodes(Node.State.ready, Node.State.active)) {
if (node.status().reboot().wanted() > node.status().reboot().current())
- tester.nodeRepository.write(node.withCurrentRebootGeneration(node.status().reboot().wanted(),
- tester.clock.instant()), () -> {});
+ nodeRepository.write(node.withCurrentRebootGeneration(node.status().reboot().wanted(),
+ nodeRepository.clock().instant()), () -> {});
}
}
/** Schedule OS upgrade for all host nodes */
- private void scheduleOsUpgrade(MaintenanceTester tester) {
- tester.nodeRepository.osVersions().setTarget(NodeType.host, Version.fromString("7.0"), Optional.empty(), false);
+ private void scheduleOsUpgrade(NodeRepository nodeRepository) {
+ nodeRepository.osVersions().setTarget(NodeType.host, Version.fromString("7.0"), Optional.empty(), false);
}
/** Simulate completion of an OS upgrade */
- private void simulateOsUpgrade(MaintenanceTester tester) {
- var wantedOsVersion = tester.nodeRepository.osVersions().targetFor(NodeType.host);
+ private void simulateOsUpgrade(NodeRepository nodeRepository) {
+ var wantedOsVersion = nodeRepository.osVersions().targetFor(NodeType.host);
if (wantedOsVersion.isEmpty()) return;
- for (Node node : tester.nodeRepository.getNodes(Node.State.ready, Node.State.active)) {
+ for (Node node : nodeRepository.getNodes(Node.State.ready, Node.State.active)) {
if (wantedOsVersion.get().isAfter(node.status().osVersion().current().orElse(Version.emptyVersion)))
- tester.nodeRepository.write(node.withCurrentOsVersion(wantedOsVersion.get(), tester.clock.instant()),
- () -> {});
+ nodeRepository.write(node.withCurrentOsVersion(wantedOsVersion.get(), nodeRepository.clock().instant()),
+ () -> {});
}
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OperatorChangeApplicationMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OperatorChangeApplicationMaintainerTest.java
index 41a1b4bac38..9d58c30a2c6 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OperatorChangeApplicationMaintainerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OperatorChangeApplicationMaintainerTest.java
@@ -6,36 +6,20 @@ import com.yahoo.config.provision.ApplicationName;
import com.yahoo.config.provision.Capacity;
import com.yahoo.config.provision.ClusterResources;
import com.yahoo.config.provision.ClusterSpec;
-import com.yahoo.config.provision.DockerImage;
-import com.yahoo.config.provision.Environment;
-import com.yahoo.config.provision.Flavor;
import com.yahoo.config.provision.InstanceName;
-import com.yahoo.config.provision.NodeFlavors;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
-import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.TenantName;
-import com.yahoo.config.provision.Zone;
import com.yahoo.test.ManualClock;
-import com.yahoo.vespa.curator.Curator;
-import com.yahoo.vespa.curator.mock.MockCurator;
-import com.yahoo.vespa.flags.InMemoryFlagSource;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.node.Agent;
-import com.yahoo.vespa.hosted.provision.provisioning.EmptyProvisionServiceProvider;
-import com.yahoo.vespa.hosted.provision.provisioning.FlavorConfigBuilder;
-import com.yahoo.vespa.hosted.provision.provisioning.NodeRepositoryProvisioner;
+import com.yahoo.vespa.hosted.provision.provisioning.ProvisioningTester;
import com.yahoo.vespa.hosted.provision.testutils.MockDeployer;
-import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver;
-import com.yahoo.vespa.hosted.provision.testutils.MockProvisionServiceProvider;
import org.junit.Test;
import java.time.Duration;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Map;
-import java.util.Optional;
import static org.junit.Assert.assertEquals;
@@ -44,31 +28,16 @@ import static org.junit.Assert.assertEquals;
*/
public class OperatorChangeApplicationMaintainerTest {
- private static final NodeFlavors nodeFlavors = FlavorConfigBuilder.createDummies("default");
-
- private NodeRepository nodeRepository;
- private Fixture fixture;
-
@Test
public void test_application_maintenance() {
- ManualClock clock = new ManualClock();
- Curator curator = new MockCurator();
- Zone zone = new Zone(Environment.prod, RegionName.from("us-east"));
- this.nodeRepository = new NodeRepository(nodeFlavors,
- new EmptyProvisionServiceProvider(),
- curator,
- clock,
- zone,
- new MockNameResolver().mockAnyLookup(),
- DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"),
- new InMemoryFlagSource(),
- true,
- 0, 1000);
- this.fixture = new Fixture(zone, nodeRepository);
-
- createReadyNodes(15, this.fixture.nodeResources, nodeRepository);
- createHostNodes(2, nodeRepository, nodeFlavors);
- createProxyNodes(2, nodeRepository, nodeFlavors);
+ NodeResources hostResources = new NodeResources(64, 128, 2000, 10);
+ Fixture fixture = new Fixture();
+ ManualClock clock = fixture.tester.clock();
+ NodeRepository nodeRepository = fixture.nodeRepository;
+
+ fixture.tester.makeReadyNodes(15, fixture.nodeResources);
+ fixture.tester.makeReadyNodes(2, hostResources);
+ fixture.tester.makeReadyNodes(2, fixture.nodeResources, NodeType.proxy);
// Create applications
fixture.activate();
@@ -104,39 +73,9 @@ public class OperatorChangeApplicationMaintainerTest {
assertEquals("No further operator changes -> no (new) redeployments", 5, fixture.deployer.redeployments);
}
- private void createReadyNodes(int count, NodeResources resources, NodeRepository nodeRepository) {
- createReadyNodes(count, new Flavor(resources), nodeRepository);
- }
-
- private void createReadyNodes(int count, Flavor flavor, NodeRepository nodeRepository) {
- List<Node> nodes = new ArrayList<>(count);
- for (int i = 0; i < count; i++)
- nodes.add(nodeRepository.createNode("node" + i, "host" + i, Optional.empty(), flavor, NodeType.tenant));
- nodes = nodeRepository.addNodes(nodes, Agent.system);
- nodes = nodeRepository.setDirty(nodes, Agent.system, getClass().getSimpleName());
- nodeRepository.setReady(nodes, Agent.system, getClass().getSimpleName());
- }
-
- private void createHostNodes(int count, NodeRepository nodeRepository, NodeFlavors nodeFlavors) {
- List<Node> nodes = new ArrayList<>(count);
- for (int i = 0; i < count; i++)
- nodes.add(nodeRepository.createNode("hostNode" + i, "realHost" + i, Optional.empty(), nodeFlavors.getFlavorOrThrow("default"), NodeType.host));
- nodes = nodeRepository.addNodes(nodes, Agent.system);
- nodes = nodeRepository.setDirty(nodes, Agent.system, getClass().getSimpleName());
- nodeRepository.setReady(nodes, Agent.system, getClass().getSimpleName());
- }
-
- private void createProxyNodes(int count, NodeRepository nodeRepository, NodeFlavors nodeFlavors) {
- List<Node> nodes = new ArrayList<>(count);
- for (int i = 0; i < count; i++)
- nodes.add(nodeRepository.createNode("proxyNode" + i, "proxyHost" + i, Optional.empty(), nodeFlavors.getFlavorOrThrow("default"), NodeType.proxy));
- nodes = nodeRepository.addNodes(nodes, Agent.system);
- nodes = nodeRepository.setDirty(nodes, Agent.system, getClass().getSimpleName());
- nodeRepository.setReady(nodes, Agent.system, getClass().getSimpleName());
- }
-
private static class Fixture {
+ final ProvisioningTester tester;
final NodeRepository nodeRepository;
final MockDeployer deployer;
@@ -151,18 +90,14 @@ public class OperatorChangeApplicationMaintainerTest {
final int wantedNodesApp2 = 7;
final int wantedNodesApp3 = 2;
- Fixture(Zone zone, NodeRepository nodeRepository) {
- this.nodeRepository = nodeRepository;
- NodeRepositoryProvisioner provisioner = new NodeRepositoryProvisioner(nodeRepository,
- zone,
- new MockProvisionServiceProvider(),
- new InMemoryFlagSource());
-
+ Fixture() {
+ this.tester = new ProvisioningTester.Builder().build();
+ this.nodeRepository = tester.nodeRepository();
Map<ApplicationId, MockDeployer.ApplicationContext> apps = Map.of(
app1, new MockDeployer.ApplicationContext(app1, clusterApp1, Capacity.from(new ClusterResources(wantedNodesApp1, 1, nodeResources))),
app2, new MockDeployer.ApplicationContext(app2, clusterApp2, Capacity.from(new ClusterResources(wantedNodesApp2, 1, nodeResources))),
app3, new MockDeployer.ApplicationContext(app3, clusterApp3, Capacity.fromRequiredNodeType(NodeType.proxy))) ;
- this.deployer = new MockDeployer(provisioner, nodeRepository.clock(), apps);
+ this.deployer = new MockDeployer(tester.provisioner(), nodeRepository.clock(), apps);
}
void activate() {
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java
index b437b8f5577..55a183c8ec1 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java
@@ -7,40 +7,26 @@ import com.yahoo.config.provision.Capacity;
import com.yahoo.config.provision.ClusterResources;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.Deployer;
-import com.yahoo.config.provision.DockerImage;
-import com.yahoo.config.provision.Environment;
-import com.yahoo.config.provision.Flavor;
import com.yahoo.config.provision.InstanceName;
-import com.yahoo.config.provision.NodeFlavors;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
-import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.TenantName;
-import com.yahoo.config.provision.Zone;
import com.yahoo.test.ManualClock;
-import com.yahoo.vespa.curator.Curator;
-import com.yahoo.vespa.curator.mock.MockCurator;
import com.yahoo.vespa.flags.InMemoryFlagSource;
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.EmptyProvisionServiceProvider;
-import com.yahoo.vespa.hosted.provision.provisioning.FlavorConfigBuilder;
-import com.yahoo.vespa.hosted.provision.provisioning.NodeRepositoryProvisioner;
+import com.yahoo.vespa.hosted.provision.provisioning.ProvisioningTester;
import com.yahoo.vespa.hosted.provision.testutils.MockDeployer;
-import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver;
-import com.yahoo.vespa.hosted.provision.testutils.MockProvisionServiceProvider;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.time.Duration;
import java.time.Instant;
-import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import java.util.Optional;
import static org.junit.Assert.assertEquals;
@@ -49,31 +35,18 @@ import static org.junit.Assert.assertEquals;
*/
public class PeriodicApplicationMaintainerTest {
- private static final NodeFlavors nodeFlavors = FlavorConfigBuilder.createDummies("default");
-
private NodeRepository nodeRepository;
private Fixture fixture;
private ManualClock clock;
@Before
public void before() {
- Curator curator = new MockCurator();
- Zone zone = new Zone(Environment.prod, RegionName.from("us-east"));
- this.clock = new ManualClock();
- this.nodeRepository = new NodeRepository(nodeFlavors,
- new EmptyProvisionServiceProvider(),
- curator,
- clock,
- zone,
- new MockNameResolver().mockAnyLookup(),
- DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"),
- new InMemoryFlagSource(),
- true,
- 0, 1000);
- this.fixture = new Fixture(zone, nodeRepository);
-
- createReadyNodes(15, fixture.nodeResources, nodeRepository);
- createHostNodes(2, nodeRepository, nodeFlavors);
+ this.fixture = new Fixture();
+ this.nodeRepository = fixture.nodeRepository;
+ this.clock = fixture.tester.clock();
+
+ fixture.tester.makeReadyNodes(15, fixture.nodeResources);
+ fixture.tester.makeReadyHosts(2, new NodeResources(64, 256, 2000, 10));
}
@After
@@ -229,32 +202,11 @@ public class PeriodicApplicationMaintainerTest {
}
}
- private void createReadyNodes(int count, NodeResources nodeResources, NodeRepository nodeRepository) {
- createReadyNodes(count, new Flavor(nodeResources), nodeRepository);
- }
-
- private void createReadyNodes(int count, Flavor flavor, NodeRepository nodeRepository) {
- List<Node> nodes = new ArrayList<>(count);
- for (int i = 0; i < count; i++)
- nodes.add(nodeRepository.createNode("node" + i, "host" + i, Optional.empty(), flavor, NodeType.tenant));
- nodes = nodeRepository.addNodes(nodes, Agent.system);
- nodes = nodeRepository.setDirty(nodes, Agent.system, getClass().getSimpleName());
- nodeRepository.setReady(nodes, Agent.system, getClass().getSimpleName());
- }
-
- private void createHostNodes(int count, NodeRepository nodeRepository, NodeFlavors nodeFlavors) {
- List<Node> nodes = new ArrayList<>(count);
- for (int i = 0; i < count; i++)
- nodes.add(nodeRepository.createNode("hostNode" + i, "realHost" + i, Optional.empty(), nodeFlavors.getFlavorOrThrow("default"), NodeType.host));
- nodes = nodeRepository.addNodes(nodes, Agent.system);
- nodes = nodeRepository.setDirty(nodes, Agent.system, getClass().getSimpleName());
- nodeRepository.setReady(nodes, Agent.system, getClass().getSimpleName());
- }
-
private class Fixture {
final NodeRepository nodeRepository;
final MockDeployer deployer;
+ final ProvisioningTester tester;
final NodeResources nodeResources = new NodeResources(2, 8, 50, 1);
final ApplicationId app1 = ApplicationId.from(TenantName.from("foo1"), ApplicationName.from("bar"), InstanceName.from("fuz"));
@@ -266,17 +218,13 @@ public class PeriodicApplicationMaintainerTest {
private final TestablePeriodicApplicationMaintainer maintainer;
- Fixture(Zone zone, NodeRepository nodeRepository) {
- this.nodeRepository = nodeRepository;
- NodeRepositoryProvisioner provisioner = new NodeRepositoryProvisioner(nodeRepository,
- zone,
- new MockProvisionServiceProvider(),
- new InMemoryFlagSource());
-
+ Fixture() {
+ this.tester = new ProvisioningTester.Builder().build();
+ this.nodeRepository = tester.nodeRepository();
Map<ApplicationId, MockDeployer.ApplicationContext> apps = Map.of(
app1, new MockDeployer.ApplicationContext(app1, clusterApp1, Capacity.from(new ClusterResources(wantedNodesApp1, 1, nodeResources))),
app2, new MockDeployer.ApplicationContext(app2, clusterApp2, Capacity.from(new ClusterResources(wantedNodesApp2, 1, nodeResources))));
- this.deployer = new MockDeployer(provisioner, nodeRepository.clock(), apps);
+ this.deployer = new MockDeployer(tester.provisioner(), nodeRepository.clock(), apps);
this.maintainer = new TestablePeriodicApplicationMaintainer(deployer, nodeRepository, Duration.ofDays(1), // Long duration to prevent scheduled runs during test
Duration.ofMinutes(30));
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ReservationExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ReservationExpirerTest.java
index e2ac644a419..12528a554d9 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ReservationExpirerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ReservationExpirerTest.java
@@ -5,31 +5,18 @@ import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.Capacity;
import com.yahoo.config.provision.ClusterResources;
import com.yahoo.config.provision.ClusterSpec;
-import com.yahoo.config.provision.DockerImage;
-import com.yahoo.config.provision.Flavor;
import com.yahoo.config.provision.NodeFlavors;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
-import com.yahoo.config.provision.Zone;
import com.yahoo.test.ManualClock;
-import com.yahoo.vespa.curator.Curator;
-import com.yahoo.vespa.curator.mock.MockCurator;
-import com.yahoo.vespa.flags.InMemoryFlagSource;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeRepository;
-import com.yahoo.vespa.hosted.provision.node.Agent;
-import com.yahoo.vespa.hosted.provision.provisioning.EmptyProvisionServiceProvider;
import com.yahoo.vespa.hosted.provision.provisioning.FlavorConfigBuilder;
-import com.yahoo.vespa.hosted.provision.provisioning.NodeRepositoryProvisioner;
-import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver;
-import com.yahoo.vespa.hosted.provision.testutils.MockProvisionServiceProvider;
+import com.yahoo.vespa.hosted.provision.provisioning.ProvisioningTester;
import org.junit.Test;
import java.time.Duration;
-import java.util.ArrayList;
import java.util.List;
-import java.util.Optional;
-import java.util.UUID;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -39,37 +26,23 @@ import static org.junit.Assert.assertFalse;
*/
public class ReservationExpirerTest {
- private final Curator curator = new MockCurator();
-
@Test
public void ensure_reservation_times_out() {
- ManualClock clock = new ManualClock();
NodeFlavors flavors = FlavorConfigBuilder.createDummies("default");
- NodeRepository nodeRepository = new NodeRepository(flavors,
- new EmptyProvisionServiceProvider(),
- curator,
- clock,
- Zone.defaultZone(),
- new MockNameResolver().mockAnyLookup(),
- DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"),
- new InMemoryFlagSource(),
- true,
- 0, 1000);
- NodeRepositoryProvisioner provisioner = new NodeRepositoryProvisioner(nodeRepository, Zone.defaultZone(), new MockProvisionServiceProvider(), new InMemoryFlagSource());
+ ProvisioningTester tester = new ProvisioningTester.Builder().flavors(flavors.getFlavors()).build();
+ ManualClock clock = tester.clock();
+ NodeRepository nodeRepository = tester.nodeRepository();
- List<Node> nodes = new ArrayList<>(2);
- nodes.add(nodeRepository.createNode(UUID.randomUUID().toString(), UUID.randomUUID().toString(), Optional.empty(), new Flavor(new NodeResources(2, 8, 50, 1)), NodeType.tenant));
- nodes.add(nodeRepository.createNode(UUID.randomUUID().toString(), UUID.randomUUID().toString(), Optional.empty(), new Flavor(new NodeResources(2, 8, 50, 1)), NodeType.tenant));
- nodes.add(nodeRepository.createNode(UUID.randomUUID().toString(), UUID.randomUUID().toString(), Optional.empty(), flavors.getFlavorOrThrow("default"), NodeType.host));
- nodes = nodeRepository.addNodes(nodes, Agent.system);
- nodes = nodeRepository.setDirty(nodes, Agent.system, getClass().getSimpleName());
+ NodeResources nodeResources = new NodeResources(2, 8, 50, 1);
+ NodeResources hostResources = nodeResources.add(nodeResources).add(nodeResources);
+ tester.makeReadyNodes(2, nodeResources);
+ tester.makeReadyHosts(1, hostResources);
// Reserve 2 nodes
- assertEquals(2, nodeRepository.getNodes(NodeType.tenant, Node.State.dirty).size());
- nodeRepository.setReady(nodes, Agent.system, getClass().getSimpleName());
+ assertEquals(2, nodeRepository.getNodes(NodeType.tenant, Node.State.ready).size());
ApplicationId applicationId = new ApplicationId.Builder().tenant("foo").applicationName("bar").instanceName("fuz").build();
ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("test")).vespaVersion("6.42").build();
- provisioner.prepare(applicationId, cluster, Capacity.from(new ClusterResources(2, 1, new NodeResources(2, 8, 50, 1))), null);
+ tester.provisioner().prepare(applicationId, cluster, Capacity.from(new ClusterResources(2, 1, nodeResources)), null);
assertEquals(2, nodeRepository.getNodes(NodeType.tenant, Node.State.reserved).size());
// Reservation times out
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java
index 9c5e74ae63c..aba5810784b 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java
@@ -7,42 +7,22 @@ import com.yahoo.config.provision.Capacity;
import com.yahoo.config.provision.ClusterResources;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.Deployer;
-import com.yahoo.config.provision.DockerImage;
-import com.yahoo.config.provision.Environment;
-import com.yahoo.config.provision.Flavor;
-import com.yahoo.config.provision.HostSpec;
import com.yahoo.config.provision.InstanceName;
-import com.yahoo.config.provision.NodeFlavors;
import com.yahoo.config.provision.NodeResources;
-import com.yahoo.config.provision.NodeType;
-import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.TenantName;
-import com.yahoo.config.provision.Zone;
import com.yahoo.test.ManualClock;
-import com.yahoo.transaction.NestedTransaction;
-import com.yahoo.vespa.curator.Curator;
-import com.yahoo.vespa.curator.mock.MockCurator;
-import com.yahoo.vespa.curator.transaction.CuratorTransaction;
-import com.yahoo.vespa.flags.InMemoryFlagSource;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeRepository;
-import com.yahoo.vespa.hosted.provision.node.Agent;
-import com.yahoo.vespa.hosted.provision.provisioning.EmptyProvisionServiceProvider;
-import com.yahoo.vespa.hosted.provision.provisioning.FlavorConfigBuilder;
import com.yahoo.vespa.hosted.provision.provisioning.NodeRepositoryProvisioner;
+import com.yahoo.vespa.hosted.provision.provisioning.ProvisioningTester;
import com.yahoo.vespa.hosted.provision.testutils.MockDeployer;
-import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver;
-import com.yahoo.vespa.hosted.provision.testutils.MockProvisionServiceProvider;
import com.yahoo.vespa.orchestrator.OrchestrationException;
import com.yahoo.vespa.orchestrator.Orchestrator;
import org.junit.Before;
import org.junit.Test;
import java.time.Duration;
-import java.util.ArrayList;
import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -58,23 +38,13 @@ import static org.mockito.Mockito.verify;
*/
public class RetiredExpirerTest {
+ private final NodeResources hostResources = new NodeResources(64, 128, 2000, 10);
private final NodeResources nodeResources = new NodeResources(2, 8, 50, 1);
- private Curator curator = new MockCurator();
- private final ManualClock clock = new ManualClock();
- private final Zone zone = new Zone(Environment.prod, RegionName.from("us-east"));
- private final NodeFlavors nodeFlavors = FlavorConfigBuilder.createDummies("default");
- private final NodeRepository nodeRepository = new NodeRepository(nodeFlavors,
- new EmptyProvisionServiceProvider(),
- curator,
- clock,
- zone,
- new MockNameResolver().mockAnyLookup(),
- DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"),
- new InMemoryFlagSource(),
- true,
- 0, 1000);
- private final NodeRepositoryProvisioner provisioner = new NodeRepositoryProvisioner(nodeRepository, zone, new MockProvisionServiceProvider(), new InMemoryFlagSource());
+ private final ProvisioningTester tester = new ProvisioningTester.Builder().build();
+ private final ManualClock clock = tester.clock();
+ private final NodeRepository nodeRepository = tester.nodeRepository();
+ private final NodeRepositoryProvisioner provisioner = tester.provisioner();
private final Orchestrator orchestrator = mock(Orchestrator.class);
private static final Duration RETIRED_EXPIRATION = Duration.ofHours(12);
@@ -87,8 +57,8 @@ public class RetiredExpirerTest {
@Test
public void ensure_retired_nodes_time_out() {
- createReadyNodes(7, nodeResources, nodeRepository);
- createHostNodes(4, nodeRepository, nodeFlavors);
+ tester.makeReadyNodes(7, nodeResources);
+ tester.makeReadyHosts(4, hostResources);
ApplicationId applicationId = ApplicationId.from(TenantName.from("foo"), ApplicationName.from("bar"), InstanceName.from("fuz"));
@@ -96,9 +66,9 @@ public class RetiredExpirerTest {
// Should end up with 3 nodes in the cluster (one previously retired), and 4 retired
ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("test")).vespaVersion("6.42").build();
int wantedNodes;
- activate(applicationId, cluster, wantedNodes=7, 1, provisioner);
- activate(applicationId, cluster, wantedNodes=2, 1, provisioner);
- activate(applicationId, cluster, wantedNodes=3, 1, provisioner);
+ activate(applicationId, cluster, wantedNodes=7, 1);
+ activate(applicationId, cluster, wantedNodes=2, 1);
+ activate(applicationId, cluster, wantedNodes=3, 1);
assertEquals(7, nodeRepository.getNodes(applicationId, Node.State.active).size());
assertEquals(0, nodeRepository.getNodes(applicationId, Node.State.inactive).size());
@@ -122,8 +92,8 @@ public class RetiredExpirerTest {
@Test
public void ensure_early_inactivation() throws OrchestrationException {
- createReadyNodes(7, nodeResources, nodeRepository);
- createHostNodes(4, nodeRepository, nodeFlavors);
+ tester.makeReadyNodes(7, nodeResources);
+ tester.makeReadyHosts(4, hostResources);
ApplicationId applicationId = ApplicationId.from(TenantName.from("foo"), ApplicationName.from("bar"), InstanceName.from("fuz"));
@@ -131,9 +101,9 @@ public class RetiredExpirerTest {
// Should end up with 3 nodes in the cluster (one previously retired), and 4 retired
ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("test")).vespaVersion("6.42").build();
int wantedNodes;
- activate(applicationId, cluster, wantedNodes=7, 1, provisioner);
- activate(applicationId, cluster, wantedNodes=2, 1, provisioner);
- activate(applicationId, cluster, wantedNodes=3, 1, provisioner);
+ activate(applicationId, cluster, wantedNodes=7, 1);
+ activate(applicationId, cluster, wantedNodes=2, 1);
+ activate(applicationId, cluster, wantedNodes=3, 1);
assertEquals(7, nodeRepository.getNodes(applicationId, Node.State.active).size());
assertEquals(0, nodeRepository.getNodes(applicationId, Node.State.inactive).size());
@@ -180,39 +150,9 @@ public class RetiredExpirerTest {
assertFalse(node.allocation().get().membership().retired());
}
- private void activate(ApplicationId applicationId, ClusterSpec cluster, int nodes, int groups, NodeRepositoryProvisioner provisioner) {
- List<HostSpec> hosts = provisioner.prepare(applicationId, cluster, Capacity.from(new ClusterResources(nodes, groups, nodeResources)), null);
- try (var lock = provisioner.lock(applicationId)) {
- NestedTransaction transaction = new NestedTransaction().add(new CuratorTransaction(curator));
- provisioner.activate(transaction, hosts, lock);
- transaction.commit();
- }
- }
-
- private void createReadyNodes(int count, NodeResources nodeResources, NodeRepository nodeRepository) {
- createReadyNodes(count, new Flavor(nodeResources), nodeRepository);
- }
-
- private void createReadyNodes(int count, NodeRepository nodeRepository, NodeFlavors nodeFlavors) {
- createReadyNodes(count, nodeFlavors.getFlavorOrThrow("default"), nodeRepository);
- }
-
- private void createReadyNodes(int count, Flavor flavor, NodeRepository nodeRepository) {
- List<Node> nodes = new ArrayList<>(count);
- for (int i = 0; i < count; i++)
- nodes.add(nodeRepository.createNode("node" + i, "node" + i, Optional.empty(), flavor, NodeType.tenant));
- nodes = nodeRepository.addNodes(nodes, Agent.system);
- nodes = nodeRepository.setDirty(nodes, Agent.system, getClass().getSimpleName());
- nodeRepository.setReady(nodes, Agent.system, getClass().getSimpleName());
- }
-
- private void createHostNodes(int count, NodeRepository nodeRepository, NodeFlavors nodeFlavors) {
- List<Node> nodes = new ArrayList<>(count);
- for (int i = 0; i < count; i++)
- nodes.add(nodeRepository.createNode("parent" + i, "parent" + i, Optional.empty(), nodeFlavors.getFlavorOrThrow("default"), NodeType.host));
- nodes = nodeRepository.addNodes(nodes, Agent.system);
- nodes = nodeRepository.setDirty(nodes, Agent.system, getClass().getSimpleName());
- nodeRepository.setReady(nodes, Agent.system, getClass().getSimpleName());
+ private void activate(ApplicationId applicationId, ClusterSpec cluster, int nodes, int groups) {
+ Capacity capacity = Capacity.from(new ClusterResources(nodes, groups, nodeResources));
+ tester.activate(applicationId, tester.prepare(applicationId, cluster, capacity));
}
private RetiredExpirer createRetiredExpirer(Deployer deployer) {
@@ -225,4 +165,5 @@ public class RetiredExpirerTest {
Duration.ofDays(30), /* Maintenance interval, use large value so it never runs by itself */
RETIRED_EXPIRATION);
}
+
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java
index 62c6c0c9426..61274d04fe0 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java
@@ -29,7 +29,7 @@ public class AclProvisioningTest {
private final NodeResources nodeResources = new NodeResources(2, 8, 50, 1);
- private ProvisioningTester tester = new ProvisioningTester.Builder().build();
+ private final ProvisioningTester tester = new ProvisioningTester.Builder().build();
@Test
public void trusted_nodes_for_allocated_node() {
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java
index 9adc87656dd..2a43b9f44f6 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java
@@ -110,7 +110,8 @@ public class ProvisioningTester {
DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"),
flagSource,
true,
- spareCount, 1000);
+ spareCount,
+ 1000);
this.orchestrator = orchestrator;
this.provisioner = new NodeRepositoryProvisioner(nodeRepository, zone, provisionServiceProvider, flagSource);
this.capacityPolicies = new CapacityPolicies(nodeRepository);
@@ -383,6 +384,13 @@ public class ProvisioningTester {
return makeProvisionedNodes(n, asFlavor(flavor, type), Optional.empty(), type, ipAddressPoolSize, dualStack);
}
public List<Node> makeProvisionedNodes(int n, Flavor flavor, Optional<TenantName> reservedTo, NodeType type, int ipAddressPoolSize, boolean dualStack) {
+ return makeProvisionedNodes(n, (index) -> "host-" + index + ".yahoo.com", flavor, reservedTo, type, ipAddressPoolSize, dualStack);
+ }
+
+ public List<Node> makeProvisionedNodes(int n, Function<Integer, String> nodeNamer, Flavor flavor, Optional<TenantName> reservedTo, NodeType type, int ipAddressPoolSize, boolean dualStack) {
+ if (ipAddressPoolSize == 0 && type == NodeType.host) {
+ ipAddressPoolSize = 1; // Tenant hosts must have at least one IP in their pool
+ }
List<Node> nodes = new ArrayList<>(n);
for (int i = 0; i < n; i++) {
@@ -398,7 +406,7 @@ public class ProvisioningTester {
nextIP += 100;
}
- String hostname = String.format("host-%d.yahoo.com", nextHost);
+ String hostname = nodeNamer.apply(nextHost);
String ipv4 = String.format("127.0.0.%d", nextIP);
String ipv6 = String.format("::%d", nextIP);
@@ -499,12 +507,6 @@ public class ProvisioningTester {
i -> String.format("%s-%03d", dockerHostId, i));
}
- /** Creates a single of virtual docker node on a single parent host */
- public List<Node> makeReadyVirtualDockerNode(int index, NodeResources resources, String dockerHostId) {
- return makeReadyVirtualNodes(1, index, resources, Optional.of(dockerHostId),
- i -> String.format("%s-%03d", dockerHostId, i));
- }
-
/** Creates a set of virtual nodes without a parent host */
public List<Node> makeReadyVirtualNodes(int n, NodeResources resources) {
return makeReadyVirtualNodes(n, 0, resources, Optional.empty(),
@@ -512,13 +514,13 @@ public class ProvisioningTester {
}
/** Creates a set of virtual nodes on a single parent host */
- private List<Node> makeReadyVirtualNodes(int count, int startIndex, NodeResources flavor, Optional<String> parentHostId,
+ public List<Node> makeReadyVirtualNodes(int count, int startIndex, NodeResources resources, Optional<String> parentHostname,
Function<Integer, String> nodeNamer) {
List<Node> nodes = new ArrayList<>(count);
for (int i = startIndex; i < count + startIndex; i++) {
String hostname = nodeNamer.apply(i);
- nodes.add(nodeRepository.createNode("openstack-id", hostname, parentHostId,
- new Flavor(flavor), NodeType.tenant));
+ nodes.add(nodeRepository.createNode("node-id", hostname, IP.Config.EMPTY, parentHostname,
+ new Flavor(resources), Optional.empty(), NodeType.tenant));
}
nodes = nodeRepository.addNodes(nodes, Agent.system);
nodes = nodeRepository.setDirty(nodes, Agent.system, getClass().getSimpleName());