summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@yahoo-inc.com>2016-10-05 10:06:51 +0200
committerJon Bratseth <bratseth@yahoo-inc.com>2016-10-05 10:06:51 +0200
commitd39f157ea6b68ff5bc80a5114c57d598cf732caa (patch)
treebc860c52cb48f43ae79697f36c659debdc7952e5
parent9107ffc588f7ad0daa4cb32ee8192be3f7ee3df2 (diff)
Support requiring specific capacity
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/provision/InMemoryProvisioner.java7
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java15
-rw-r--r--config-model/src/main/resources/schema/common.rnc1
-rw-r--r--config-model/src/main/resources/schema/containercluster.rnc1
-rw-r--r--config-model/src/main/resources/schema/content.rnc2
-rw-r--r--config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.java21
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/Capacity.java6
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java4
8 files changed, 48 insertions, 9 deletions
diff --git a/config-model/src/main/java/com/yahoo/config/model/provision/InMemoryProvisioner.java b/config-model/src/main/java/com/yahoo/config/model/provision/InMemoryProvisioner.java
index 5c9d03b434f..c4ac4d91001 100644
--- a/config-model/src/main/java/com/yahoo/config/model/provision/InMemoryProvisioner.java
+++ b/config-model/src/main/java/com/yahoo/config/model/provision/InMemoryProvisioner.java
@@ -101,8 +101,9 @@ public class InMemoryProvisioner implements HostProvisioner {
throw new IllegalArgumentException("Requested " + requestedCapacity.nodeCount() + " nodes in " +
groups + " groups, but the node count is not divisible into this number of groups");
- int capacity = failOnOutOfCapacity ? requestedCapacity.nodeCount() :
- Math.min(requestedCapacity.nodeCount(), freeNodes.get("default").size() + totalAllocatedTo(cluster));
+ int capacity = failOnOutOfCapacity || requestedCapacity.isRequired()
+ ? requestedCapacity.nodeCount()
+ : Math.min(requestedCapacity.nodeCount(), freeNodes.get("default").size() + totalAllocatedTo(cluster));
if (groups > capacity)
groups = capacity;
@@ -138,7 +139,7 @@ public class InMemoryProvisioner implements HostProvisioner {
int nextIndex = nextIndexInCluster.getOrDefault(new Pair<>(clusterGroup.type(), clusterGroup.id()), startIndex);
while (allocation.size() < nodesInGroup) {
- if (freeNodes.get(flavor).isEmpty()) throw new IllegalArgumentException("No nodes of flavor '" + flavor + "' available");
+ if (freeNodes.get(flavor).isEmpty()) throw new IllegalArgumentException("Insufficient capacity of flavor '" + flavor + "'");
Host newHost = freeNodes.removeValue(flavor, 0);
ClusterMembership membership = ClusterMembership.from(clusterGroup, nextIndex++);
allocation.add(new HostSpec(newHost.hostname(), newHost.aliases(), membership));
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java
index 7dabfdc600b..c83f6098a0f 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java
@@ -25,14 +25,22 @@ public class NodesSpecification {
private final int groups;
+ /**
+ * Whether the capacity amount specified is required or can it be relaxed
+ * at the discretion of the component fulfilling it
+ */
+ private final boolean required;
+
private final Optional<String> flavor;
private final Optional<String> dockerImage;
- private NodesSpecification(boolean dedicated, int count, int groups, Optional<String> flavor, Optional<String> dockerImage) {
+ private NodesSpecification(boolean dedicated, int count, int groups, boolean required,
+ Optional<String> flavor, Optional<String> dockerImage) {
this.dedicated = dedicated;
this.count = count;
this.groups = groups;
+ this.required = required;
this.flavor = flavor;
this.dockerImage = dockerImage;
}
@@ -41,6 +49,7 @@ public class NodesSpecification {
this(dedicated,
nodesElement.requiredIntegerAttribute("count"),
nodesElement.getIntegerAttribute("groups", 1),
+ nodesElement.getBooleanAttribute("required", false),
Optional.ofNullable(nodesElement.getStringAttribute("flavor")),
Optional.ofNullable(nodesElement.getStringAttribute("docker-image")));
}
@@ -78,7 +87,7 @@ public class NodesSpecification {
/** Returns a requirement from <code>count</code> nondedicated nodes in one group */
public static NodesSpecification nonDedicated(int count) {
- return new NodesSpecification(false, count, 1, Optional.empty(), Optional.empty());
+ return new NodesSpecification(false, count, 1, false, Optional.empty(), Optional.empty());
}
/**
@@ -95,7 +104,7 @@ public class NodesSpecification {
public Map<HostResource, ClusterMembership> provision(HostSystem hostSystem, ClusterSpec.Type clusterType, ClusterSpec.Id clusterId, DeployLogger logger) {
ClusterSpec cluster = ClusterSpec.request(clusterType, clusterId, dockerImage);
- return hostSystem.allocateHosts(cluster, Capacity.fromNodeCount(count, flavor), groups, logger);
+ return hostSystem.allocateHosts(cluster, Capacity.fromNodeCount(count, flavor, required), groups, logger);
}
@Override
diff --git a/config-model/src/main/resources/schema/common.rnc b/config-model/src/main/resources/schema/common.rnc
index 06e7b945c18..b89fe0d7fcb 100644
--- a/config-model/src/main/resources/schema/common.rnc
+++ b/config-model/src/main/resources/schema/common.rnc
@@ -23,6 +23,7 @@ Nodes = element nodes {
OptionalDedicatedNodes = element nodes {
attribute count { xsd:positiveInteger } &
attribute flavor { xsd:string }? &
+ attribute required { xsd:boolean }? &
attribute docker-image { xsd:string }? &
attribute dedicated { xsd:boolean }?
}
diff --git a/config-model/src/main/resources/schema/containercluster.rnc b/config-model/src/main/resources/schema/containercluster.rnc
index a5679151a03..17e38883755 100644
--- a/config-model/src/main/resources/schema/containercluster.rnc
+++ b/config-model/src/main/resources/schema/containercluster.rnc
@@ -194,6 +194,7 @@ NodesOfContainerCluster = element nodes {
(
attribute count { xsd:positiveInteger } &
attribute flavor { xsd:string }? &
+ attribute required { xsd:boolean }? &
attribute docker-image { xsd:string }?
)
|
diff --git a/config-model/src/main/resources/schema/content.rnc b/config-model/src/main/resources/schema/content.rnc
index 30b931053d5..c3a8386ac5e 100644
--- a/config-model/src/main/resources/schema/content.rnc
+++ b/config-model/src/main/resources/schema/content.rnc
@@ -216,6 +216,7 @@ ContentNodes = element nodes {
(
attribute count { xsd:positiveInteger } &
attribute flavor { xsd:string }? &
+ attribute required { xsd:boolean }? &
attribute docker-image { xsd:string }? &
attribute groups { xsd:positiveInteger }?
)
@@ -260,6 +261,7 @@ Group = element group {
element nodes {
attribute count { xsd:positiveInteger } &
attribute flavor { xsd:string }? &
+ attribute required { xsd:boolean }? &
attribute docker-image { xsd:string }? &
attribute groups { xsd:positiveInteger }?
}
diff --git a/config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.java b/config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.java
index 86fabdf26bc..8ed4539456a 100644
--- a/config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.java
+++ b/config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.java
@@ -522,6 +522,7 @@ public class ModelProvisioningTest {
assertEquals(1, clusterControllers.getContainers().size()); // TODO: Expected 5 with this feature reactivated
}
+ @Test
public void testClusterControllersAreNotPlacedOnRetiredNodes() {
String services =
"<?xml version='1.0' encoding='utf-8' ?>\n" +
@@ -907,6 +908,26 @@ public class ModelProvisioningTest {
assertThat(cluster.getRootGroup().getNodes().get(0).getConfigId(), is("bar/storage/0"));
}
+ @Test(expected = IllegalArgumentException.class)
+ public void testRequiringMoreNodesThanAreAvailable() throws ParseException {
+ String services =
+ "<?xml version='1.0' encoding='utf-8' ?>\n" +
+ "<services>" +
+ " <content version='1.0' id='bar'>" +
+ " <redundancy>1</redundancy>" +
+ " <documents>" +
+ " <document type='type1' mode='index'/>" +
+ " </documents>" +
+ " <nodes count='3' required='true'/>" +
+ " </content>" +
+ "</services>";
+
+ int numberOfHosts = 2;
+ VespaModelTester tester = new VespaModelTester();
+ tester.addHosts(numberOfHosts);
+ tester.createModel(services, false);
+ }
+
@Test
public void testUsingNodesCountAttributesAndGettingJustOneNode() {
String services =
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/Capacity.java b/config-provisioning/src/main/java/com/yahoo/config/provision/Capacity.java
index 7c13204c1e7..7894b722b58 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/Capacity.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/Capacity.java
@@ -75,7 +75,11 @@ public final class Capacity {
public static Capacity fromRequiredNodeCount(int nodeCount, Optional<String> flavor) {
return new Capacity(nodeCount, true, flavor, NodeType.tenant);
}
-
+
+ public static Capacity fromNodeCount(int nodeCount, Optional<String> flavor, boolean required) {
+ return new Capacity(nodeCount, required, flavor, NodeType.tenant);
+ }
+
/** Creates this from a node type */
public static Capacity fromRequiredNodeType(NodeType type) {
return new Capacity(0, true, Optional.empty(), type);
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java
index 6665833c1a2..a759a8fca37 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java
@@ -31,7 +31,7 @@ public class CapacityPolicies {
switch(zone.environment()) {
case dev : case test : return 1;
- case perf : return Math.min(requestedCapacity.nodeCount(), 10); // TODO: Decrease to 3 when isRequired is implemented
+ case perf : return Math.min(requestedCapacity.nodeCount(), 3);
case staging: return requestedNodes <= 1 ? requestedNodes : Math.max(2, requestedNodes / 10);
case prod : return ensureRedundancy(requestedCapacity.nodeCount());
default : throw new IllegalArgumentException("Unsupported environment " + zone.environment());
@@ -53,7 +53,7 @@ public class CapacityPolicies {
/**
* Throw if the node count is 1
-
+ *
* @return the argument node count
* @throws IllegalArgumentException if only one node is requested
*/