diff options
author | Jon Bratseth <bratseth@gmail.com> | 2021-06-07 14:59:57 +0200 |
---|---|---|
committer | Jon Bratseth <bratseth@gmail.com> | 2021-06-07 14:59:57 +0200 |
commit | bcdd3565654fb7fe7bdcd17f6a5a5904088c8e82 (patch) | |
tree | 2c63af6f88a48c7086dcfcbaa3be0837a3609b4d /config-model/src | |
parent | facc295e58c32bbcc438c7d40349c6cab1b80861 (diff) |
Validate redundancy=1 on first deployment
Diffstat (limited to 'config-model/src')
4 files changed, 114 insertions, 1 deletions
diff --git a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java index 2927df57bc1..e08c57a6fb4 100644 --- a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java +++ b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java @@ -42,6 +42,7 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea private double defaultTermwiseLimit = 1.0; private String jvmGCOptions = null; private String sequencerType = "LATENCY"; + private boolean firstTimeDeployment = false; private String responseSequencerType = "ADAPTIVE"; private int responseNumThreads = 2; private Optional<EndpointCertificateSecrets> endpointCertificateSecrets = Optional.empty(); @@ -77,7 +78,7 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea @Override public String jvmGCOptions(Optional<ClusterSpec.Type> clusterType) { return jvmGCOptions; } @Override public String feedSequencerType() { return sequencerType; } @Override public boolean isBootstrap() { return false; } - @Override public boolean isFirstTimeDeployment() { return false; } + @Override public boolean isFirstTimeDeployment() { return firstTimeDeployment; } @Override public boolean useDedicatedNodeForLogserver() { return useDedicatedNodeForLogserver; } @Override public Optional<EndpointCertificateSecrets> endpointCertificateSecrets() { return endpointCertificateSecrets; } @Override public double defaultTermwiseLimit() { return defaultTermwiseLimit; } @@ -133,6 +134,10 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea responseSequencerType = type; return this; } + public TestProperties setFirstTimeDeployment(boolean firstTimeDeployment) { + this.firstTimeDeployment = firstTimeDeployment; + return this; + } public TestProperties setResponseNumThreads(int numThreads) { responseNumThreads = numThreads; return this; diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java index eccb54780d6..66f497f5040 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java @@ -25,6 +25,7 @@ import com.yahoo.vespa.model.application.validation.change.ResourcesReductionVal import com.yahoo.vespa.model.application.validation.change.StartupCommandChangeValidator; import com.yahoo.vespa.model.application.validation.change.StreamingSearchClusterChangeValidator; import com.yahoo.vespa.model.application.validation.first.AccessControlOnFirstDeploymentValidator; +import com.yahoo.vespa.model.application.validation.first.RedundancyOnFirstDeploymentValidator; import java.time.Instant; import java.util.Arrays; @@ -124,6 +125,7 @@ public class Validation { private static void validateFirstTimeDeployment(VespaModel model, DeployState deployState) { new AccessControlOnFirstDeploymentValidator().validate(model, deployState); + new RedundancyOnFirstDeploymentValidator().validate(model, deployState); } private static void deferConfigChangesForClustersToBeRestarted(List<ConfigChangeAction> actions, VespaModel model) { diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/first/RedundancyOnFirstDeploymentValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/first/RedundancyOnFirstDeploymentValidator.java new file mode 100644 index 00000000000..acffb0cf292 --- /dev/null +++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/first/RedundancyOnFirstDeploymentValidator.java @@ -0,0 +1,42 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.model.application.validation.first; + +import com.yahoo.config.application.api.ValidationId; +import com.yahoo.config.model.ConfigModelContext.ApplicationType; +import com.yahoo.config.model.deploy.DeployState; +import com.yahoo.vespa.model.VespaModel; +import com.yahoo.vespa.model.application.validation.Validator; +import com.yahoo.vespa.model.container.ApplicationContainerCluster; +import com.yahoo.vespa.model.container.Container; +import com.yahoo.vespa.model.container.ContainerCluster; +import com.yahoo.vespa.model.content.cluster.ContentCluster; + +import java.util.ArrayList; +import java.util.List; + +import static com.yahoo.collections.CollectionUtil.mkString; +import static com.yahoo.config.provision.InstanceName.defaultName; +import static com.yahoo.vespa.model.container.http.AccessControl.hasHandlerThatNeedsProtection; + +/** + * Validates that applications in prod zones do not have redundancy 1 (without a validation override). + * + * @author bratseth + */ +public class RedundancyOnFirstDeploymentValidator extends Validator { + + @Override + public void validate(VespaModel model, DeployState deployState) { + if ( ! deployState.zone().environment().isProduction()) return; + + for (ContentCluster cluster : model.getContentClusters().values()) { + if (cluster.redundancy().finalRedundancy() == 1) + deployState.validationOverrides().invalid(ValidationId.redundancyOne, + cluster + " has redundancy 1, which will cause it to lose data " + + "if a node fails. This requires an override on first deployment " + + "in a production zone", + deployState.now()); + } + } + +} diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/first/RedundancyOnFirstDeploymentValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/first/RedundancyOnFirstDeploymentValidatorTest.java new file mode 100644 index 00000000000..d59b2f7227c --- /dev/null +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/first/RedundancyOnFirstDeploymentValidatorTest.java @@ -0,0 +1,64 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.model.application.validation.first; + +import com.yahoo.config.application.api.ValidationId; +import com.yahoo.config.application.api.ValidationOverrides; +import com.yahoo.config.model.deploy.TestProperties; +import com.yahoo.config.provision.Environment; +import com.yahoo.vespa.model.application.validation.ValidationTester; +import com.yahoo.yolean.Exceptions; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * @author bratseth + */ +public class RedundancyOnFirstDeploymentValidatorTest { + + private final ValidationTester tester = new ValidationTester(7, false, + new TestProperties().setFirstTimeDeployment(true) + .setHostedVespa(true)); + + @Test + public void testRedundancyOnFirstDeploymentValidation() { + try { + tester.deploy(null, getServices(1), Environment.prod, null); + fail("Expected exception due to redundancy 1"); + } + catch (IllegalArgumentException expected) { + assertEquals("redundancy-one: " + + "content cluster 'contentClusterId' has redundancy 1, which will cause it to lose data if a node fails. " + + "This requires an override on first deployment in a production zone. " + + ValidationOverrides.toAllowMessage(ValidationId.redundancyOne), + Exceptions.toMessageString(expected)); + } + } + + @Test + public void testOverridingRedundancyOnFirstDeploymentValidation() { + tester.deploy(null, getServices(1), Environment.prod, redundancyOneOverride); // Allowed due to override + } + + private static String getServices(int redundancy) { + return "<services version='1.0'>" + + " <content id='contentClusterId' version='1.0'>" + + " <redundancy>" + redundancy + "</redundancy>" + + " <engine>" + + " <proton/>" + + " </engine>" + + " <documents>" + + " <document type='music' mode='index'/>" + + " </documents>" + + " <nodes count='3'/>" + + " </content>" + + "</services>"; + } + + private static final String redundancyOneOverride = + "<validation-overrides>\n" + + " <allow until='2000-01-03'>redundancy-one</allow>\n" + + "</validation-overrides>\n"; + +} |