diff options
author | Jon Bratseth <bratseth@gmail.com> | 2023-05-22 11:07:30 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-22 11:07:30 +0200 |
commit | 6429ecefcc607e78f7b9242744dd8d1e690c5537 (patch) | |
tree | 41de50304edc304882ff7c59ed2257884bd8d1e1 /config-model | |
parent | 1b2ce97684449b5cf8f02d099d3034984229bffe (diff) | |
parent | c7a07adf43c13165e49e2aa2ef509ecb2526a48c (diff) |
Merge branch 'master' into bratseth/memory-overhead
Diffstat (limited to 'config-model')
4 files changed, 54 insertions, 25 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 4b993f8e244..ae9d696a9a3 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 @@ -160,7 +160,7 @@ public class InMemoryProvisioner implements HostProvisioner { public List<HostSpec> prepare(ClusterSpec cluster, Capacity requested, ProvisionLogger logger) { provisioned.add(cluster.id(), requested); clusters.add(cluster); - if (environment == Environment.dev) { + if (environment == Environment.dev && ! requested.isRequired()) { requested = requested.withLimits(requested.minResources().withNodes(1), requested.maxResources().withNodes(1)); } 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 4ea74147aaf..475a4174f9a 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 @@ -53,8 +53,8 @@ public class QuotaValidator extends Validator { } throwIfBudgetNegative(actualSpend, budget, systemName); - throwIfBudgetExceeded(actualSpend, budget, systemName); - throwIfBudgetExceeded(maxSpend, budget, systemName); + throwIfBudgetExceeded(actualSpend, budget, systemName, true); + throwIfBudgetExceeded(maxSpend, budget, systemName, false); } private Set<ClusterSpec.Id> adminClusterIds(VespaModel model) { @@ -86,18 +86,22 @@ public class QuotaValidator extends Validator { private static void throwIfBudgetNegative(double spend, BigDecimal budget, SystemName systemName) { if (budget.doubleValue() < 0) { - throw new IllegalArgumentException(quotaMessage("Please free up some capacity.", systemName, spend, budget)); + throw new IllegalArgumentException(quotaMessage("Please free up some capacity.", systemName, spend, budget, true)); } } - private static void throwIfBudgetExceeded(double spend, BigDecimal budget, SystemName systemName) { + private static void throwIfBudgetExceeded(double spend, BigDecimal budget, SystemName systemName, boolean actual) { if (budget.doubleValue() < spend) { - throw new IllegalArgumentException(quotaMessage("Contact support to upgrade your plan.", systemName, spend, budget)); + throw new IllegalArgumentException(quotaMessage("Contact support to upgrade your plan.", systemName, spend, budget, actual)); } } - private static String quotaMessage(String message, SystemName system, double spend, BigDecimal budget) { - String quotaDescription = String.format(Locale.ENGLISH, "The max resources specified cost $%.2f but your quota is $%.2f", spend, budget); + private static String quotaMessage(String message, SystemName system, double spend, BigDecimal budget, boolean actual) { + String quotaDescription = String.format(Locale.ENGLISH, + "The %s cost $%.2f but your quota is $%.2f", + actual ? "resources used" : "max resources specified", + spend, + budget); return (system == SystemName.Public ? "" : system.value() + ": ") + quotaDescription + ": " + message; } 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 1a7b3d62cb7..a1a3b40a858 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 @@ -21,19 +21,20 @@ public class QuotaValidatorTest { private final Zone publicZone = new Zone(SystemName.Public, Environment.prod, RegionName.from("foo")); private final Zone publicCdZone = new Zone(SystemName.PublicCd, Environment.prod, RegionName.from("foo")); + private final Zone devZone = new Zone(SystemName.Public, Environment.dev, RegionName.from("foo")); private final Quota quota = Quota.unlimited().withClusterSize(10).withBudget(BigDecimal.valueOf(1.25)); @Test void test_deploy_under_quota() { var tester = new ValidationTester(8, false, new TestProperties().setHostedVespa(true).setQuota(quota).setZone(publicZone)); - tester.deploy(null, getServices("testCluster", 4), Environment.prod, null); + tester.deploy(null, getServices(4), Environment.prod, null); } @Test void test_deploy_above_quota_clustersize() { var tester = new ValidationTester(14, false, new TestProperties().setHostedVespa(true).setQuota(quota).setZone(publicZone)); try { - tester.deploy(null, getServices("testCluster", 11), Environment.prod, null); + tester.deploy(null, getServices(11), Environment.prod, null); fail(); } catch (RuntimeException e) { assertEquals("Clusters testCluster exceeded max cluster size of 10", e.getMessage()); @@ -44,10 +45,10 @@ public class QuotaValidatorTest { void test_deploy_above_quota_budget() { var tester = new ValidationTester(13, false, new TestProperties().setHostedVespa(true).setQuota(quota).setZone(publicZone)); try { - tester.deploy(null, getServices("testCluster", 10), Environment.prod, null); + tester.deploy(null, getServices(10), Environment.prod, null); fail(); } catch (RuntimeException e) { - assertEquals("The max resources specified cost $1.63 but your quota is $1.25: Contact support to upgrade your plan.", e.getMessage()); + assertEquals("The resources used cost $1.63 but your quota is $1.25: Contact support to upgrade your plan.", e.getMessage()); } } @@ -55,10 +56,10 @@ public class QuotaValidatorTest { void test_deploy_above_quota_budget_in_publiccd() { 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); + tester.deploy(null, getServices(10), Environment.prod, null); fail(); } catch (RuntimeException e) { - assertEquals("publiccd: The max resources specified cost $1.63 but your quota is $1.00: Contact support to upgrade your plan.", e.getMessage()); + assertEquals("publiccd: The resources used cost $1.63 but your quota is $1.00: Contact support to upgrade your plan.", e.getMessage()); } } @@ -66,11 +67,33 @@ public class QuotaValidatorTest { 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); + tester.deploy(null, getServices(10), Environment.prod, null); fail(); } catch (RuntimeException e) { - assertEquals("publiccd: The max resources specified cost $1.63 but your quota is $1.25: Contact support to upgrade your plan.", e.getMessage()); + assertEquals("publiccd: The resources used cost $1.63 but your quota is $1.25: Contact support to upgrade your plan.", e.getMessage()); + } + } + + + @Test + void test_deploy_above_quota_budget_in_dev() { + var quota = Quota.unlimited().withBudget(BigDecimal.valueOf(0.01)); + var tester = new ValidationTester(5, false, new TestProperties().setHostedVespa(true).setQuota(quota).setZone(devZone)); + // There is downscaling to 1 node per cluster in dev + try { + tester.deploy(null, getServices(2, false), Environment.dev, null); + fail(); + } catch (RuntimeException e) { + assertEquals("The resources used cost $0.16 but your quota is $0.01: Contact support to upgrade your plan.", e.getMessage()); + } + + // Override so that we will get 2 nodes in content cluster + try { + tester.deploy(null, getServices(2, true), Environment.dev, null); + fail(); + } catch (RuntimeException e) { + assertEquals("The resources used cost $0.33 but your quota is $0.01: Contact support to upgrade your plan.", e.getMessage()); } } @@ -79,25 +102,26 @@ public class QuotaValidatorTest { var quota = Quota.unlimited().withBudget(BigDecimal.valueOf(-1)); var tester = new ValidationTester(13, false, new TestProperties().setHostedVespa(true).setQuota(quota).setZone(publicZone)); try { - tester.deploy(null, getServices("testCluster", 10), Environment.prod, null); + tester.deploy(null, getServices(10), Environment.prod, null); fail(); } catch (RuntimeException e) { - assertEquals("The max resources specified cost $-.-- but your quota is $--.--: Please free up some capacity.", + assertEquals("The resources used cost $-.-- but your quota is $--.--: Please free up some capacity.", ValidationTester.censorNumbers(e.getMessage())); } } - private static String getServices(String contentClusterId, int nodeCount) { - return "<services version='1.0'>" + - " <content id='" + contentClusterId + "' version='1.0'>" + + private static String getServices(int nodeCount) { + return getServices(nodeCount, false); + } + + private static String getServices(int nodeCount, boolean devOverride) { + return "<services version='1.0' xmlns:deploy='vespa' xmlns:preprocess='properties'>" + + " <content id='" + "testCluster" + "' version='1.0'>" + " <redundancy>1</redundancy>" + - " <engine>" + - " <proton/>" + - " </engine>" + " <documents>" + " <document type='music' mode='index'/>" + " </documents>" + - " <nodes count='" + nodeCount + "'>" + + " <nodes count='" + nodeCount + "' " + (devOverride ? "required='true'" : "") + " >\n" + " <resources vcpu=\"[0.5, 2]\" memory=\"[1Gb, 6Gb]\" disk=\"[1Gb, 18Gb]\"/>\n" + " </nodes>" + " </content>" + diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/ValidationTester.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/ValidationTester.java index 78d3838d39d..1517f7971ed 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/ValidationTester.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/ValidationTester.java @@ -57,6 +57,7 @@ public class ValidationTester { public ValidationTester(InMemoryProvisioner hostProvisioner, TestProperties testProperties) { this.hostProvisioner = hostProvisioner; this.properties = testProperties; + hostProvisioner.setEnvironment(testProperties.zone().environment()); } /** |