aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@gmail.com>2022-11-28 22:58:01 +0100
committerJon Bratseth <bratseth@gmail.com>2022-11-29 17:02:20 +0100
commit99d87eb3689a0d606bd2aef18ef126e377192dc2 (patch)
tree8487b5d45a65499335db5c2015ce40ec99c4d650
parent7d4c85bd682642d0abe0de89c3b5a589cfa9e667 (diff)
More realistic tests
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Address.java1
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java6
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java10
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java11
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockHostProvisioner.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNameResolver.java6
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicProvisioningTest.java177
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java3
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java3
9 files changed, 99 insertions, 120 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Address.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Address.java
index fd9771103de..532e6747d9a 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Address.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Address.java
@@ -9,6 +9,7 @@ import java.util.Objects;
* @author hakon
*/
public class Address {
+
private final String hostname;
public Address(String hostname) {
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java
index ad2973ff435..f0848f5caeb 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java
@@ -74,9 +74,9 @@ public class GroupPreparer {
public PrepareResult prepare(ApplicationId application, ClusterSpec cluster, NodeSpec requestedNodes,
List<Node> surplusActiveNodes, NodeIndices indices, int wantedGroups,
NodesAndHosts<LockedNodeList> allNodesAndHosts) {
- log.log(Level.FINE, "Preparing " + cluster.type().name() + " " + cluster.id() + " with requested resources " + requestedNodes.resources().orElse(NodeResources.unspecified()));
- // Try preparing in memory without global unallocated lock. Most of the time there should be no changes and we
- // can return nodes previously allocated.
+ log.log(Level.FINE, () -> "Preparing " + cluster.type().name() + " " + cluster.id() + " with requested resources " + requestedNodes.resources().orElse(NodeResources.unspecified()));
+ // Try preparing in memory without global unallocated lock. Most of the time there should be no changes,
+ // and we can return nodes previously allocated.
NodeAllocation probeAllocation = prepareAllocation(application, cluster, requestedNodes, surplusActiveNodes,
indices::probeNext, wantedGroups, allNodesAndHosts);
if (probeAllocation.fulfilledAndNoChanges()) {
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 178b42096e6..21efd1b014c 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
@@ -34,8 +34,7 @@ import java.util.logging.Logger;
import java.util.stream.Collectors;
/**
- * Used to manage a list of nodes during the node reservation process
- * in order to fulfill the nodespec.
+ * Used to manage a list of nodes during the node reservation process to fulfill the nodespec.
*
* @author bratseth
*/
@@ -316,7 +315,7 @@ class NodeAllocation {
* Returns {@link HostDeficit} describing the host deficit for the given {@link NodeSpec}.
*
* @return empty if the requested spec is already fulfilled. Otherwise returns {@link HostDeficit} containing the
- * flavor and host count required to cover the deficit.
+ * flavor and host count required to cover the deficit.
*/
Optional<HostDeficit> hostDeficit() {
if (nodeType().isHost()) {
@@ -521,6 +520,11 @@ class NodeAllocation {
return count;
}
+ @Override
+ public String toString() {
+ return "deficit of " + count + " nodes with " + resources;
+ }
+
}
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java
index fe4eb5d68c9..c1d65e0df4e 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java
@@ -146,12 +146,13 @@ public class NodePrioritizer {
if (spareHosts.contains(host) && !canAllocateToSpareHosts) continue;
if ( ! capacity.hasCapacity(host, requestedNodes.resources().get())) continue;
if ( ! allNodesAndHosts.childrenOf(host).owner(application).cluster(clusterSpec.id()).isEmpty()) continue;
+
candidates.add(NodeCandidate.createNewChild(requestedNodes.resources().get(),
- capacity.availableCapacityOf(host),
- host,
- spareHosts.contains(host),
- allNodesAndHosts.nodes(),
- nameResolver));
+ capacity.availableCapacityOf(host),
+ host,
+ spareHosts.contains(host),
+ allNodesAndHosts.nodes(),
+ nameResolver));
}
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockHostProvisioner.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockHostProvisioner.java
index 5a8c5221c47..e190f1c3bd2 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockHostProvisioner.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockHostProvisioner.java
@@ -190,7 +190,7 @@ public class MockHostProvisioner implements HostProvisioner {
.collect(Collectors.toList());
}
- private Node withIpAssigned(Node node) {
+ public Node withIpAssigned(Node node) {
if (!node.type().isHost()) {
return node.with(node.ipConfig().withPrimary(nameResolver.resolveAll(node.hostname())));
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNameResolver.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNameResolver.java
index 0764d4527d5..dbc74f32f6b 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNameResolver.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNameResolver.java
@@ -64,9 +64,9 @@ public class MockNameResolver implements NameResolver {
return records.get(name);
}
if (mockAnyLookup) {
- Set<String> ipAddresses = Set.of(randomIpAddress());
- records.put(name, ipAddresses);
- return ipAddresses;
+ records.computeIfAbsent(name, (k) -> new HashSet<>())
+ .add(randomIpAddress());
+ return records.get(name);
}
throw new RuntimeException(new UnknownHostException("Could not resolve: " + name));
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicProvisioningTest.java
index e0301d0c329..13089da2063 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicProvisioningTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicProvisioningTest.java
@@ -1,16 +1,15 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.provision.provisioning;
-import com.yahoo.component.Version;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.Capacity;
import com.yahoo.config.provision.Cloud;
-import com.yahoo.config.provision.CloudAccount;
import com.yahoo.config.provision.ClusterResources;
import com.yahoo.config.provision.ClusterSpec;
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.NodeResources.Architecture;
import com.yahoo.config.provision.NodeResources.DiskSpeed;
@@ -23,18 +22,16 @@ import com.yahoo.vespa.flags.InMemoryFlagSource;
import com.yahoo.vespa.flags.PermanentFlags;
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.node.IP;
-import com.yahoo.vespa.hosted.provision.provisioning.HostProvisioner.HostSharing;
import com.yahoo.vespa.hosted.provision.testutils.MockHostProvisioner;
import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver;
import org.junit.Test;
import java.time.Instant;
+import java.util.Collection;
import java.util.List;
-import java.util.Optional;
import java.util.Set;
-import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@@ -45,13 +42,6 @@ import static com.yahoo.config.provision.NodeResources.StorageType.remote;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-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
@@ -59,79 +49,63 @@ import static org.mockito.Mockito.when;
*/
public class DynamicProvisioningTest {
- private static final Zone zone = new Zone(
- Cloud.builder().dynamicProvisioning(true).allowHostSharing(false).build(),
- SystemName.main,
- Environment.prod,
- RegionName.from("us-east"));
private final MockNameResolver nameResolver = new MockNameResolver().mockAnyLookup();
- private final HostProvisioner hostProvisioner = mock(HostProvisioner.class);
- private final ProvisioningTester tester = new ProvisioningTester.Builder()
- .zone(zone).hostProvisioner(hostProvisioner).nameResolver(nameResolver).build();
@Test
public void dynamically_provision_with_empty_node_repo() {
+ var tester = tester(true);
assertEquals(0, tester.nodeRepository().nodes().list().size());
- ApplicationId application1 = ProvisioningTester.applicationId();
+ ApplicationId application1 = ProvisioningTester.applicationId("application1");
NodeResources resources = new NodeResources(1, 4, 10, 1);
-
- mockHostProvisioner(hostProvisioner, "large", 3, null); // Provision shared hosts
- prepareAndActivate(application1, clusterSpec("mycluster"), 4, 1, resources);
- verify(hostProvisioner).provisionHosts(eq(List.of(100, 101, 102, 103)), eq(NodeType.host), eq(resources), eq(application1),
- eq(Version.emptyVersion), eq(HostSharing.any), eq(Optional.of(ClusterSpec.Type.content)), eq(CloudAccount.empty), any());
+ prepareAndActivate(application1, clusterSpec("mycluster"), 4, 1, resources, tester);
// Total of 8 nodes should now be in node-repo, 4 active hosts and 4 active nodes
assertEquals(8, tester.nodeRepository().nodes().list().size());
assertEquals(4, tester.nodeRepository().nodes().list(Node.State.active).nodeType(NodeType.host).size());
- assertEquals(Set.of("host-100-1", "host-101-1", "host-102-1", "host-103-1"),
+ assertEquals(Set.of("host100-1", "host101-1", "host102-1", "host103-1"),
tester.nodeRepository().nodes().list(Node.State.active).nodeType(NodeType.tenant).hostnames());
// Deploy new application
- ApplicationId application2 = ProvisioningTester.applicationId();
- prepareAndActivate(application2, clusterSpec("mycluster"), 4, 1, resources);
+ ApplicationId application2 = ProvisioningTester.applicationId("application2");
+ prepareAndActivate(application2, clusterSpec("mycluster"), 4, 1, resources, tester);
// Total of 12 nodes should now be in node-repo, 4 active hosts and 8 active nodes
assertEquals(12, tester.nodeRepository().nodes().list().size());
assertEquals(4, tester.nodeRepository().nodes().list(Node.State.active).nodeType(NodeType.host).size());
- assertEquals(Set.of("host-100-1", "host-100-2", "host-101-1", "host-101-2", "host-102-1", "host-102-2",
- "host-103-1", "host-103-2"),
+ assertEquals(Set.of("host100-1", "host100-2", "host101-1", "host101-2", "host102-1", "host102-2", "host103-1", "host103-2"),
tester.nodeRepository().nodes().list(Node.State.active).nodeType(NodeType.tenant).hostnames());
// Deploy new exclusive application
- ApplicationId application3 = ProvisioningTester.applicationId();
- mockHostProvisioner(hostProvisioner, "large", 3, application3);
- prepareAndActivate(application3, clusterSpec("mycluster", true), 4, 1, resources);
- verify(hostProvisioner).provisionHosts(eq(List.of(104, 105, 106, 107)), eq(NodeType.host), eq(resources), eq(application3),
- eq(Version.emptyVersion), eq(HostSharing.exclusive), eq(Optional.of(ClusterSpec.Type.content)), eq(CloudAccount.empty), any());
+ ApplicationId application3 = ProvisioningTester.applicationId("application3");
+ NodeResources exclusiveResources = new NodeResources(1, 10, 10, 1);
+ prepareAndActivate(application3, clusterSpec("mycluster", true), 4, 1, exclusiveResources, tester);
// Total of 20 nodes should now be in node-repo, 8 active hosts and 12 active nodes
assertEquals(20, tester.nodeRepository().nodes().list().size());
assertEquals(8, tester.nodeRepository().nodes().list(Node.State.active).nodeType(NodeType.host).size());
assertEquals(12, tester.nodeRepository().nodes().list(Node.State.active).nodeType(NodeType.tenant).size());
-
- verifyNoMoreInteractions(hostProvisioner);
}
@Test
public void in_place_resize_not_allowed_on_exclusive_to_hosts() {
- NodeResources initialResources = new NodeResources(2, 8, 10, 1);
- NodeResources smallResources = new NodeResources(1, 4, 10, 1);
+ var tester = tester(false);
+
+ NodeResources initialResources = new NodeResources(4, 80, 100, 1);
+ NodeResources smallResources = new NodeResources(1, 20, 50, 1);
ApplicationId application1 = ProvisioningTester.applicationId();
- mockHostProvisioner(hostProvisioner, "large", 3, null); // Provision shared hosts
- prepareAndActivate(application1, clusterSpec("mycluster"), 4, 1, initialResources);
+ prepareAndActivate(application1, clusterSpec("mycluster"), 4, 1, initialResources, tester);
ApplicationId application2 = ProvisioningTester.applicationId();
- mockHostProvisioner(hostProvisioner, "large", 3, application2); // Provision exclusive hosts
- prepareAndActivate(application2, clusterSpec("mycluster", true), 4, 1, initialResources);
+ prepareAndActivate(application2, clusterSpec("mycluster", true), 4, 1, initialResources, tester);
// Total of 16 nodes should now be in node-repo, 8 active hosts and 8 active nodes
assertEquals(16, tester.nodeRepository().nodes().list().size());
assertEquals(8, tester.nodeRepository().nodes().list(Node.State.active).nodeType(NodeType.tenant).size());
- prepareAndActivate(application1, clusterSpec("mycluster"), 4, 1, smallResources);
- prepareAndActivate(application2, clusterSpec("mycluster", true), 4, 1, smallResources);
+ prepareAndActivate(application1, clusterSpec("mycluster"), 4, 1, smallResources, tester);
+ prepareAndActivate(application2, clusterSpec("mycluster", true), 4, 1, smallResources, tester);
// 24 nodes: 4 shared hosts with 4 app1 nodes + 8 exclusive hosts with 8 nodes of app2, 4 of which are retired
NodeList nodes = tester.nodeRepository().nodes().list();
@@ -143,50 +117,51 @@ public class DynamicProvisioningTest {
@Test
public void avoids_allocating_to_empty_hosts() {
+ var tester = tester(false);
tester.makeReadyHosts(6, new NodeResources(12, 12, 200, 12));
tester.activateTenantHosts();
NodeResources resources = new NodeResources(1, 4, 10, 4);
ApplicationId application1 = ProvisioningTester.applicationId();
- prepareAndActivate(application1, clusterSpec("mycluster"), 4, 1, resources);
+ prepareAndActivate(application1, clusterSpec("mycluster"), 4, 1, resources, tester);
ApplicationId application2 = ProvisioningTester.applicationId();
- prepareAndActivate(application2, clusterSpec("mycluster"), 3, 1, resources);
+ prepareAndActivate(application2, clusterSpec("mycluster"), 3, 1, resources, tester);
ApplicationId application3 = ProvisioningTester.applicationId();
- prepareAndActivate(application3, clusterSpec("mycluster"), 3, 1, resources);
+ prepareAndActivate(application3, clusterSpec("mycluster"), 3, 1, resources, tester);
assertEquals(4, tester.nodeRepository().nodes().list().nodeType(NodeType.tenant).stream().map(Node::parentHostname).distinct().count());
ApplicationId application4 = ProvisioningTester.applicationId();
- prepareAndActivate(application4, clusterSpec("mycluster"), 3, 1, resources);
+ prepareAndActivate(application4, clusterSpec("mycluster"), 3, 1, resources, tester);
assertEquals(5, tester.nodeRepository().nodes().list().nodeType(NodeType.tenant).stream().map(Node::parentHostname).distinct().count());
}
@Test
public void retires_on_exclusivity_violation() {
+ var tester = tester(false);
ApplicationId application1 = ProvisioningTester.applicationId();
- NodeResources resources = new NodeResources(1, 4, 10, 1);
+ NodeResources resources = new NodeResources(4, 80, 100, 1);
- mockHostProvisioner(hostProvisioner, "large", 3, null); // Provision shared hosts
- prepareAndActivate(application1, clusterSpec("mycluster"), 4, 1, resources);
+ prepareAndActivate(application1, clusterSpec("mycluster"), 4, 1, resources, tester);
NodeList initialNodes = tester.nodeRepository().nodes().list().owner(application1);
assertEquals(4, initialNodes.size());
// Redeploy same application with exclusive=true
- mockHostProvisioner(hostProvisioner, "large", 3, application1);
- prepareAndActivate(application1, clusterSpec("mycluster", true), 4, 1, resources);
+ prepareAndActivate(application1, clusterSpec("mycluster", true), 4, 1, resources, tester);
assertEquals(8, tester.nodeRepository().nodes().list().owner(application1).size());
assertEquals(initialNodes, tester.nodeRepository().nodes().list().owner(application1).retired());
// Redeploy without exclusive again is no-op
- prepareAndActivate(application1, clusterSpec("mycluster"), 4, 1, resources);
+ prepareAndActivate(application1, clusterSpec("mycluster"), 4, 1, resources, tester);
assertEquals(8, tester.nodeRepository().nodes().list().owner(application1).size());
assertEquals(initialNodes, tester.nodeRepository().nodes().list().owner(application1).retired());
}
@Test
public void node_indices_are_unique_even_when_a_node_is_left_in_reserved_state() {
+ var tester = tester(false);
NodeResources resources = new NodeResources(10, 10, 10, 10);
ApplicationId app = ProvisioningTester.applicationId();
@@ -224,9 +199,9 @@ public class DynamicProvisioningTest {
List<Flavor> flavors = List.of(new Flavor("2x",
new NodeResources(2, 17, 200, 10, fast, remote)));
- ProvisioningTester tester = new ProvisioningTester.Builder().zone(zone)
+ ProvisioningTester tester = new ProvisioningTester.Builder().zone(zone(false))
.flavors(flavors)
- .hostProvisioner(new MockHostProvisioner(flavors, memoryTax, zone.cloud()))
+ .hostProvisioner(new MockHostProvisioner(flavors, memoryTax, zone(false).cloud()))
.nameResolver(nameResolver)
.resourcesCalculator(memoryTax, 0)
.build();
@@ -268,8 +243,8 @@ public class DynamicProvisioningTest {
InMemoryFlagSource flagSource = new InMemoryFlagSource();
List<Flavor> flavors = List.of(new Flavor("x86", new NodeResources(1, 4, 50, 0.1, fast, local, Architecture.x86_64)),
new Flavor("arm", new NodeResources(1, 4, 50, 0.1, fast, local, Architecture.arm64)));
- MockHostProvisioner hostProvisioner = new MockHostProvisioner(flavors, zone.cloud());
- ProvisioningTester tester = new ProvisioningTester.Builder().zone(zone)
+ MockHostProvisioner hostProvisioner = new MockHostProvisioner(flavors, zone(false).cloud());
+ ProvisioningTester tester = new ProvisioningTester.Builder().zone(zone(false))
.flavors(flavors)
.hostProvisioner(hostProvisioner)
.resourcesCalculator(0, 0)
@@ -312,9 +287,9 @@ public class DynamicProvisioningTest {
new Flavor("2x", new NodeResources(2, 20 - memoryTax, 200, 0.1, fast, remote)),
new Flavor("4x", new NodeResources(4, 40 - memoryTax, 400, 0.1, fast, remote)));
- ProvisioningTester tester = new ProvisioningTester.Builder().zone(zone)
+ ProvisioningTester tester = new ProvisioningTester.Builder().zone(zone(false))
.flavors(flavors)
- .hostProvisioner(new MockHostProvisioner(flavors, memoryTax, zone.cloud()))
+ .hostProvisioner(new MockHostProvisioner(flavors, memoryTax, zone(false).cloud()))
.nameResolver(nameResolver)
.resourcesCalculator(memoryTax, 0)
.build();
@@ -387,9 +362,9 @@ public class DynamicProvisioningTest {
new Flavor("4x", new NodeResources(4, 40 - memoryTax, 400, 0.1, fast, remote)),
new Flavor("4xl", new NodeResources(4, 40 - memoryTax, 400, 0.1, fast, local)));
- ProvisioningTester tester = new ProvisioningTester.Builder().zone(zone)
+ ProvisioningTester tester = new ProvisioningTester.Builder().zone(zone(false))
.flavors(flavors)
- .hostProvisioner(new MockHostProvisioner(flavors, memoryTax, zone.cloud()))
+ .hostProvisioner(new MockHostProvisioner(flavors, memoryTax, zone(false).cloud()))
.nameResolver(nameResolver)
.resourcesCalculator(memoryTax, 0)
.build();
@@ -422,9 +397,9 @@ public class DynamicProvisioningTest {
new Flavor("2xl", new NodeResources(2, 20 - memoryTax, 200, 0.1, fast, remote)),
new Flavor("4xl", new NodeResources(4, 40 - memoryTax, 400, 0.1, fast, remote)));
- ProvisioningTester tester = new ProvisioningTester.Builder().zone(zone)
+ ProvisioningTester tester = new ProvisioningTester.Builder().zone(zone(false))
.flavors(flavors)
- .hostProvisioner(new MockHostProvisioner(flavors, memoryTax, zone.cloud()))
+ .hostProvisioner(new MockHostProvisioner(flavors, memoryTax, zone(false).cloud()))
.nameResolver(nameResolver)
.resourcesCalculator(memoryTax, localDiskTax)
.build();
@@ -445,9 +420,9 @@ public class DynamicProvisioningTest {
public void gpu_host() {
List<Flavor> flavors = List.of(new Flavor("gpu", new NodeResources(4, 16, 125, 10, fast, local,
Architecture.x86_64, new NodeResources.GpuResources(1, 16))));
- ProvisioningTester tester = new ProvisioningTester.Builder().zone(zone)
+ ProvisioningTester tester = new ProvisioningTester.Builder().zone(zone(false))
.flavors(flavors)
- .hostProvisioner(new MockHostProvisioner(flavors, zone.cloud()))
+ .hostProvisioner(new MockHostProvisioner(flavors, zone(false).cloud()))
.nameResolver(nameResolver)
.build();
NodeResources resources = new NodeResources(4, 16, 125, 0.3,
@@ -458,16 +433,43 @@ public class DynamicProvisioningTest {
2, 1, resources);
}
- private void prepareAndActivate(ApplicationId application, ClusterSpec clusterSpec, int nodes, int groups, NodeResources resources) {
+ private Zone zone(boolean sharing) {
+ return new Zone(
+ Cloud.builder().dynamicProvisioning(true).allowHostSharing(sharing).build(),
+ SystemName.main,
+ Environment.prod,
+ RegionName.from("us-east"));
+ }
+
+ private ProvisioningTester tester(boolean sharing) {
+ var hostProvisioner = new MockHostProvisioner(new NodeFlavors(ProvisioningTester.createConfig()).getFlavors(), nameResolver, 0, zone(sharing).cloud());
+ return new ProvisioningTester.Builder().zone(zone(sharing)).hostProvisioner(hostProvisioner).nameResolver(nameResolver).build();
+ }
+
+ private void prepareAndActivate(ApplicationId application, ClusterSpec clusterSpec, int nodes, int groups, NodeResources resources,
+ ProvisioningTester tester) {
List<HostSpec> prepared = tester.prepare(application, clusterSpec, nodes, groups, resources);
NodeList provisionedHosts = tester.nodeRepository().nodes().list(Node.State.provisioned).nodeType(NodeType.host);
if (!provisionedHosts.isEmpty()) {
- tester.move(Node.State.ready, provisionedHosts.asList());
+ List<Node> hosts = provisionedHosts.asList()
+ .stream()
+ .map(h -> ((MockHostProvisioner)tester.hostProvisioner()).withIpAssigned(h))
+ .toList();
+ tester.move(Node.State.ready, hosts);
tester.activateTenantHosts();
}
+ assignIpAddresses(prepared, tester.nodeRepository());
tester.activate(application, prepared);
}
+ private void assignIpAddresses(Collection<HostSpec> hosts, NodeRepository nodeRepository) {
+ for (var host : hosts) {
+ try (var nodeLock = nodeRepository.nodes().lockAndGetRequired(host.hostname())) {
+ var node = nodeLock.node();
+ nodeRepository.nodes().write(node.with(node.ipConfig().withPrimary(nodeRepository.nameResolver().resolveAll(node.hostname()))), nodeLock);
+ }
+ }
+ }
private static ClusterSpec clusterSpec(String clusterId) {
return clusterSpec(clusterId, false);
}
@@ -482,39 +484,8 @@ public class DynamicProvisioningTest {
}
private static ClusterResources resources(int nodes, int groups, double vcpu, double memory, double disk,
- DiskSpeed diskSpeed, StorageType storageType) {
+ DiskSpeed diskSpeed, StorageType storageType) {
return new ClusterResources(nodes, groups, new NodeResources(vcpu, memory, disk, 0.1, diskSpeed, storageType));
}
- private void mockHostProvisioner(HostProvisioner hostProvisioner, String hostFlavorName, int numIps, ApplicationId exclusiveTo) {
- doAnswer(invocation -> {
- Flavor hostFlavor = tester.nodeRepository().flavors().getFlavorOrThrow(hostFlavorName);
- List<Integer> provisionIndexes = invocation.getArgument(0);
- NodeResources nodeResources = invocation.getArgument(2);
- Consumer<List<ProvisionedHost>> provisionedHostConsumer = invocation.getArgument(8);
-
- List<ProvisionedHost> provisionedHosts = provisionIndexes.stream()
- .map(hostIndex -> {
- String hostHostname = "host-" + hostIndex;
- String hostIp = "::" + hostIndex + ":0";
- nameResolver.addRecord(hostHostname, hostIp);
- Set<String> pool = IntStream.range(1, numIps + 1).mapToObj(i -> {
- String ip = "::" + hostIndex + ":" + i;
- nameResolver.addRecord(hostHostname + "-" + i, ip);
- return ip;
- }).collect(Collectors.toSet());
-
- Node parent = Node.create(hostHostname, new IP.Config(Set.of(hostIp), pool), hostHostname, hostFlavor, NodeType.host)
- .exclusiveToApplicationId(exclusiveTo).build();
- Node child = Node.reserve(Set.of("::" + hostIndex + ":1"), hostHostname + "-1", hostHostname, nodeResources, NodeType.tenant).build();
- ProvisionedHost provisionedHost = mock(ProvisionedHost.class);
- when(provisionedHost.generateHost()).thenReturn(parent);
- when(provisionedHost.generateNode()).thenReturn(child);
- return provisionedHost;
- }).toList();
- provisionedHostConsumer.accept(provisionedHosts);
- return null;
- }).when(hostProvisioner).provisionHosts(any(), any(), any(), any(), any(), any(), any(), any(), any());
- }
-
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java
index 5679201c77b..a19f986a177 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java
@@ -161,8 +161,7 @@ public class LoadBalancerProvisionerTest {
clusterRequest(ClusterSpec.Type.container, containerCluster),
clusterRequest(ClusterSpec.Type.content, contentCluster)));
List<LoadBalancer> activeLoadBalancers = lbApp1.get().stream()
- .filter(lb -> lb.state() == LoadBalancer.State.active)
- .collect(Collectors.toList());
+ .filter(lb -> lb.state() == LoadBalancer.State.active).toList();
assertEquals(1, activeLoadBalancers.size());
assertEquals(Set.of(), activeLoadBalancers.get(0).instance().get().reals());
}
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 2ea8d95bc9d..bf15e4bbe1c 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
@@ -80,6 +80,7 @@ public class ProvisioningTester {
private final NodeFlavors nodeFlavors;
private final ManualClock clock;
private final NodeRepository nodeRepository;
+ private final HostProvisioner hostProvisioner;
private final NodeRepositoryProvisioner provisioner;
private final CapacityPolicies capacityPolicies;
private final ProvisionLogger provisionLogger;
@@ -102,6 +103,7 @@ public class ProvisioningTester {
this.curator = curator;
this.nodeFlavors = nodeFlavors;
this.clock = new ManualClock();
+ this.hostProvisioner = hostProvisioner;
ProvisionServiceProvider provisionServiceProvider = new MockProvisionServiceProvider(loadBalancerService, hostProvisioner, resourcesCalculator);
this.nodeRepository = new NodeRepository(nodeFlavors,
provisionServiceProvider,
@@ -144,6 +146,7 @@ public class ProvisioningTester {
public Orchestrator orchestrator() { return nodeRepository.orchestrator(); }
public ManualClock clock() { return clock; }
public NodeRepositoryProvisioner provisioner() { return provisioner; }
+ public HostProvisioner hostProvisioner() { return hostProvisioner; }
public LoadBalancerServiceMock loadBalancerService() { return loadBalancerService; }
public CapacityPolicies capacityPolicies() { return capacityPolicies; }
public NodeList getNodes(ApplicationId id, Node.State ... inState) { return nodeRepository.nodes().list(inState).owner(id); }