summaryrefslogtreecommitdiffstats
path: root/config-model
diff options
context:
space:
mode:
authorAndreas Eriksen <andreer@verizonmedia.com>2021-05-04 16:31:15 +0200
committerGitHub <noreply@github.com>2021-05-04 16:31:15 +0200
commit1a206c055d516c5775e68a80cdd9338c5633a44a (patch)
tree90dc62a3600090e2086e32425a46e0095a4e9801 /config-model
parent986202394f3e068ad7871b1b333e006fd1b97408 (diff)
validate max capacity (#17685)
* validate max capacity * test actual spend above quota
Diffstat (limited to 'config-model')
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/QuotaValidator.java32
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/application/validation/QuotaValidatorTest.java19
2 files changed, 42 insertions, 9 deletions
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/QuotaValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/QuotaValidator.java
index d2b465e9d02..d22affaf5a3 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/QuotaValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/QuotaValidator.java
@@ -3,15 +3,17 @@ package com.yahoo.vespa.model.application.validation;
import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.provision.Capacity;
+import com.yahoo.config.provision.ClusterResources;
import com.yahoo.config.provision.ClusterSpec;
-import com.yahoo.config.provision.HostSpec;
+import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.SystemName;
import com.yahoo.vespa.model.VespaModel;
+import org.jetbrains.annotations.NotNull;
import java.math.BigDecimal;
import java.util.Locale;
import java.util.Map;
-import java.util.Objects;
+import java.util.Set;
import java.util.logging.Logger;
import java.util.stream.Collectors;
@@ -23,6 +25,7 @@ import java.util.stream.Collectors;
public class QuotaValidator extends Validator {
private static final Logger log = Logger.getLogger(QuotaValidator.class.getName());
+ private static final Capacity zeroCapacity = Capacity.from(new ClusterResources(0, 0, NodeResources.zero()));
@Override
public void validate(VespaModel model, DeployState deployState) {
@@ -32,18 +35,35 @@ public class QuotaValidator extends Validator {
}
private void validateBudget(BigDecimal budget, VespaModel model, SystemName systemName) {
- var spend = model.allocatedHosts().getHosts().stream()
+
+ var maxSpend = model.allClusters().stream()
+ .filter(id -> !adminClusterIds(model).contains(id))
+ .map(id -> model.provisioned().all().getOrDefault(id, zeroCapacity))
+ .mapToDouble(c -> c.maxResources().cost())
+ .sum();
+
+ var actualSpend = model.allocatedHosts().getHosts().stream()
.filter(hostSpec -> hostSpec.membership().get().cluster().type() != ClusterSpec.Type.admin)
.mapToDouble(hostSpec -> hostSpec.advertisedResources().cost())
.sum();
- if (Math.abs(spend) < 0.01) {
+ if (Math.abs(actualSpend) < 0.01) {
log.warning("Deploying application " + model.applicationPackage().getApplicationId() + " with zero budget use. This is suspicious, but not blocked");
return;
}
- throwIfBudgetNegative(spend, budget, systemName);
- throwIfBudgetExceeded(spend, budget, systemName);
+ throwIfBudgetNegative(actualSpend, budget, systemName);
+ throwIfBudgetExceeded(actualSpend, budget, systemName);
+ throwIfBudgetExceeded(maxSpend, budget, systemName);
+ }
+
+ @NotNull
+ private Set<ClusterSpec.Id> adminClusterIds(VespaModel model) {
+ return model.allocatedHosts().getHosts().stream()
+ .map(hostSpec -> hostSpec.membership().orElseThrow().cluster())
+ .filter(cluster -> cluster.type() == ClusterSpec.Type.admin)
+ .map(ClusterSpec::id)
+ .collect(Collectors.toUnmodifiableSet());
}
/** Check that all clusters in the application do not exceed the quota max cluster size. */
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/QuotaValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/QuotaValidatorTest.java
index d92ace2939a..e99a92b530a 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/QuotaValidatorTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/QuotaValidatorTest.java
@@ -26,7 +26,7 @@ public class QuotaValidatorTest {
@Test
public void test_deploy_under_quota() {
var tester = new ValidationTester(8, false, new TestProperties().setHostedVespa(true).setQuota(quota).setZone(publicZone));
- tester.deploy(null, getServices("testCluster", 5), Environment.prod, null);
+ tester.deploy(null, getServices("testCluster", 4), Environment.prod, null);
}
@Test
@@ -54,7 +54,7 @@ public class QuotaValidatorTest {
@Test
public void test_deploy_above_quota_budget_in_publiccd() {
- var tester = new ValidationTester(13, false, new TestProperties().setHostedVespa(true).setQuota(quota).setZone(publicCdZone));
+ var tester = new ValidationTester(13, false, new TestProperties().setHostedVespa(true).setQuota(quota.withBudget(BigDecimal.ONE)).setZone(publicCdZone));
try {
tester.deploy(null, getServices("testCluster", 10), Environment.prod, null);
fail();
@@ -65,6 +65,19 @@ public class QuotaValidatorTest {
}
@Test
+ public void test_deploy_max_resources_above_quota() {
+ var tester = new ValidationTester(13, false, new TestProperties().setHostedVespa(true).setQuota(quota).setZone(publicCdZone));
+ try {
+ tester.deploy(null, getServices("testCluster", 10), Environment.prod, null);
+ fail();
+ } catch (RuntimeException e) {
+ assertEquals("publiccd: Please free up some capacity! This deployment's quota use ($-.--) exceeds reserved quota ($-.--)!",
+ ValidationTester.censorNumbers(e.getMessage()));
+
+ }
+ }
+
+ @Test
public void test_deploy_with_negative_budget() {
var quota = Quota.unlimited().withBudget(BigDecimal.valueOf(-1));
var tester = new ValidationTester(13, false, new TestProperties().setHostedVespa(true).setQuota(quota).setZone(publicZone));
@@ -88,7 +101,7 @@ public class QuotaValidatorTest {
" <document type='music' mode='index'/>" +
" </documents>" +
" <nodes count='" + nodeCount + "'>" +
- " <resources vcpu=\"[0.5, 1]\" memory=\"[1Gb, 3Gb]\" disk=\"[1Gb, 9Gb]\"/>\n" +
+ " <resources vcpu=\"[0.5, 2]\" memory=\"[1Gb, 6Gb]\" disk=\"[1Gb, 18Gb]\"/>\n" +
" </nodes>" +
" </content>" +
"</services>";