summaryrefslogtreecommitdiffstats
path: root/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java
diff options
context:
space:
mode:
Diffstat (limited to 'node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java')
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java221
1 files changed, 13 insertions, 208 deletions
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java
index 2a4dbe32ab5..e21c57b3ef5 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java
@@ -1,22 +1,18 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.provision.autoscale;
-import com.yahoo.collections.Pair;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.Capacity;
import com.yahoo.config.provision.ClusterResources;
import com.yahoo.config.provision.ClusterSpec;
-import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.Flavor;
import com.yahoo.config.provision.HostSpec;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
-import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.Zone;
import com.yahoo.test.ManualClock;
import com.yahoo.transaction.Mutex;
import com.yahoo.vespa.hosted.provision.Node;
-import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.Nodelike;
import com.yahoo.vespa.hosted.provision.applications.Application;
@@ -29,11 +25,9 @@ import com.yahoo.vespa.hosted.provision.provisioning.HostResourcesCalculator;
import com.yahoo.vespa.hosted.provision.provisioning.ProvisioningTester;
import java.time.Duration;
-import java.time.Instant;
+import java.util.ArrayList;
import java.util.List;
-import java.util.Map;
import java.util.Set;
-import java.util.function.IntFunction;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -48,29 +42,17 @@ class AutoscalingTester {
private final HostResourcesCalculator hostResourcesCalculator;
private final CapacityPolicies capacityPolicies;
- /** Creates an autoscaling tester with a single host type ready */
- public AutoscalingTester(NodeResources hostResources) {
- this(Environment.prod, hostResources);
- }
-
- public AutoscalingTester(Environment environment, NodeResources hostResources) {
- this(new Zone(environment, RegionName.from("us-east")), hostResources, null);
- }
-
- public AutoscalingTester(Zone zone, NodeResources hostResources, HostResourcesCalculator resourcesCalculator) {
+ public AutoscalingTester(Zone zone, HostResourcesCalculator resourcesCalculator, List<NodeResources> hostResources) {
this(zone, hostResources, resourcesCalculator, 20);
}
- private AutoscalingTester(Zone zone, NodeResources hostResources, HostResourcesCalculator resourcesCalculator, int hostCount) {
- this(zone, List.of(new Flavor("hostFlavor", hostResources)), resourcesCalculator);
- provisioningTester.makeReadyNodes(hostCount, "hostFlavor", NodeType.host, 8);
+ private AutoscalingTester(Zone zone, List<NodeResources> hostResources, HostResourcesCalculator resourcesCalculator, int hostCount) {
+ this(zone, toFlavors(hostResources), resourcesCalculator);
+ for (Flavor flavor : toFlavors(hostResources))
+ provisioningTester.makeReadyNodes(hostCount, flavor.name(), NodeType.host, 8);
provisioningTester.activateTenantHosts();
}
- public AutoscalingTester(Zone zone, List<Flavor> flavors) {
- this(zone, flavors, new MockHostResourcesCalculator(zone, 3));
- }
-
private AutoscalingTester(Zone zone, List<Flavor> flavors, HostResourcesCalculator resourcesCalculator) {
provisioningTester = new ProvisioningTester.Builder().zone(zone)
.flavors(flavors)
@@ -83,6 +65,13 @@ class AutoscalingTester {
capacityPolicies = new CapacityPolicies(provisioningTester.nodeRepository());
}
+ private static List<Flavor> toFlavors(List<NodeResources> resources) {
+ List<Flavor> flavors = new ArrayList<>();
+ for (int i = 0; i < resources.size(); i++)
+ flavors.add(new Flavor("flavor" + i, resources.get(i)));
+ return flavors;
+ }
+
public static Fixture.Builder fixture() { return new Fixture.Builder(); }
public ProvisioningTester provisioning() { return provisioningTester; }
@@ -121,10 +110,6 @@ class AutoscalingTester {
nodeRepository().nodes().setReady(List.of(host), Agent.system, getClass().getSimpleName());
}
- public void deactivateRetired(ApplicationId application, ClusterSpec cluster, ClusterResources resources) {
- deactivateRetired(application, cluster, Capacity.from(resources));
- }
-
public void deactivateRetired(ApplicationId application, ClusterSpec cluster, Capacity capacity) {
try (Mutex lock = nodeRepository().nodes().lock(application)) {
for (Node node : nodeRepository().nodes().list(Node.State.active).owner(application)) {
@@ -135,145 +120,6 @@ class AutoscalingTester {
deploy(application, cluster, capacity);
}
- public ClusterModel clusterModel(ApplicationId applicationId, ClusterSpec clusterSpec) {
- var application = nodeRepository().applications().get(applicationId).get();
- return new ClusterModel(application,
- clusterSpec,
- application.cluster(clusterSpec.id()).get(),
- nodeRepository().nodes().list(Node.State.active).cluster(clusterSpec.id()),
- nodeRepository().metricsDb(),
- nodeRepository().clock());
- }
-
- /**
- * Adds measurements with the given resource value and ideal values for the other resources,
- * scaled to take one node redundancy into account.
- * (I.e we adjust to measure a bit lower load than "naively" wanted to offset for the autoscaler
- * wanting to see the ideal load with one node missing.)
- *
- * @param otherResourcesLoad the load factor relative to ideal to use for other resources
- * @param count the number of measurements
- * @param applicationId the application we're adding measurements for all nodes of
- */
- public Duration addCpuMeasurements(float value, float otherResourcesLoad,
- int count, ApplicationId applicationId) {
- NodeList nodes = nodeRepository().nodes().list(Node.State.active).owner(applicationId);
- float oneExtraNodeFactor = (float)(nodes.size() - 1.0) / (nodes.size());
- Instant initialTime = clock().instant();
- for (int i = 0; i < count; i++) {
- clock().advance(Duration.ofSeconds(150));
- for (Node node : nodes) {
- Load load = new Load(value,
- ClusterModel.idealMemoryLoad * otherResourcesLoad,
- ClusterModel.idealContentDiskLoad * otherResourcesLoad).multiply(oneExtraNodeFactor);
- nodeMetricsDb().addNodeMetrics(List.of(new Pair<>(node.hostname(),
- new NodeMetricSnapshot(clock().instant(),
- load,
- 0,
- true,
- true,
- 0.0))));
- }
- }
- return Duration.between(initialTime, clock().instant());
- }
-
- /**
- * Adds measurements with the given resource value and ideal values for the other resources,
- * scaled to take one node redundancy into account.
- * (I.e we adjust to measure a bit lower load than "naively" wanted to offset for the autoscaler
- * wanting to see the ideal load with one node missing.)
- *
- * @param otherResourcesLoad the load factor relative to ideal to use for other resources
- * @param count the number of measurements
- * @param applicationId the application we're adding measurements for all nodes of
- * @return the duration added to the current time by this
- */
- public Duration addDiskMeasurements(float value, float otherResourcesLoad,
- int count, ApplicationId applicationId) {
- NodeList nodes = nodeRepository().nodes().list(Node.State.active).owner(applicationId);
- float oneExtraNodeFactor = (float)(nodes.size() - 1.0) / (nodes.size());
- Instant initialTime = clock().instant();
- for (int i = 0; i < count; i++) {
- clock().advance(Duration.ofSeconds(150));
- for (Node node : nodes) {
- Load load = new Load(ClusterModel.idealQueryCpuLoad * otherResourcesLoad,
- ClusterModel.idealContentDiskLoad * otherResourcesLoad,
- value).multiply(oneExtraNodeFactor);
- nodeMetricsDb().addNodeMetrics(List.of(new Pair<>(node.hostname(),
- new NodeMetricSnapshot(clock().instant(),
- load,
- 0,
- true,
- true,
- 0.0))));
- }
- }
- return Duration.between(initialTime, clock().instant());
- }
-
- /**
- * Adds measurements with the given resource value and ideal values for the other resources,
- * scaled to take one node redundancy into account.
- * (I.e we adjust to measure a bit lower load than "naively" wanted to offset for the autoscaler
- * wanting to see the ideal load with one node missing.)
- *
- * @param otherResourcesLoad the load factor relative to ideal to use for other resources
- * @param count the number of measurements
- * @param applicationId the application we're adding measurements for all nodes of
- */
- public void addMemMeasurements(float value, float otherResourcesLoad,
- int count, ApplicationId applicationId) {
- NodeList nodes = nodeRepository().nodes().list(Node.State.active).owner(applicationId);
- float oneExtraNodeFactor = (float)(nodes.size() - 1.0) / (nodes.size());
- for (int i = 0; i < count; i++) {
- clock().advance(Duration.ofMinutes(1));
- for (Node node : nodes) {
- float cpu = (float) 0.2 * otherResourcesLoad * oneExtraNodeFactor;
- float memory = value * oneExtraNodeFactor;
- float disk = (float) ClusterModel.idealContentDiskLoad * otherResourcesLoad * oneExtraNodeFactor;
- Load load = new Load(0.2 * otherResourcesLoad,
- value,
- ClusterModel.idealContentDiskLoad * otherResourcesLoad).multiply(oneExtraNodeFactor);
- nodeMetricsDb().addNodeMetrics(List.of(new Pair<>(node.hostname(),
- new NodeMetricSnapshot(clock().instant(),
- load,
- 0,
- true,
- true,
- 0.0))));
- }
- }
- }
-
- public void addMeasurements(float cpu, float memory, float disk, int count, ApplicationId applicationId) {
- addMeasurements(cpu, memory, disk, 0, true, true, count, applicationId);
- }
-
- public void addMeasurements(float cpu, float memory, float disk, int generation, boolean inService, boolean stable,
- int count, ApplicationId applicationId) {
- NodeList nodes = nodeRepository().nodes().list(Node.State.active).owner(applicationId);
- for (int i = 0; i < count; i++) {
- clock().advance(Duration.ofMinutes(1));
- for (Node node : nodes) {
- nodeMetricsDb().addNodeMetrics(List.of(new Pair<>(node.hostname(),
- new NodeMetricSnapshot(clock().instant(),
- new Load(cpu, memory, disk),
- generation,
- inService,
- stable,
- 0.0))));
- }
- }
- }
-
- public void storeReadShare(double currentReadShare, double maxReadShare, ApplicationId applicationId) {
- Application application = nodeRepository().applications().require(applicationId);
- application = application.with(application.status().withCurrentReadShare(currentReadShare)
- .withMaxReadShare(maxReadShare));
- nodeRepository().applications().put(application, nodeRepository().nodes().lock(applicationId));
- }
-
/** Creates a single redeployment event with bogus data except for the given duration */
public void setScalingDuration(ApplicationId applicationId, ClusterSpec.Id clusterId, Duration duration) {
Application application = nodeRepository().applications().require(applicationId);
@@ -294,47 +140,6 @@ class AutoscalingTester {
nodeRepository().applications().put(application, nodeRepository().nodes().lock(applicationId));
}
- /** Creates the given number of measurements, spaced 5 minutes between, using the given function */
- public Duration addLoadMeasurements(ApplicationId application,
- ClusterSpec.Id cluster,
- int measurements,
- IntFunction<Double> queryRate,
- IntFunction<Double> writeRate) {
- Instant initialTime = clock().instant();
- for (int i = 0; i < measurements; i++) {
- nodeMetricsDb().addClusterMetrics(application,
- Map.of(cluster, new ClusterMetricSnapshot(clock().instant(),
- queryRate.apply(i),
- writeRate.apply(i))));
- clock().advance(Duration.ofMinutes(5));
- }
- return Duration.between(initialTime, clock().instant());
- }
-
- /** Creates the given number of measurements, spaced 5 minutes between, using the given function */
- public Duration addQueryRateMeasurements(ApplicationId application,
- ClusterSpec.Id cluster,
- int measurements,
- IntFunction<Double> queryRate) {
- return addQueryRateMeasurements(application, cluster, measurements, Duration.ofMinutes(5), queryRate);
- }
-
- public Duration addQueryRateMeasurements(ApplicationId application,
- ClusterSpec.Id cluster,
- int measurements,
- Duration samplingInterval,
- IntFunction<Double> queryRate) {
- Instant initialTime = clock().instant();
- for (int i = 0; i < measurements; i++) {
- nodeMetricsDb().addClusterMetrics(application,
- Map.of(cluster, new ClusterMetricSnapshot(clock().instant(),
- queryRate.apply(i),
- 0.0)));
- clock().advance(samplingInterval);
- }
- return Duration.between(initialTime, clock().instant());
- }
-
public Autoscaler.Advice autoscale(ApplicationId applicationId, ClusterSpec cluster, Capacity capacity) {
capacity = capacityPolicies.applyOn(capacity, applicationId, capacityPolicies.decideExclusivity(capacity, cluster.isExclusive()));
Application application = nodeRepository().applications().get(applicationId).orElse(Application.empty(applicationId))