summaryrefslogtreecommitdiffstats
path: root/node-repository
diff options
context:
space:
mode:
authorValerij Fredriksen <valerijf@verizonmedia.com>2019-02-13 21:45:26 +0100
committerValerij Fredriksen <valerijf@verizonmedia.com>2019-02-14 14:09:02 +0100
commit28740d3322e3f3d5ea7d7456c13dbcf80e8c0c7d (patch)
treece343c7607b06e77d9deeba6e0df866c83e307dc /node-repository
parent28f9beb798831c3f964d648e5507b897b798e5db (diff)
Pass provision indexes to host provisioner
Diffstat (limited to 'node-repository')
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java15
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java7
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostProvisioner.java5
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerProvisionTest.java26
4 files changed, 35 insertions, 18 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java
index de8fb703462..2f100b00982 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java
@@ -15,6 +15,7 @@ import com.yahoo.transaction.NestedTransaction;
import com.yahoo.transaction.Transaction;
import com.yahoo.vespa.curator.Curator;
import com.yahoo.vespa.curator.Lock;
+import com.yahoo.vespa.curator.recipes.CuratorCounter;
import com.yahoo.vespa.curator.transaction.CuratorOperations;
import com.yahoo.vespa.curator.transaction.CuratorTransaction;
import com.yahoo.vespa.hosted.provision.Node;
@@ -41,6 +42,7 @@ import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
+import java.util.stream.IntStream;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toMap;
@@ -69,12 +71,14 @@ public class CuratorDatabaseClient {
private final CuratorDatabase curatorDatabase;
private final Clock clock;
private final Zone zone;
+ private final CuratorCounter provisionIndexCounter;
public CuratorDatabaseClient(NodeFlavors flavors, Curator curator, Clock clock, Zone zone, boolean useCache) {
this.nodeSerializer = new NodeSerializer(flavors);
this.zone = zone;
this.curatorDatabase = new CuratorDatabase(curator, root, useCache);
this.clock = clock;
+ this.provisionIndexCounter = new CuratorCounter(curator, root.append("provisionIndexCounter").getAbsolute());
initZK();
}
@@ -92,6 +96,7 @@ public class CuratorDatabaseClient {
curatorDatabase.create(firmwareCheckPath());
curatorDatabase.create(loadBalancersRoot);
curatorDatabase.create(flagsRoot);
+ provisionIndexCounter.initialize(100);
}
/**
@@ -515,4 +520,14 @@ public class CuratorDatabaseClient {
return CuratorOperations.create(path.getAbsolute(), data);
}
+ /** Returns a given number of unique provision indexes */
+ public List<Integer> getProvisionIndexes(int numIndexes) {
+ if (numIndexes < 1)
+ throw new IllegalArgumentException("numIndexes must be a positive integer, was " + numIndexes);
+
+ int firstProvisionIndex = (int) provisionIndexCounter.add(numIndexes) - numIndexes;
+ return IntStream.range(0, numIndexes)
+ .mapToObj(i -> firstProvisionIndex + i)
+ .collect(Collectors.toList());
+ }
}
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 6ff683c1d7e..a8b48751d23 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
@@ -77,8 +77,11 @@ public class GroupPreparer {
allocation.offer(prioritizer.prioritize());
if (dynamicProvisioningEnabled) {
- List<ProvisionedHost> provisionedHosts = allocation.getFulfilledDockerDeficit().map(deficit ->
- hostProvisioner.get().provisionHosts(deficit.getCount(), deficit.getFlavor())).orElseGet(List::of);
+ List<ProvisionedHost> provisionedHosts = allocation.getFulfilledDockerDeficit()
+ .map(deficit -> hostProvisioner.get().provisionHosts(
+ nodeRepository.database().getProvisionIndexes(deficit.getCount()),
+ deficit.getFlavor()))
+ .orElseGet(List::of);
// At this point we have started provisioning of the hosts, the first priority is to make sure that
// the returned hosts are added to the node-repo so that they are tracked by the provision maintainers
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostProvisioner.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostProvisioner.java
index 34fbaf94478..79296e58045 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostProvisioner.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostProvisioner.java
@@ -17,12 +17,13 @@ public interface HostProvisioner {
/**
* Schedule provisioning of a given number of hosts.
*
- * @param numHosts number of hosts to provision
+ * @param provisionIndexes List of unique provision indexes which will be used to generate the host hostnames
+ * on the form of <code>[prefix][index].[domain]</code>
* @param nodeFlavor Vespa flavor of the node that will run on this host. The resulting provisioned host
* will be of a flavor that is at least as big or bigger than this.
* @return list of {@link ProvisionedHost} describing the provisioned hosts and nodes on them.
*/
- List<ProvisionedHost> provisionHosts(int numHosts, Flavor nodeFlavor);
+ List<ProvisionedHost> provisionHosts(List<Integer> provisionIndexes, Flavor nodeFlavor);
/**
* Continue provisioning of given list of Nodes.
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerProvisionTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerProvisionTest.java
index 38352e033dd..60e9289b9bf 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerProvisionTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerProvisionTest.java
@@ -20,11 +20,9 @@ import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
-import java.util.stream.IntStream;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -50,13 +48,13 @@ public class DynamicDockerProvisionTest {
mockHostProvisioner(hostProvisioner, tester.nodeRepository().getAvailableFlavors().getFlavorOrThrow("small"));
List<HostSpec> hostSpec = tester.prepare(application1, clusterSpec("myContent.t1.a1"), 4, 1, flavor.canonicalName());
- verify(hostProvisioner).provisionHosts(4, flavor);
+ verify(hostProvisioner).provisionHosts(List.of(100, 101, 102, 103), flavor);
// Total of 8 nodes should now be in node-repo, 4 hosts in state provisioned, and 4 reserved nodes
assertEquals(8, tester.nodeRepository().list().size());
assertEquals(4, tester.nodeRepository().getNodes(NodeType.host, Node.State.provisioned).size());
assertEquals(4, tester.nodeRepository().getNodes(NodeType.tenant, Node.State.reserved).size());
- assertEquals(List.of("host-1-1", "host-2-1", "host-3-1", "host-4-1"),
+ assertEquals(List.of("host-100-1", "host-101-1", "host-102-1", "host-103-1"),
hostSpec.stream().map(HostSpec::hostname).collect(Collectors.toList()));
}
@@ -70,7 +68,7 @@ public class DynamicDockerProvisionTest {
mockHostProvisioner(hostProvisioner, tester.nodeRepository().getAvailableFlavors().getFlavorOrThrow("small"));
tester.prepare(application, clusterSpec("myContent.t2.a2"), 2, 1, flavor.canonicalName());
- verify(hostProvisioner).provisionHosts(2, flavor);
+ verify(hostProvisioner).provisionHosts(List.of(100, 101), flavor);
}
@Test
@@ -78,12 +76,13 @@ public class DynamicDockerProvisionTest {
ApplicationId application = tester.makeApplicationId();
Flavor flavor = tester.nodeRepository().getAvailableFlavors().getFlavorOrThrow("dockerSmall");
+ List<Integer> expectedProvisionIndexes = List.of(100, 101);
mockHostProvisioner(hostProvisioner, tester.nodeRepository().getAvailableFlavors().getFlavorOrThrow("large"));
tester.prepare(application, clusterSpec("myContent.t2.a2"), 2, 1, flavor.canonicalName());
- verify(hostProvisioner).provisionHosts(2, flavor);
+ verify(hostProvisioner).provisionHosts(expectedProvisionIndexes, flavor);
// Ready the provisioned hosts, add an IP addreses to pool and activate them
- for (int i = 1; i < 3; i++) {
+ for (Integer i : expectedProvisionIndexes) {
String hostname = "host-" + i;
Node host = tester.nodeRepository().getNode(hostname).orElseThrow()
.withIpAddressPool(Set.of("::" + i + ":2")).withIpAddresses(Set.of("::" + i + ":0"));
@@ -95,7 +94,7 @@ public class DynamicDockerProvisionTest {
mockHostProvisioner(hostProvisioner, tester.nodeRepository().getAvailableFlavors().getFlavorOrThrow("small"));
tester.prepare(application, clusterSpec("another-id"), 2, 1, flavor.canonicalName());
// Verify there was only 1 call to provision hosts (during the first prepare)
- verify(hostProvisioner).provisionHosts(anyInt(), any());
+ verify(hostProvisioner).provisionHosts(any(), any());
// Node-repo should now consist of 2 active hosts with 2 reserved nodes on each
assertEquals(6, tester.nodeRepository().list().size());
@@ -121,15 +120,14 @@ public class DynamicDockerProvisionTest {
return ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from(clusterId), Version.fromString("6.42"), false, Collections.emptySet());
}
+ @SuppressWarnings("unchecked")
private static void mockHostProvisioner(HostProvisioner hostProvisioner, Flavor hostFlavor) {
- final int[] numProvisioned = { 0 };
doAnswer(invocation -> {
- int numHosts = (int) invocation.getArguments()[0];
+ List<Integer> provisionIndexes = (List<Integer>) invocation.getArguments()[0];
Flavor nodeFlavor = (Flavor) invocation.getArguments()[1];
- return IntStream.range(0, numHosts)
- .map(i -> ++numProvisioned[0])
- .mapToObj(i -> new ProvisionedHost("id-" + i, "host-" + i, hostFlavor, "host-" + i + "-1", nodeFlavor))
+ return provisionIndexes.stream()
+ .map(i -> new ProvisionedHost("id-" + i, "host-" + i, hostFlavor, "host-" + i + "-1", nodeFlavor))
.collect(Collectors.toList());
- }).when(hostProvisioner).provisionHosts(anyInt(), any());
+ }).when(hostProvisioner).provisionHosts(any(), any());
}
}