summaryrefslogtreecommitdiffstats
path: root/config-model
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2022-10-27 14:36:16 +0200
committerMartin Polden <mpolden@mpolden.no>2022-10-27 20:08:33 +0200
commitab9903801f0eaf409a7123df1eb386b2f2b02068 (patch)
treead23317fec3704a3dde0386675ecac7d2247ecdc /config-model
parent15719d50be8f37fdf78f4e6855af26c7d47d0ad8 (diff)
Reject cloud account change
Diffstat (limited to 'config-model')
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java4
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/CloudAccountChangeValidator.java40
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/CloudAccountChangeValidatorTest.java90
3 files changed, 133 insertions, 1 deletions
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 dab1eeccc96..68b5adcc84f 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
@@ -11,6 +11,7 @@ import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.vespa.model.VespaModel;
import com.yahoo.vespa.model.application.validation.change.ChangeValidator;
+import com.yahoo.vespa.model.application.validation.change.CloudAccountChangeValidator;
import com.yahoo.vespa.model.application.validation.change.ClusterSizeReductionValidator;
import com.yahoo.vespa.model.application.validation.change.ConfigValueChangeValidator;
import com.yahoo.vespa.model.application.validation.change.ContainerRestartValidator;
@@ -118,7 +119,8 @@ public class Validation {
new ResourcesReductionValidator(),
new ContainerRestartValidator(),
new NodeResourceChangeValidator(),
- new RedundancyIncreaseValidator()
+ new RedundancyIncreaseValidator(),
+ new CloudAccountChangeValidator()
};
List<ConfigChangeAction> actions = Arrays.stream(validators)
.flatMap(v -> v.validate(currentModel, nextModel, overrides, now).stream())
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/CloudAccountChangeValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/CloudAccountChangeValidator.java
new file mode 100644
index 00000000000..ba8a8819c5b
--- /dev/null
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/CloudAccountChangeValidator.java
@@ -0,0 +1,40 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.model.application.validation.change;
+
+import com.yahoo.config.application.api.ValidationOverrides;
+import com.yahoo.config.model.api.ConfigChangeAction;
+import com.yahoo.config.provision.Capacity;
+import com.yahoo.config.provision.CloudAccount;
+import com.yahoo.config.provision.ClusterSpec;
+import com.yahoo.vespa.model.VespaModel;
+
+import java.time.Instant;
+import java.util.List;
+
+/**
+ * @author mpolden
+ */
+public class CloudAccountChangeValidator implements ChangeValidator {
+
+ @Override
+ public List<ConfigChangeAction> validate(VespaModel current, VespaModel next, ValidationOverrides overrides, Instant now) {
+ for (var clusterId : current.allClusters()) {
+ CloudAccount currentAccount = cloudAccountOf(current, clusterId);
+ CloudAccount nextAccount = cloudAccountOf(next, clusterId);
+ if (currentAccount == null || nextAccount == null) continue;
+
+ if (!nextAccount.equals(currentAccount)) {
+ throw new IllegalArgumentException("Cannot change cloud account from " + currentAccount +
+ " to " + nextAccount + ". The existing deployment must be removed " +
+ "before changing accounts");
+ }
+ }
+ return List.of();
+ }
+
+ private static CloudAccount cloudAccountOf(VespaModel model, ClusterSpec.Id cluster) {
+ Capacity capacity = model.provisioned().all().get(cluster);
+ return capacity == null ? null : capacity.cloudAccount().orElse(CloudAccount.empty);
+ }
+
+}
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/CloudAccountChangeValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/CloudAccountChangeValidatorTest.java
new file mode 100644
index 00000000000..aec6cb468d1
--- /dev/null
+++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/CloudAccountChangeValidatorTest.java
@@ -0,0 +1,90 @@
+package com.yahoo.vespa.model.application.validation.change;
+
+import com.yahoo.config.application.api.ValidationOverrides;
+import com.yahoo.config.model.api.Provisioned;
+import com.yahoo.config.model.deploy.DeployState;
+import com.yahoo.config.model.deploy.TestProperties;
+import com.yahoo.config.provision.Capacity;
+import com.yahoo.config.provision.CloudAccount;
+import com.yahoo.config.provision.ClusterResources;
+import com.yahoo.config.provision.ClusterSpec;
+import com.yahoo.config.provision.NodeResources;
+import com.yahoo.vespa.model.VespaModel;
+import com.yahoo.vespa.model.test.utils.VespaModelCreatorWithMockPkg;
+import org.junit.jupiter.api.Test;
+
+import java.time.Instant;
+import java.util.List;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
+/**
+ * @author mpolden
+ */
+class CloudAccountChangeValidatorTest {
+
+ @Test
+ public void validate() {
+ VespaModel model0 = model(provisioned(capacity(CloudAccount.empty)));
+ VespaModel model1 = model(provisioned(capacity(new CloudAccount("000000000000"))));
+
+ CloudAccountChangeValidator validator = new CloudAccountChangeValidator();
+ try {
+ validator.validate(model0, model1, ValidationOverrides.empty, Instant.now());
+ fail("Expected exception");
+ } catch (IllegalArgumentException e) {
+ assertEquals(e.getMessage(), "Cannot change cloud account from unspecified account to " +
+ "account '000000000000'. The existing deployment must be removed before " +
+ "changing accounts");
+ }
+ assertEquals(List.of(), validator.validate(model0, model0, ValidationOverrides.empty, Instant.now()));
+ assertEquals(List.of(), validator.validate(model1, model1, ValidationOverrides.empty, Instant.now()));
+ }
+
+ private static Provisioned provisioned(Capacity... capacity) {
+ Provisioned provisioned = new Provisioned();
+ for (int i = 0; i < capacity.length; i++) {
+ provisioned.add(ClusterSpec.Id.from("c" + i), capacity[i]);
+ }
+ return provisioned;
+ }
+
+ private static Capacity capacity(CloudAccount cloudAccount) {
+ NodeResources nodeResources = new NodeResources(4, 8, 100, 10);
+ return Capacity.from(new ClusterResources(2, 1, nodeResources),
+ new ClusterResources(2, 1, nodeResources),
+ false,
+ false,
+ Optional.of(cloudAccount).filter(account -> !account.isEmpty()));
+ }
+
+ private static VespaModel model(Provisioned provisioned) {
+ var properties = new TestProperties();
+ properties.setHostedVespa(true);
+ var deployState = new DeployState.Builder().properties(properties)
+ .provisioned(provisioned);
+ String services = """
+ <?xml version='1.0' encoding='utf-8' ?>
+ <services version='1.0'>
+ <container id='c0' version='1.0'>
+ <nodes count='2'>
+ <resources vcpu='4' memory='8Gb' disk='100Gb'/>
+ </nodes>
+ </container>
+ <content id='c1' version='1.0'>
+ <nodes count='2'>
+ <resources vcpu='4' memory='8Gb' disk='100Gb'/>
+ </nodes>
+ <documents>
+ <document type='test' mode='index'/>
+ </documents>
+ <redundancy>2</redundancy>
+ </content>
+ </services>""";
+ return new VespaModelCreatorWithMockPkg(null, services, List.of("schema test { document test {} }"))
+ .create(deployState);
+ }
+
+}