summaryrefslogtreecommitdiffstats
path: root/config-model
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@gmail.com>2020-10-08 11:10:24 +0200
committerJon Bratseth <bratseth@gmail.com>2020-10-08 11:10:24 +0200
commit2bccbdbfd60eecd55f7362ff9060ee9a2eff9917 (patch)
tree45453f19e3da9a990e1fe0b943e331ab271637dd /config-model
parentf2e89d3361cae0e2e74bac89405a175d6ecf5e98 (diff)
Emit restart actions on node resource change
The actions should track what changes will actually cause restarts such that we can reason about the consequences of restarts based on them.
Diffstat (limited to 'config-model')
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/test/MockApplicationPackage.java2
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java2
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ChangeValidator.java1
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ClusterSizeReductionValidator.java5
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContentClusterRemovalValidator.java3
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContentTypeRemovalValidator.java3
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/GlobalDocumentChangeValidator.java3
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/NodeResourceChangeValidator.java75
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ResourcesReductionValidator.java5
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorageCluster.java17
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/NodeResourceChangeValidatorTest.java129
11 files changed, 218 insertions, 27 deletions
diff --git a/config-model/src/main/java/com/yahoo/config/model/test/MockApplicationPackage.java b/config-model/src/main/java/com/yahoo/config/model/test/MockApplicationPackage.java
index 10649df88e1..2594c64b951 100644
--- a/config-model/src/main/java/com/yahoo/config/model/test/MockApplicationPackage.java
+++ b/config-model/src/main/java/com/yahoo/config/model/test/MockApplicationPackage.java
@@ -140,7 +140,7 @@ public class MockApplicationPackage implements ApplicationPackage {
}
@Override
- public List<NamedReader> getFiles(Path dir,String fileSuffix,boolean recurse) {
+ public List<NamedReader> getFiles(Path dir, String fileSuffix, boolean recurse) {
return new ArrayList<>();
}
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 fa72a4965b0..9480690c395 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
@@ -17,6 +17,7 @@ import com.yahoo.vespa.model.application.validation.change.ContentTypeRemovalVal
import com.yahoo.vespa.model.application.validation.change.GlobalDocumentChangeValidator;
import com.yahoo.vespa.model.application.validation.change.IndexedSearchClusterChangeValidator;
import com.yahoo.vespa.model.application.validation.change.IndexingModeChangeValidator;
+import com.yahoo.vespa.model.application.validation.change.NodeResourceChangeValidator;
import com.yahoo.vespa.model.application.validation.change.ResourcesReductionValidator;
import com.yahoo.vespa.model.application.validation.change.StartupCommandChangeValidator;
import com.yahoo.vespa.model.application.validation.change.StreamingSearchClusterChangeValidator;
@@ -91,6 +92,7 @@ public class Validation {
new ClusterSizeReductionValidator(),
new ResourcesReductionValidator(),
new ContainerRestartValidator(),
+ new NodeResourceChangeValidator()
};
return 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/ChangeValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ChangeValidator.java
index bec7fd1518f..b720cc13f42 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ChangeValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ChangeValidator.java
@@ -12,7 +12,6 @@ import java.util.List;
* Interface for validating changes between a current active and next config model.
*
* @author geirst
- * @since 2014-11-18
*/
public interface ChangeValidator {
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ClusterSizeReductionValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ClusterSizeReductionValidator.java
index 162f6798462..f223ba69f61 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ClusterSizeReductionValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ClusterSizeReductionValidator.java
@@ -7,11 +7,8 @@ import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.vespa.model.VespaModel;
import com.yahoo.config.application.api.ValidationId;
import com.yahoo.config.application.api.ValidationOverrides;
-import com.yahoo.vespa.model.container.ContainerCluster;
-import com.yahoo.vespa.model.content.cluster.ContentCluster;
import java.time.Instant;
-import java.util.Collections;
import java.util.List;
/**
@@ -33,7 +30,7 @@ public class ClusterSizeReductionValidator implements ChangeValidator {
overrides,
now);
}
- return Collections.emptyList();
+ return List.of();
}
private void validate(Capacity current,
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContentClusterRemovalValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContentClusterRemovalValidator.java
index 866f647a351..4a43a30c167 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContentClusterRemovalValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContentClusterRemovalValidator.java
@@ -8,7 +8,6 @@ import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.vespa.model.content.cluster.ContentCluster;
import java.time.Instant;
-import java.util.Collections;
import java.util.List;
/**
@@ -30,7 +29,7 @@ public class ContentClusterRemovalValidator implements ChangeValidator {
now);
}
- return Collections.emptyList();
+ return List.of();
}
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContentTypeRemovalValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContentTypeRemovalValidator.java
index a691c8bb5c4..f3a018f2cdd 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContentTypeRemovalValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContentTypeRemovalValidator.java
@@ -9,7 +9,6 @@ import com.yahoo.vespa.model.VespaModel;
import com.yahoo.vespa.model.content.cluster.ContentCluster;
import java.time.Instant;
-import java.util.Collections;
import java.util.List;
/**
@@ -36,7 +35,7 @@ public class ContentTypeRemovalValidator implements ChangeValidator {
}
}
}
- return Collections.emptyList();
+ return List.of();
}
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/GlobalDocumentChangeValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/GlobalDocumentChangeValidator.java
index 198030d1f44..0b3f865c760 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/GlobalDocumentChangeValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/GlobalDocumentChangeValidator.java
@@ -8,7 +8,6 @@ import com.yahoo.documentmodel.NewDocumentType;
import com.yahoo.vespa.model.VespaModel;
import com.yahoo.vespa.model.content.cluster.ContentCluster;
-import java.util.Collections;
import java.time.Instant;
import java.util.List;
import java.util.Map;
@@ -30,7 +29,7 @@ public class GlobalDocumentChangeValidator implements ChangeValidator {
validateContentCluster(currentEntry.getValue(), nextCluster);
}
}
- return Collections.emptyList();
+ return List.of();
}
private void validateContentCluster(ContentCluster currentCluster, ContentCluster nextCluster) {
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/NodeResourceChangeValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/NodeResourceChangeValidator.java
new file mode 100644
index 00000000000..d6731c86607
--- /dev/null
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/NodeResourceChangeValidator.java
@@ -0,0 +1,75 @@
+// 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.change;
+
+import com.yahoo.config.application.api.ValidationOverrides;
+import com.yahoo.config.model.api.ConfigChangeAction;
+import com.yahoo.config.provision.ClusterSpec;
+import com.yahoo.config.provision.NodeResources;
+import com.yahoo.vespa.model.VespaModel;
+import com.yahoo.vespa.model.container.ApplicationContainerCluster;
+import com.yahoo.vespa.model.content.cluster.ContentCluster;
+
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * Emits restart change actions for clusters where the node resources are changed.
+ * Nodes will restart on their own on this condition but we want to emit restart actions to
+ * defer applying new config until restart.
+ *
+ * @author bratseth
+ */
+public class NodeResourceChangeValidator implements ChangeValidator {
+
+ @Override
+ public List<ConfigChangeAction> validate(VespaModel current, VespaModel next, ValidationOverrides overrides, Instant now) {
+ var restartActions = new ArrayList<ConfigChangeAction>();
+ for (ClusterSpec.Id clusterId : current.allClusters()) {
+ Optional<NodeResources> currentResources = resourcesOf(clusterId, current);
+ Optional<NodeResources> nextResources = resourcesOf(clusterId, next);
+ if (currentResources.isEmpty() || nextResources.isEmpty()) continue; // new or removed cluster
+ if ( ! currentResources.equals(nextResources))
+ restartActions.addAll(createRestartActionsFor(clusterId, current));
+ }
+ return restartActions;
+ }
+
+ private Optional<NodeResources> resourcesOf(ClusterSpec.Id clusterId, VespaModel model) {
+ return model.allocatedHosts().getHosts().stream().filter(host -> host.membership().isPresent())
+ .filter(host -> host.membership().get().cluster().id().equals(clusterId))
+ .findFirst()
+ .map(host -> host.realResources());
+ }
+
+ private List<ConfigChangeAction> createRestartActionsFor(ClusterSpec.Id clusterId, VespaModel model) {
+ ApplicationContainerCluster containerCluster = model.getContainerClusters().get(clusterId.value());
+ if (containerCluster != null)
+ return createRestartActionsFor(containerCluster);
+
+ ContentCluster contentCluster = model.getContentClusters().get(clusterId.value());
+ if (contentCluster != null)
+ return createRestartActionsFor(contentCluster);
+
+ return List.of();
+ }
+
+ private List<ConfigChangeAction> createRestartActionsFor(ApplicationContainerCluster cluster) {
+ return cluster.getContainers().stream()
+ .map(container -> new VespaRestartAction("Node resource change",
+ container.getServiceInfo(),
+ false))
+ .collect(Collectors.toList());
+ }
+
+ private List<ConfigChangeAction> createRestartActionsFor(ContentCluster cluster) {
+ return cluster.getSearch().getSearchNodes().stream()
+ .map(node -> new VespaRestartAction("Node resource change",
+ node.getServiceInfo(),
+ false))
+ .collect(Collectors.toList());
+ }
+
+}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ResourcesReductionValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ResourcesReductionValidator.java
index 24b7b0949f6..0fdfcd78323 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ResourcesReductionValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ResourcesReductionValidator.java
@@ -1,22 +1,17 @@
// Copyright 2020 Oath Inc. 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.collections.Pair;
import com.yahoo.config.application.api.ValidationId;
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.ClusterSpec;
-import com.yahoo.config.provision.NodeResources;
-import com.yahoo.vespa.model.HostResource;
import com.yahoo.vespa.model.VespaModel;
import java.time.Instant;
import java.util.List;
import java.util.Locale;
-import java.util.Map;
import java.util.Optional;
-import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorageCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorageCluster.java
index 981ce1bc004..bacb22b0b89 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorageCluster.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorageCluster.java
@@ -45,13 +45,12 @@ public class StorageCluster extends AbstractConfigProducer<StorageNode>
}
}
- private Integer bucketMoverMaxFillAboveAverage = null;
- private String clusterName;
- private FileStorProducer fileStorProducer;
- private IntegrityCheckerProducer integrityCheckerProducer;
- private StorServerProducer storServerProducer;
- private StorVisitorProducer storVisitorProducer;
- private PersistenceProducer persistenceProducer;
+ private final String clusterName;
+ private final FileStorProducer fileStorProducer;
+ private final IntegrityCheckerProducer integrityCheckerProducer;
+ private final StorServerProducer storServerProducer;
+ private final StorVisitorProducer storVisitorProducer;
+ private final PersistenceProducer persistenceProducer;
StorageCluster(AbstractConfigProducer parent,
String clusterName,
@@ -71,9 +70,6 @@ public class StorageCluster extends AbstractConfigProducer<StorageNode>
@Override
public void getConfig(StorBucketmoverConfig.Builder builder) {
- if (bucketMoverMaxFillAboveAverage != null) {
- builder.max_target_fill_rate_above_average(bucketMoverMaxFillAboveAverage);
- }
}
@Override
@@ -127,4 +123,5 @@ public class StorageCluster extends AbstractConfigProducer<StorageNode>
public void getConfig(StorFilestorConfig.Builder builder) {
fileStorProducer.getConfig(builder);
}
+
}
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/NodeResourceChangeValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/NodeResourceChangeValidatorTest.java
new file mode 100644
index 00000000000..fa4887cd8ee
--- /dev/null
+++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/NodeResourceChangeValidatorTest.java
@@ -0,0 +1,129 @@
+// 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.change;
+
+import com.yahoo.config.application.api.ValidationOverrides;
+import com.yahoo.config.model.api.ConfigChangeAction;
+import com.yahoo.config.model.api.HostProvisioner;
+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.ClusterMembership;
+import com.yahoo.config.provision.ClusterSpec;
+import com.yahoo.config.provision.HostSpec;
+import com.yahoo.config.provision.ProvisionLogger;
+import com.yahoo.vespa.model.VespaModel;
+import com.yahoo.vespa.model.test.utils.VespaModelCreatorWithMockPkg;
+import org.junit.Test;
+
+import java.time.Clock;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author bratseth
+ */
+public class NodeResourceChangeValidatorTest {
+
+ @Test
+ public void test_restart_action_count() {
+ assertEquals(0, validate(model(1, 1, 1, 1), model(1, 1, 1, 1)).size());
+ assertEquals(1, validate(model(1, 1, 1, 1), model(2, 1, 1, 1)).size());
+ assertEquals(2, validate(model(1, 1, 1, 1), model(1, 2, 1, 1)).size());
+ assertEquals(3, validate(model(1, 1, 1, 1), model(1, 1, 2, 1)).size());
+ assertEquals(4, validate(model(1, 1, 1, 1), model(1, 1, 1, 2)).size());
+ assertEquals(5, validate(model(1, 1, 1, 1), model(2, 1, 1, 2)).size());
+ assertEquals(6, validate(model(1, 1, 1, 1), model(1, 2, 1, 2)).size());
+ assertEquals(7, validate(model(1, 1, 1, 1), model(1, 1, 2, 2)).size());
+ assertEquals(8, validate(model(1, 1, 1, 1), model(2, 1, 2, 2)).size());
+ assertEquals(9, validate(model(1, 1, 1, 1), model(1, 2, 2, 2)).size());
+ assertEquals(10, validate(model(1, 1, 1, 1), model(2, 2, 2, 2)).size());
+ }
+
+ @Test
+ public void test_restart_action_details() {
+ ConfigChangeAction containerAction = validate(model(1, 1, 1, 1), model(2, 1, 1, 1)).get(0);
+ assertEquals(ConfigChangeAction.Type.RESTART, containerAction.getType());
+ assertEquals("service 'container' of type container on host0", containerAction.getServices().get(0).toString());
+ assertEquals(false, containerAction.ignoreForInternalRedeploy());
+
+ ConfigChangeAction contentAction = validate(model(1, 1, 1, 1), model(1, 1, 2, 1)).get(0);
+ assertEquals(ConfigChangeAction.Type.RESTART, contentAction.getType());
+ assertEquals("service 'searchnode' of type searchnode on host3", contentAction.getServices().get(0).toString());
+ assertEquals(false, contentAction.ignoreForInternalRedeploy());
+ }
+
+ private List<ConfigChangeAction> validate(VespaModel current, VespaModel next) {
+ return new NodeResourceChangeValidator().validate(current, next,
+ ValidationOverrides.empty,
+ Clock.systemUTC().instant());
+ }
+
+ private static VespaModel model(int vcpu1, int vcpu2, int vcpu3, int vcpu4) {
+ var properties = new TestProperties();
+ properties.setHostedVespa(true);
+ var deployState = new DeployState.Builder().properties(properties)
+ .modelHostProvisioner(new Provisioner());
+ return new VespaModelCreatorWithMockPkg(
+ null,
+ "<?xml version='1.0' encoding='utf-8' ?>\n" +
+ "<services version='1.0'>\n" +
+ " <container id='container1' version='1.0'>\n" +
+ " <nodes count='1'>\n" +
+ " <resources vcpu='" + vcpu1 + "' memory='10Gb' disk='100Gb'/>" +
+ " </nodes>\n" +
+ " </container>\n" +
+ " <container id='container2' version='1.0'>\n" +
+ " <nodes count='2'>\n" +
+ " <resources vcpu='" + vcpu2 + "' memory='10Gb' disk='100Gb'/>" +
+ " </nodes>\n" +
+ " </container>\n" +
+ " <content id='content1' version='1.0'>\n" +
+ " <nodes count='3'>\n" +
+ " <resources vcpu='" + vcpu3 + "' memory='10Gb' disk='100Gb'/>" +
+ " </nodes>\n" +
+ " <documents>\n" +
+ " <document mode='index' type='test'/>\n" +
+ " </documents>\n" +
+ " <redundancy>2</redundancy>\n" +
+ " </content>\n" +
+ " <content id='content2' version='1.0'>\n" +
+ " <nodes count='4'>\n" +
+ " <resources vcpu='" + vcpu4 + "' memory='10Gb' disk='100Gb'/>" +
+ " </nodes>\n" +
+ " <documents>\n" +
+ " <document mode='streaming' type='test'/>\n" +
+ " </documents>\n" +
+ " <redundancy>2</redundancy>\n" +
+ " </content>\n" +
+ "</services>",
+ List.of("schema test { document test {} }"))
+ .create(deployState);
+ }
+
+ private static class Provisioner implements HostProvisioner {
+
+ private int hostsCreated = 0;
+
+ @Override
+ public HostSpec allocateHost(String alias) {
+ return new HostSpec(alias, List.of(), Optional.empty());
+ }
+
+ @Override
+ public List<HostSpec> prepare(ClusterSpec cluster, Capacity capacity, ProvisionLogger logger) {
+ List<HostSpec> hosts = new ArrayList<>();
+ var resources = capacity.minResources().nodeResources();
+ for (int i = 0; i < capacity.minResources().nodes(); i++)
+ hosts.add(new HostSpec("host" + (hostsCreated++),
+ resources, resources, resources,
+ ClusterMembership.from(cluster, i),
+ Optional.empty(), Optional.empty(), Optional.empty()));
+ return hosts;
+ }
+
+ }
+
+}