diff options
8 files changed, 38 insertions, 17 deletions
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java index 5158f3ec488..d2892917a2e 100644 --- a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java @@ -96,6 +96,7 @@ public interface ModelContext { @ModelFeatureFlag(owners = {"tokle", "bjorncs"}) default boolean enableCustomAclMapping() { return false; } @ModelFeatureFlag(owners = {"geirst", "vekterli"}) default int numDistributorStripes() { return 0; } @ModelFeatureFlag(owners = {"arnej"}) default boolean requireConnectivityCheck() { return false; } + @ModelFeatureFlag(owners = {"hmusum"}) default boolean throwIfResourceLimitsSpecified() { return false; } } /** Warning: As elsewhere in this package, do not make backwards incompatible changes that will break old config models! */ diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/ClusterResourceLimits.java b/config-model/src/main/java/com/yahoo/vespa/model/content/ClusterResourceLimits.java index 66640d4b2dc..8db656a5f2c 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/content/ClusterResourceLimits.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/content/ClusterResourceLimits.java @@ -36,12 +36,14 @@ public class ClusterResourceLimits { private final boolean enableFeedBlockInDistributor; private final boolean hostedVespa; + private final boolean throwIfSpecified; private ResourceLimits.Builder ctrlBuilder = new ResourceLimits.Builder(); private ResourceLimits.Builder nodeBuilder = new ResourceLimits.Builder(); - public Builder(boolean enableFeedBlockInDistributor, boolean hostedVespa) { + public Builder(boolean enableFeedBlockInDistributor, boolean hostedVespa, boolean throwIfSpecified) { this.enableFeedBlockInDistributor = enableFeedBlockInDistributor; this.hostedVespa = hostedVespa; + this.throwIfSpecified = throwIfSpecified; } public ClusterResourceLimits build(ModelElement clusterElem) { @@ -55,7 +57,7 @@ public class ClusterResourceLimits { private ResourceLimits.Builder createBuilder(ModelElement element) { return element == null ? new ResourceLimits.Builder() - : DomResourceLimitsBuilder.createBuilder(element, hostedVespa); + : DomResourceLimitsBuilder.createBuilder(element, hostedVespa, throwIfSpecified); } public void setClusterControllerBuilder(ResourceLimits.Builder builder) { diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java index 90cca1494b2..97093203758 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java @@ -121,7 +121,9 @@ public class ContentCluster extends AbstractConfigProducer<AbstractConfigProduce globallyDistributedDocuments, routingSelection, deployState.zone(), deployState.isHosted()); boolean enableFeedBlockInDistributor = deployState.getProperties().featureFlags().enableFeedBlockInDistributor(); - var resourceLimits = new ClusterResourceLimits.Builder(enableFeedBlockInDistributor, stateIsHosted(deployState)) + var resourceLimits = new ClusterResourceLimits.Builder(enableFeedBlockInDistributor, + stateIsHosted(deployState), + deployState.featureFlags().throwIfResourceLimitsSpecified()) .build(contentElement); c.clusterControllerConfig = new ClusterControllerConfig.Builder(getClusterId(contentElement), contentElement, diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/DomResourceLimitsBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/DomResourceLimitsBuilder.java index f65c67de07d..bab991efe51 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/DomResourceLimitsBuilder.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/DomResourceLimitsBuilder.java @@ -11,12 +11,13 @@ import com.yahoo.vespa.model.content.ResourceLimits; */ public class DomResourceLimitsBuilder { - public static ResourceLimits.Builder createBuilder(ModelElement contentXml, boolean hostedVespa) { + public static ResourceLimits.Builder createBuilder(ModelElement contentXml, boolean hostedVespa, boolean throwIfSpecified) { ResourceLimits.Builder builder = new ResourceLimits.Builder(); ModelElement resourceLimits = contentXml.child("resource-limits"); if (resourceLimits == null) { return builder; } - if (hostedVespa) throw new IllegalArgumentException("Element '" + resourceLimits + "' is not allowed to be set"); + if (hostedVespa && throwIfSpecified) + throw new IllegalArgumentException("Element '" + resourceLimits + "' is not allowed to be set"); if (resourceLimits.child("disk") != null) { builder.setDiskLimit(resourceLimits.childAsDouble("disk")); diff --git a/config-model/src/test/java/com/yahoo/vespa/model/content/ClusterResourceLimitsTest.java b/config-model/src/test/java/com/yahoo/vespa/model/content/ClusterResourceLimitsTest.java index 8e7b1a27d36..ad1f5331a91 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/content/ClusterResourceLimitsTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/content/ClusterResourceLimitsTest.java @@ -6,6 +6,7 @@ import com.yahoo.vespa.model.builder.xml.dom.ModelElement; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.w3c.dom.Document; import java.util.Optional; @@ -48,7 +49,7 @@ public class ClusterResourceLimitsTest { return this; } public ClusterResourceLimits build() { - var builder = new ClusterResourceLimits.Builder(enableFeedBlockInDistributor, false); + var builder = new ClusterResourceLimits.Builder(enableFeedBlockInDistributor, false, false); builder.setClusterControllerBuilder(ctrlBuilder); builder.setContentNodeBuilder(nodeBuilder); return builder.build(); @@ -126,18 +127,22 @@ public class ClusterResourceLimitsTest { public void exception_is_thrown_when_resource_limits_are_specified() { final boolean hosted = true; + Document clusterXml = XML.getDocument("<cluster id=\"test\">" + + " <tuning>\n" + + " <resource-limits>\n" + + " <memory>0.92</memory>\n" + + " </resource-limits>\n" + + " </tuning>\n" + + "</cluster>"); + expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage(containsString("Element 'resource-limits' is not allowed to be set")); + ClusterResourceLimits.Builder builder = new ClusterResourceLimits.Builder(true, hosted, true); + builder.build(new ModelElement(clusterXml.getDocumentElement())); - ClusterResourceLimits.Builder builder = new ClusterResourceLimits.Builder(true, hosted); - builder.build(new ModelElement(XML.getDocument("<cluster id=\"test\">" + - " <tuning>\n" + - " <resource-limits>\n" + - " <memory>0.92</memory>\n" + - " </resource-limits>\n" + - " </tuning>\n" + - "</cluster>") - .getDocumentElement())); + expectedException = ExpectedException.none(); + ClusterResourceLimits.Builder builder2 = new ClusterResourceLimits.Builder(true, hosted, false); + builder2.build(new ModelElement(clusterXml.getDocumentElement())); } private void assertLimits(Double expCtrlDisk, Double expCtrlMemory, Double expNodeDisk, Double expNodeMemory, Fixture f) { diff --git a/config-model/src/test/java/com/yahoo/vespa/model/content/FleetControllerClusterTest.java b/config-model/src/test/java/com/yahoo/vespa/model/content/FleetControllerClusterTest.java index c713414d043..2eecfa9440e 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/content/FleetControllerClusterTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/content/FleetControllerClusterTest.java @@ -23,7 +23,7 @@ public class FleetControllerClusterTest { var clusterElement = new ModelElement(doc.getDocumentElement()); return new ClusterControllerConfig.Builder("storage", clusterElement, - new ClusterResourceLimits.Builder(enableFeedBlockInDistributor, false) + new ClusterResourceLimits.Builder(enableFeedBlockInDistributor, false, false) .build(clusterElement).getClusterControllerLimits()) .build(root.getDeployState(), root, clusterElement.getXml()); } @@ -112,7 +112,7 @@ public class FleetControllerClusterTest { assertLimits(0.8, 0.7, getConfigForResourceLimitsTuning(null, 0.7)); } - private static double DELTA = 0.00001; + private static final double DELTA = 0.00001; private void assertLimits(double expDisk, double expMemory, FleetcontrollerConfig config) { var limits = config.cluster_feed_block_limit(); diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java index 8805c339482..5cd52e36339 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java @@ -180,6 +180,7 @@ public class ModelContextImpl implements ModelContext { private final boolean requireConnectivityCheck; private final int maxConcurrentMergesPerContentNode; private final int maxMergeQueueSize; + private final boolean throwIfResourceLimitsSpecified; public FeatureFlags(FlagSource source, ApplicationId appId) { this.dedicatedClusterControllerFlavor = parseDedicatedClusterControllerFlavor(flagValue(source, appId, Flags.DEDICATED_CLUSTER_CONTROLLER_FLAVOR)); @@ -205,6 +206,7 @@ public class ModelContextImpl implements ModelContext { this.requireConnectivityCheck = flagValue(source, appId, Flags.REQUIRE_CONNECTIVITY_CHECK); this.maxConcurrentMergesPerContentNode = flagValue(source, appId, Flags.MAX_CONCURRENT_MERGES_PER_NODE); this.maxMergeQueueSize = flagValue(source, appId, Flags.MAX_MERGE_QUEUE_SIZE); + this.throwIfResourceLimitsSpecified = flagValue(source, appId, Flags.THROW_EXCEPTION_IF_RESOURCE_LIMITS_SPECIFIED); } @Override public Optional<NodeResources> dedicatedClusterControllerFlavor() { return Optional.ofNullable(dedicatedClusterControllerFlavor); } @@ -232,6 +234,7 @@ public class ModelContextImpl implements ModelContext { @Override public boolean requireConnectivityCheck() { return requireConnectivityCheck; } @Override public int maxConcurrentMergesPerNode() { return maxConcurrentMergesPerContentNode; } @Override public int maxMergeQueueSize() { return maxMergeQueueSize; } + @Override public boolean throwIfResourceLimitsSpecified() { return throwIfResourceLimitsSpecified; } private static <V> V flagValue(FlagSource source, ApplicationId appId, UnboundFlag<? extends V, ?, ?> flag) { return flag.bindTo(source) diff --git a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java index cfa14979d3f..9904ef77513 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java @@ -266,6 +266,13 @@ public class Flags { "Takes effect on next restart", ZONE_ID, APPLICATION_ID); + public static final UnboundBooleanFlag THROW_EXCEPTION_IF_RESOURCE_LIMITS_SPECIFIED = defineFeatureFlag( + "throw-exception-if-resource-limits-specified", false, + List.of("mpolden"), "2021-06-07", "2021-07-07", + "Whether to throw an exception in hosted Vespa if the application specifies resource limits in services.xml", + "Takes effect on next deployment through controller", + APPLICATION_ID); + /** WARNING: public for testing: All flags should be defined in {@link Flags}. */ public static UnboundBooleanFlag defineFeatureFlag(String flagId, boolean defaultValue, List<String> owners, String createdAt, String expiresAt, String description, |