summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@vespa.ai>2023-05-15 20:47:16 +0200
committerJon Bratseth <bratseth@vespa.ai>2023-05-15 20:47:16 +0200
commit9406d9e50a3b0d183ec2d76595679eea41f0129f (patch)
treec75ae3cd85aa29522043ceb1f3f49e80fe6f8f5f
parentc2a220bed85e7af09f62d34de339b168d9507b87 (diff)
Make all node resource elements optional
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/provision/InMemoryProvisioner.java11
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java6
-rw-r--r--config-model/src/main/resources/schema/common.rnc6
-rw-r--r--config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.java30
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/test/VespaModelTester.java28
-rw-r--r--config-model/src/test/schema-test-files/services-hosted.xml2
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/NodeResources.java7
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Limits.java8
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java16
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java9
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java2
11 files changed, 86 insertions, 39 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 41697e61bf2..4b993f8e244 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
@@ -232,9 +232,14 @@ public class InMemoryProvisioner implements HostProvisioner {
}
// Minimal capacity policies
- private NodeResources decideResources(NodeResources requestedResources) {
- if (requestedResources.isUnspecified()) return defaultNodeResources;
- return requestedResources;
+ private NodeResources decideResources(NodeResources resources) {
+ if (resources.vcpuIsUnspecified())
+ resources = resources.withVcpu(defaultNodeResources.vcpu());
+ if (resources.memoryGbIsUnspecified())
+ resources = resources.withMemoryGb(defaultNodeResources.memoryGb());
+ if (resources.diskGbIsUnspecified())
+ resources = resources.withDiskGb(defaultNodeResources.diskGb());
+ return resources;
}
private List<HostSpec> allocateHostGroup(ClusterSpec clusterGroup, NodeResources requestedResourcesOrUnspecified,
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 c968e31325a..e70c555a366 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
@@ -307,9 +307,9 @@ public class NodesSpecification {
}
private static Pair<NodeResources, NodeResources> nodeResourcesFromResourcesElement(ModelElement element) {
- Pair<Double, Double> vcpu = toRange(element.requiredStringAttribute("vcpu"), .0, Double::parseDouble);
- Pair<Double, Double> memory = toRange(element.requiredStringAttribute("memory"), .0, s -> parseGbAmount(s, "B"));
- Pair<Double, Double> disk = toRange(element.requiredStringAttribute("disk"), .0, s -> parseGbAmount(s, "B"));
+ Pair<Double, Double> vcpu = toRange(element.stringAttribute("vcpu"), .0, Double::parseDouble);
+ Pair<Double, Double> memory = toRange(element.stringAttribute("memory"), .0, s -> parseGbAmount(s, "B"));
+ Pair<Double, Double> disk = toRange(element.stringAttribute("disk"), .0, s -> parseGbAmount(s, "B"));
Pair<Double, Double> bandwith = toRange(element.stringAttribute("bandwidth"), .3, s -> parseGbAmount(s, "BPS"));
NodeResources.DiskSpeed diskSpeed = parseOptionalDiskSpeed(element.stringAttribute("disk-speed"));
NodeResources.StorageType storageType = parseOptionalStorageType(element.stringAttribute("storage-type"));
diff --git a/config-model/src/main/resources/schema/common.rnc b/config-model/src/main/resources/schema/common.rnc
index 538a8f069f5..21f3399a027 100644
--- a/config-model/src/main/resources/schema/common.rnc
+++ b/config-model/src/main/resources/schema/common.rnc
@@ -23,9 +23,9 @@ Nodes = element nodes {
}
Resources = element resources {
- attribute vcpu { xsd:double { minExclusive = "0.0" } | xsd:string } &
- attribute memory { xsd:string } &
- attribute disk { xsd:string } &
+ attribute vcpu { xsd:double { minExclusive = "0.0" } | xsd:string }? &
+ attribute memory { xsd:string }? &
+ attribute disk { xsd:string }? &
attribute disk-speed { xsd:string }? &
attribute storage-type { xsd:string }? &
attribute architecture { xsd:string }? &
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 f1dffe53ad7..5472ea2ca82 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
@@ -1542,7 +1542,7 @@ public class ModelProvisioningTest {
tester.addHosts(new NodeResources(8, 200, 1000000, 0.3), 5); // Content-foo
tester.addHosts(new NodeResources(10, 64, 200, 0.3), 6); // Content-bar
tester.addHosts(new NodeResources(0.5, 2, 10, 0.3), 6); // Cluster-controller
- VespaModel model = tester.createModel(services, true, 0);
+ VespaModel model = tester.createModel(services, true, NodeResources.unspecified(), 0);
assertEquals(totalHosts, model.getRoot().hostSystem().getHosts().size());
}
@@ -2425,7 +2425,7 @@ public class ModelProvisioningTest {
assertTrue(config.build().server().stream().noneMatch(ZookeeperServerConfig.Server::joining), "Initial servers are not joining");
}
{
- VespaModel nextModel = tester.createModel(Zone.defaultZone(), servicesXml.apply(3), true, false, false, 0, Optional.of(model), new DeployState.Builder(), "node-1-3-50-04", "node-1-3-50-03");
+ VespaModel nextModel = tester.createModel(Zone.defaultZone(), servicesXml.apply(3), true, false, false, NodeResources.unspecified(), 0, Optional.of(model), new DeployState.Builder(), "node-1-3-50-04", "node-1-3-50-03");
ApplicationContainerCluster cluster = nextModel.getContainerClusters().get("zk");
ZookeeperServerConfig.Builder config = new ZookeeperServerConfig.Builder();
cluster.getContainers().forEach(c -> c.getConfig(config));
@@ -2491,13 +2491,35 @@ public class ModelProvisioningTest {
VespaModelTester tester = new VespaModelTester();
tester.addHosts(new NodeResources(1, 3, 10, 5, NodeResources.DiskSpeed.slow), 5);
- VespaModel model = tester.createModel(services, true, 0);
+ VespaModel model = tester.createModel(services, true, NodeResources.unspecified(), 0);
ContentSearchCluster cluster = model.getContentClusters().get("test").getSearch();
assertEquals(2, cluster.getSearchNodes().size());
assertEquals(40, getProtonConfig(cluster, 0).hwinfo().disk().writespeed(), 0.001);
assertEquals(40, getProtonConfig(cluster, 1).hwinfo().disk().writespeed(), 0.001);
}
+ @Test
+ public void require_that_resources_can_be_partially_specified() {
+ String services = joinLines("<?xml version='1.0' encoding='utf-8' ?>",
+ "<services>",
+ " <content version='1.0' id='test'>",
+ " <redundancy>2</redundancy>" +
+ " <documents>",
+ " <document type='type1' mode='index'/>",
+ " </documents>",
+ " <nodes count='2'>",
+ " <resources vcpu='1'/>",
+ " </nodes>",
+ " </content>",
+ "</services>");
+
+ VespaModelTester tester = new VespaModelTester();
+ tester.addHosts(new NodeResources(1, 3, 10, 5), 5);
+ VespaModel model = tester.createModel(services, true, new NodeResources(1.0, 3.0, 9.0, 1.0), 0);
+ ContentSearchCluster cluster = model.getContentClusters().get("test").getSearch();
+ assertEquals(2, cluster.getSearchNodes().size());
+ }
+
private static ProtonConfig getProtonConfig(ContentSearchCluster cluster, int searchNodeIdx) {
ProtonConfig.Builder builder = new ProtonConfig.Builder();
List<SearchNode> searchNodes = cluster.getSearchNodes();
@@ -2542,7 +2564,7 @@ public class ModelProvisioningTest {
VespaModelTester tester = new VespaModelTester();
tester.addHosts(new NodeResources(1, 3, 10, 1), 4);
tester.addHosts(new NodeResources(1, 128, 100, 0.3), 1);
- VespaModel model = tester.createModel(services, true, 0);
+ VespaModel model = tester.createModel(services, true, NodeResources.unspecified(), 0);
ContentSearchCluster cluster = model.getContentClusters().get("test").getSearch();
ProtonConfig cfg = getProtonConfig(model, cluster.getSearchNodes().get(0).getConfigId());
assertEquals(2000, cfg.flush().memory().maxtlssize()); // from config override
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/test/VespaModelTester.java b/config-model/src/test/java/com/yahoo/vespa/model/test/VespaModelTester.java
index 500fb0838e1..e7d46e1c009 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/test/VespaModelTester.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/test/VespaModelTester.java
@@ -130,51 +130,60 @@ public class VespaModelTester {
/** Creates a model which uses 0 as start index */
public VespaModel createModel(String services, String hosts, boolean failOnOutOfCapacity, String ... retiredHostNames) {
- return createModel(Zone.defaultZone(), services, hosts, failOnOutOfCapacity, false, false, 0,
+ return createModel(Zone.defaultZone(), services, hosts, failOnOutOfCapacity, false, false,
+ NodeResources.unspecified(), 0,
Optional.empty(), new DeployState.Builder(), retiredHostNames);
}
/** Creates a model which uses 0 as start index */
public VespaModel createModel(String services, boolean failOnOutOfCapacity, DeployState.Builder builder) {
- return createModel(Zone.defaultZone(), services, failOnOutOfCapacity, false, false, 0, Optional.empty(), builder);
+ return createModel(Zone.defaultZone(), services, failOnOutOfCapacity, false, false,
+ NodeResources.unspecified(), 0, Optional.empty(), builder);
}
/** Creates a model which uses 0 as start index */
public VespaModel createModel(String services, boolean failOnOutOfCapacity, boolean useMaxResources, String ... retiredHostNames) {
- return createModel(Zone.defaultZone(), services, failOnOutOfCapacity, useMaxResources, false, 0,
+ return createModel(Zone.defaultZone(), services, failOnOutOfCapacity, useMaxResources, false,
+ NodeResources.unspecified(), 0,
Optional.empty(), new DeployState.Builder(), retiredHostNames);
}
/** Creates a model which uses 0 as start index */
public VespaModel createModel(String services, boolean failOnOutOfCapacity, boolean useMaxResources, boolean alwaysReturnOneNode, String ... retiredHostNames) {
- return createModel(Zone.defaultZone(), services, failOnOutOfCapacity, useMaxResources, alwaysReturnOneNode, 0,
+ return createModel(Zone.defaultZone(), services, failOnOutOfCapacity, useMaxResources, alwaysReturnOneNode,
+ NodeResources.unspecified(), 0,
Optional.empty(), new DeployState.Builder(), retiredHostNames);
}
/** Creates a model which uses 0 as start index */
- public VespaModel createModel(String services, boolean failOnOutOfCapacity, int startIndexForClusters, String ... retiredHostNames) {
- return createModel(Zone.defaultZone(), services, failOnOutOfCapacity, false, false, startIndexForClusters,
+ public VespaModel createModel(String services, boolean failOnOutOfCapacity, NodeResources defaultResources,
+ int startIndexForClusters, String ... retiredHostNames) {
+ return createModel(Zone.defaultZone(), services, failOnOutOfCapacity, false, false,
+ defaultResources, startIndexForClusters,
Optional.empty(), new DeployState.Builder(), retiredHostNames);
}
/** Creates a model which uses 0 as start index */
public VespaModel createModel(Zone zone, String services, boolean failOnOutOfCapacity, String ... retiredHostNames) {
- return createModel(zone, services, failOnOutOfCapacity, false, false, 0,
+ return createModel(zone, services, failOnOutOfCapacity, false, false, NodeResources.unspecified(), 0,
Optional.empty(), new DeployState.Builder(), retiredHostNames);
}
/** Creates a model which uses 0 as start index */
public VespaModel createModel(Zone zone, String services, boolean failOnOutOfCapacity,
DeployState.Builder deployStateBuilder, String ... retiredHostNames) {
- return createModel(zone, services, failOnOutOfCapacity, false, false, 0,
+ return createModel(zone, services, failOnOutOfCapacity, false, false,
+ NodeResources.unspecified(),0,
Optional.empty(), deployStateBuilder, retiredHostNames);
}
public VespaModel createModel(Zone zone, String services, boolean failOnOutOfCapacity, boolean useMaxResources,
boolean alwaysReturnOneNode,
+ NodeResources defaultResources,
int startIndexForClusters, Optional<VespaModel> previousModel,
DeployState.Builder deployStatebuilder, String ... retiredHostNames) {
return createModel(zone, services, null, failOnOutOfCapacity, useMaxResources, alwaysReturnOneNode,
+ defaultResources,
startIndexForClusters, previousModel, deployStatebuilder, retiredHostNames);
}
/**
@@ -189,6 +198,7 @@ public class VespaModelTester {
*/
public VespaModel createModel(Zone zone, String services, String hosts, boolean failOnOutOfCapacity, boolean useMaxResources,
boolean alwaysReturnOneNode,
+ NodeResources defaultResources,
int startIndexForClusters, Optional<VespaModel> previousModel,
DeployState.Builder deployStatebuilder, String ... retiredHostNames) {
VespaModelCreatorWithMockPkg modelCreatorWithMockPkg = new VespaModelCreatorWithMockPkg(hosts, services, generateSchemas("type1"));
@@ -200,7 +210,7 @@ public class VespaModelTester {
useMaxResources,
alwaysReturnOneNode,
false,
- NodeResources.unspecified(),
+ defaultResources,
startIndexForClusters,
retiredHostNames);
provisioner.setEnvironment(zone.environment());
diff --git a/config-model/src/test/schema-test-files/services-hosted.xml b/config-model/src/test/schema-test-files/services-hosted.xml
index 1246f06c58f..db4f9fa34ab 100644
--- a/config-model/src/test/schema-test-files/services-hosted.xml
+++ b/config-model/src/test/schema-test-files/services-hosted.xml
@@ -25,7 +25,7 @@
<content id="search" version="1.0">
<redundancy>2</redundancy>
<nodes count="7" flavor="large" groups="12" no-vespamalloc="proton distributord">
- <resources vcpu="3.0" memory="32000.0Mb" disk="300 Gb"/>
+ <resources memory="32000.0Mb" disk="300 Gb"/>
</nodes>
</content>
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/NodeResources.java b/config-provisioning/src/main/java/com/yahoo/config/provision/NodeResources.java
index 9ca10091129..d1fd409fc93 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/NodeResources.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/NodeResources.java
@@ -210,6 +210,10 @@ public class NodeResources {
public Architecture architecture() { return architecture; }
public GpuResources gpuResources() { return gpuResources; }
+ public boolean vcpuIsUnspecified() { return vcpu == 0; }
+ public boolean memoryGbIsUnspecified() { return memoryGb == 0; }
+ public boolean diskGbIsUnspecified() { return diskGb == 0; }
+
/** Returns the standard cost of these resources, in dollars per hour */
public double cost() {
return (vcpu * cpuUnitCost) +
@@ -219,19 +223,16 @@ public class NodeResources {
}
public NodeResources withVcpu(double vcpu) {
- ensureSpecified();
if (vcpu == this.vcpu) return this;
return new NodeResources(vcpu, memoryGb, diskGb, bandwidthGbps, diskSpeed, storageType, architecture, gpuResources);
}
public NodeResources withMemoryGb(double memoryGb) {
- ensureSpecified();
if (memoryGb == this.memoryGb) return this;
return new NodeResources(vcpu, memoryGb, diskGb, bandwidthGbps, diskSpeed, storageType, architecture, gpuResources);
}
public NodeResources withDiskGb(double diskGb) {
- ensureSpecified();
if (diskGb == this.diskGb) return this;
return new NodeResources(vcpu, memoryGb, diskGb, bandwidthGbps, diskSpeed, storageType, architecture, gpuResources);
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Limits.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Limits.java
index 70e42fe712f..46eb9e9014a 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Limits.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Limits.java
@@ -68,10 +68,10 @@ public class Limits {
public Limits fullySpecified(ClusterSpec clusterSpec, NodeRepository nodeRepository, ApplicationId applicationId) {
if (this.isEmpty()) throw new IllegalStateException("Unspecified limits can not be made fully specified");
- var defaultResources = new CapacityPolicies(nodeRepository).defaultNodeResources(clusterSpec, applicationId);
- var specifiedMin = min.nodeResources().isUnspecified() ? min.with(defaultResources) : min;
- var specifiedMax = max.nodeResources().isUnspecified() ? max.with(defaultResources) : max;
- return new Limits(specifiedMin, specifiedMax, groupSize);
+ var capacityPolicies = new CapacityPolicies(nodeRepository);
+ return new Limits(capacityPolicies.specifyFully(min, clusterSpec, applicationId),
+ capacityPolicies.specifyFully(max, clusterSpec, applicationId),
+ groupSize);
}
private double between(double min, double max, double value) {
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 5732e94956a..8cff57e3005 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
@@ -84,7 +84,21 @@ public class CapacityPolicies {
return target;
}
- public NodeResources defaultNodeResources(ClusterSpec clusterSpec, ApplicationId applicationId) {
+ public ClusterResources specifyFully(ClusterResources resources, ClusterSpec clusterSpec, ApplicationId applicationId) {
+ return resources.with(specifyFully(resources.nodeResources(), clusterSpec, applicationId));
+ }
+
+ public NodeResources specifyFully(NodeResources resources, ClusterSpec clusterSpec, ApplicationId applicationId) {
+ if (resources.vcpuIsUnspecified())
+ resources = resources.withVcpu(defaultResources(clusterSpec, applicationId).vcpu());
+ if (resources.memoryGbIsUnspecified())
+ resources = resources.withMemoryGb(defaultResources(clusterSpec, applicationId).memoryGb());
+ if (resources.diskGbIsUnspecified())
+ resources = resources.withDiskGb(defaultResources(clusterSpec, applicationId).diskGb());
+ return resources;
+ }
+
+ private NodeResources defaultResources(ClusterSpec clusterSpec, ApplicationId applicationId) {
if (clusterSpec.type() == ClusterSpec.Type.admin) {
Architecture architecture = adminClusterArchitecture(applicationId);
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java
index 1eef438a64e..237a6657ccc 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java
@@ -124,9 +124,7 @@ public class NodeRepositoryProvisioner implements Provisioner {
}
private NodeResources getNodeResources(ClusterSpec cluster, NodeResources nodeResources, ApplicationId applicationId) {
- return nodeResources.isUnspecified()
- ? capacityPolicies.defaultNodeResources(cluster, applicationId)
- : nodeResources;
+ return capacityPolicies.specifyFully(nodeResources, cluster, applicationId);
}
@Override
@@ -184,10 +182,7 @@ public class NodeRepositoryProvisioner implements Provisioner {
}
private ClusterResources initialResourcesFrom(Capacity requested, ClusterSpec clusterSpec, ApplicationId applicationId) {
- var initial = requested.minResources();
- if (initial.nodeResources().isUnspecified())
- initial = initial.with(capacityPolicies.defaultNodeResources(clusterSpec, applicationId));
- return initial;
+ return capacityPolicies.specifyFully(requested.minResources(), clusterSpec, applicationId);
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java
index f1cf33d0477..36d0e464b3d 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java
@@ -358,7 +358,7 @@ public class AutoscalingTest {
.build();
NodeResources defaultResources =
- new CapacityPolicies(fixture.tester().nodeRepository()).defaultNodeResources(fixture.clusterSpec, fixture.applicationId);
+ new CapacityPolicies(fixture.tester().nodeRepository()).specifyFully(NodeResources.unspecified(), fixture.clusterSpec, fixture.applicationId);
fixture.tester().assertResources("Min number of nodes and default resources",
2, 1, defaultResources,