diff options
author | Jon Bratseth <bratseth@oath.com> | 2020-09-29 00:05:15 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-09-29 00:05:15 +0200 |
commit | 8884e08b3b394e19901b8bbde5c6889b75e772f1 (patch) | |
tree | d268c8a8dff8303cd3b8e0a40778c17f3c04e1cb /node-repository | |
parent | 243ba9ab96b9ef4be55442641c6b8472994e6e40 (diff) | |
parent | 16f7e8910a17f437f1a581610fe8f468bad5a892 (diff) |
Merge pull request #14560 from vespa-engine/bratseth/autoscaling-reconfiguration-events
Bratseth/autoscaling reconfiguration events
Diffstat (limited to 'node-repository')
30 files changed, 622 insertions, 362 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java index ba63376d61e..d359b86ae85 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java @@ -1,6 +1,7 @@ // Copyright Verizon Media. 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.config.provision.ApplicationId; import com.yahoo.config.provision.ClusterResources; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.vespa.hosted.provision.Node; @@ -8,7 +9,11 @@ import com.yahoo.vespa.hosted.provision.NodeRepository; import com.yahoo.vespa.hosted.provision.applications.Cluster; import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; @@ -63,11 +68,13 @@ public class Autoscaler { private Optional<AllocatableClusterResources> autoscale(List<Node> clusterNodes, Limits limits, boolean exclusive) { if (unstable(clusterNodes)) return Optional.empty(); - ClusterSpec.Type clusterType = clusterNodes.get(0).allocation().get().membership().cluster().type(); AllocatableClusterResources currentAllocation = new AllocatableClusterResources(clusterNodes, nodeRepository); - Optional<Double> cpuLoad = averageLoad(Resource.cpu, clusterNodes, clusterType); - Optional<Double> memoryLoad = averageLoad(Resource.memory, clusterNodes, clusterType); - Optional<Double> diskLoad = averageLoad(Resource.disk, clusterNodes, clusterType); + + MetricSnapshot metricSnapshot = new MetricSnapshot(clusterNodes, metricsDb, nodeRepository); + + Optional<Double> cpuLoad = metricSnapshot.averageLoad(Resource.cpu); + Optional<Double> memoryLoad = metricSnapshot.averageLoad(Resource.memory); + Optional<Double> diskLoad = metricSnapshot.averageLoad(Resource.disk); if (cpuLoad.isEmpty() || memoryLoad.isEmpty() || diskLoad.isEmpty()) return Optional.empty(); var target = ResourceTarget.idealLoad(cpuLoad.get(), memoryLoad.get(), diskLoad.get(), currentAllocation); @@ -93,23 +100,6 @@ public class Autoscaler { return Math.abs(r1 - r2) / (( r1 + r2) / 2) < threshold; } - /** - * Returns the average load of this resource in the measurement window, - * or empty if we are not in a position to make decisions from these measurements at this time. - */ - private Optional<Double> averageLoad(Resource resource, List<Node> clusterNodes, ClusterSpec.Type clusterType) { - NodeMetricsDb.Window window = metricsDb.getWindow(nodeRepository.clock().instant().minus(scalingWindow(clusterType)), - resource, - clusterNodes.stream().map(Node::hostname).collect(Collectors.toList())); - - // Require a total number of measurements scaling with the number of nodes, - // but don't require that we have at least that many from every node - if (window.measurementCount()/clusterNodes.size() < minimumMeasurementsPerNode(clusterType)) return Optional.empty(); - if (window.hostnames() != clusterNodes.size()) return Optional.empty(); - - return Optional.of(window.average()); - } - /** The duration of the window we need to consider to make a scaling decision. See also minimumMeasurementsPerNode */ static Duration scalingWindow(ClusterSpec.Type clusterType) { if (clusterType.isContent()) return Duration.ofHours(12); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Metric.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Metric.java new file mode 100644 index 00000000000..b98535f19c3 --- /dev/null +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Metric.java @@ -0,0 +1,46 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.provision.autoscale; + +/** + * A kind of measurement we are making for autoscaling purposes + * + * @author bratseth + */ +public enum Metric { + + cpu { // a node resource + public String fullName() { return "cpu.util"; } + float valueFromMetric(double metricValue) { return (float)metricValue / 100; } // % to ratio + }, + memory { // a node resource + public String fullName() { return "mem_total.util"; } + float valueFromMetric(double metricValue) { return (float)metricValue / 100; } // % to ratio + }, + disk { // a node resource + public String fullName() { return "disk.util"; } + float valueFromMetric(double metricValue) { return (float)metricValue / 100; } // % to ratio + }, + generation { // application config generation active on the node + public String fullName() { return "application_generation"; } + float valueFromMetric(double metricValue) { return (float)metricValue; } // Really an integer, ok up to 16M gens + }; + + /** The name of this metric as emitted from its source */ + public abstract String fullName(); + + /** Convert from the emitted value of this metric to the value we want to use here */ + abstract float valueFromMetric(double metricValue); + + public static Metric fromFullName(String name) { + for (Metric metric : values()) + if (metric.fullName().equals(name)) return metric; + throw new IllegalArgumentException("Metric '" + name + "' has no mapping"); + } + + public static Metric from(Resource resource) { + for (Metric metric : values()) + if (metric.name().equals(resource.name())) return metric; + throw new IllegalArgumentException("Resource '" + resource + "' does not map to a metric"); + } + +} diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricSnapshot.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricSnapshot.java new file mode 100644 index 00000000000..46ba4351082 --- /dev/null +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricSnapshot.java @@ -0,0 +1,98 @@ +// Copyright Verizon Media. 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.config.provision.ApplicationId; +import com.yahoo.config.provision.ClusterSpec; +import com.yahoo.vespa.hosted.provision.Node; +import com.yahoo.vespa.hosted.provision.NodeRepository; + +import java.time.Instant; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * A snapshot which implements the questions we want to ask about metrics for one cluster at one point in time. + * + * @author bratseth + */ +public class MetricSnapshot { + + private final List<Node> clusterNodes; + private final NodeMetricsDb db; + private final NodeRepository nodeRepository; + private final Map<String, Instant> startTimePerHost; + + public MetricSnapshot(List<Node> clusterNodes, NodeMetricsDb db, NodeRepository nodeRepository) { + this.clusterNodes = clusterNodes; + this.db = db; + this.nodeRepository = nodeRepository; + this.startTimePerHost = metricStartTimes(clusterNodes, db, nodeRepository); + } + + /** + * Returns the instant of the oldest metric to consider for each node, or an empty map if metrics from the + * entire (max) window should be considered. + */ + private static Map<String, Instant> metricStartTimes(List<Node> clusterNodes, + NodeMetricsDb db, + NodeRepository nodeRepository) { + ApplicationId application = clusterNodes.get(0).allocation().get().owner(); + List<NodeMetricsDb.AutoscalingEvent> deployments = db.getEvents(application); + Map<String, Instant> startTimePerHost = new HashMap<>(); + if (!deployments.isEmpty()) { + var deployment = deployments.get(deployments.size() - 1); + List<NodeMetricsDb.NodeMeasurements> generationMeasurements = + db.getMeasurements(deployment.time(), + Metric.generation, + clusterNodes.stream().map(Node::hostname).collect(Collectors.toList())); + for (Node node : clusterNodes) { + startTimePerHost.put(node.hostname(), nodeRepository.clock().instant()); // Discard all unless we can prove otherwise + var nodeGenerationMeasurements = + generationMeasurements.stream().filter(m -> m.hostname().equals(node.hostname())).findAny(); + if (nodeGenerationMeasurements.isPresent()) { + var firstMeasurementOfCorrectGeneration = + nodeGenerationMeasurements.get().asList().stream() + .filter(m -> m.value() >= deployment.generation()) + .findFirst(); + if (firstMeasurementOfCorrectGeneration.isPresent()) { + startTimePerHost.put(node.hostname(), firstMeasurementOfCorrectGeneration.get().at()); + } + } + } + } + return startTimePerHost; + } + + /** + * Returns the average load of this resource in the measurement window, + * or empty if we are not in a position to make decisions from these measurements at this time. + */ + public Optional<Double> averageLoad(Resource resource) { + ClusterSpec.Type clusterType = clusterNodes.get(0).allocation().get().membership().cluster().type(); + + List<NodeMetricsDb.NodeMeasurements> measurements = + db.getMeasurements(nodeRepository.clock().instant().minus(Autoscaler.scalingWindow(clusterType)), + Metric.from(resource), + clusterNodes.stream().map(Node::hostname).collect(Collectors.toList())); + measurements = filterStale(measurements, startTimePerHost); + + // Require a total number of measurements scaling with the number of nodes, + // but don't require that we have at least that many from every node + int measurementCount = measurements.stream().mapToInt(m -> m.size()).sum(); + if (measurementCount / clusterNodes.size() < Autoscaler.minimumMeasurementsPerNode(clusterType)) return Optional.empty(); + if (measurements.size() != clusterNodes.size()) return Optional.empty(); + + double measurementSum = measurements.stream().flatMap(m -> m.asList().stream()).mapToDouble(m -> m.value()).sum(); + return Optional.of(measurementSum / measurementCount); + } + + private List<NodeMetricsDb.NodeMeasurements> filterStale(List<NodeMetricsDb.NodeMeasurements> measurements, + Map<String, Instant> startTimePerHost) { + if (startTimePerHost.isEmpty()) return measurements; // Map is either empty or complete + return measurements.stream().map(m -> m.copyAfter(startTimePerHost.get(m.hostname()))).collect(Collectors.toList()); + } + +} diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java index 87551a5bd5f..b4195b4cdf1 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java @@ -46,16 +46,16 @@ public class MetricsResponse { private void consumeNodeMetrics(String hostname, Inspector node) { long timestampSecond = node.field("timestamp").asLong(); Map<String, Double> values = consumeMetrics(node.field("metrics")); - for (Resource resource : Resource.values()) - addMetricIfPresent(hostname, resource, timestampSecond, values); + for (Metric metric : Metric.values()) + addMetricIfPresent(hostname, metric, timestampSecond, values); } - private void addMetricIfPresent(String hostname, Resource resource, long timestampSecond, Map<String, Double> values) { - if (values.containsKey(resource.metricName())) + private void addMetricIfPresent(String hostname, Metric metric, long timestampSecond, Map<String, Double> values) { + if (values.containsKey(metric.fullName())) metricValues.add(new NodeMetrics.MetricValue(hostname, - resource.metricName(), + metric.fullName(), timestampSecond, - values.get(resource.metricName()))); + values.get(metric.fullName()))); } private void consumeServiceMetrics(String hostname, Inspector node) { diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDb.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDb.java index 316708732a7..635f3ffc081 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDb.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDb.java @@ -1,6 +1,7 @@ // Copyright Verizon Media. 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.config.provision.ApplicationId; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.vespa.hosted.provision.Node; import com.yahoo.vespa.hosted.provision.NodeRepository; @@ -9,6 +10,7 @@ import java.time.Clock; import java.time.Instant; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -30,6 +32,9 @@ public class NodeMetricsDb { /** Measurements by key. Each list of measurements is sorted by increasing timestamp */ private final Map<NodeMeasurementsKey, NodeMeasurements> db = new HashMap<>(); + /** Events */ + private final List<AutoscalingEvent> events = new ArrayList<>(); + /** Lock all access for now since we modify lists inside a map */ private final Object lock = new Object(); @@ -37,120 +42,89 @@ public class NodeMetricsDb { this.nodeRepository = nodeRepository; } - /** Add measurements to this */ + /** Adds measurements to this. */ public void add(Collection<NodeMetrics.MetricValue> metricValues) { synchronized (lock) { for (var value : metricValues) { - Resource resource = Resource.fromMetric(value.name()); - NodeMeasurementsKey key = new NodeMeasurementsKey(value.hostname(), resource); + Metric metric = Metric.fromFullName(value.name()); + NodeMeasurementsKey key = new NodeMeasurementsKey(value.hostname(), metric); NodeMeasurements measurements = db.get(key); if (measurements == null) { // new node Optional<Node> node = nodeRepository.getNode(value.hostname()); if (node.isEmpty()) continue; if (node.get().allocation().isEmpty()) continue; measurements = new NodeMeasurements(value.hostname(), - resource, - node.get().allocation().get().membership().cluster().type()); + metric, + node.get().allocation().get().membership().cluster().type(), + new ArrayList<>()); db.put(key, measurements); } measurements.add(new Measurement(value.timestampSecond() * 1000, - (float)resource.valueFromMetric(value.value()))); + metric.valueFromMetric(value.value()))); } } } - /** Must be called intermittently (as long as add is called) to gc old measurements */ + /** Adds an event to this */ + public void add(AutoscalingEvent event) { + synchronized (lock) { + events.add(event); + } + } + + /** Must be called intermittently (as long as any add methods are called) to gc old data */ public void gc(Clock clock) { synchronized (lock) { // Each measurement is Object + long + float = 16 + 8 + 4 = 28 bytes // 12 hours with 1k nodes and 3 resources and 1 measurement/sec is about 5Gb - for (Iterator<NodeMeasurements> i = db.values().iterator(); i.hasNext(); ) { var measurements = i.next(); measurements.removeOlderThan(clock.instant().minus(Autoscaler.scalingWindow(measurements.type)).toEpochMilli()); if (measurements.isEmpty()) i.remove(); } - } - } - - /** Returns a window within which we can ask for specific information from this db */ - public Window getWindow(Instant startTime, Resource resource, List<String> hostnames) { - return new Window(startTime, resource, hostnames); - } - - public class Window { - - private final long startTime; - private final List<NodeMeasurementsKey> keys; - private Window(Instant startTime, Resource resource, List<String> hostnames) { - this.startTime = startTime.toEpochMilli(); - keys = hostnames.stream().map(hostname -> new NodeMeasurementsKey(hostname, resource)).collect(Collectors.toList()); + // TODO: gc events } + } - public int measurementCount() { - synchronized (lock) { - int count = 0; - for (NodeMeasurementsKey key : keys) { - NodeMeasurements measurements = db.get(key); - if (measurements == null) continue; - count += measurements.after(startTime).size(); - } - return count; - } - } - - /** Returns the count of hostnames which have measurements in this window */ - public int hostnames() { - synchronized (lock) { - int count = 0; - for (NodeMeasurementsKey key : keys) { - NodeMeasurements measurements = db.get(key); - if (measurements == null || measurements.isEmpty()) continue; - - if (measurements.get(measurements.size() - 1).timestamp >= startTime) - count++; - } - return count; + /** + * Returns a list of measurements with one entry for each of the given host names + * which have any values after startTime, in the same order + */ + public List<NodeMeasurements> getMeasurements(Instant startTime, Metric metric, List<String> hostnames) { + synchronized (lock) { + List<NodeMeasurements> measurementsList = new ArrayList<>(hostnames.size()); + for (String hostname : hostnames) { + NodeMeasurements measurements = db.get(new NodeMeasurementsKey(hostname, metric)); + if (measurements == null) continue; + measurements = measurements.copyAfter(startTime); + if (measurements.isEmpty()) continue; + measurementsList.add(measurements); } + return measurementsList; } + } - public double average() { - synchronized (lock) { - double sum = 0; - int count = 0; - for (NodeMeasurementsKey key : keys) { - NodeMeasurements measurements = db.get(key); - if (measurements == null) continue; - - int index = measurements.size() - 1; - while (index >= 0 && measurements.get(index).timestamp >= startTime) { - sum += measurements.get(index).value; - count++; - - index--; - } - } - return sum / count; - } + public List<AutoscalingEvent> getEvents(ApplicationId application) { + synchronized (lock) { + return events.stream().filter(event -> event.application().equals(application)).collect(Collectors.toList()); } - } private static class NodeMeasurementsKey { private final String hostname; - private final Resource resource; + private final Metric metric; - public NodeMeasurementsKey(String hostname, Resource resource) { + public NodeMeasurementsKey(String hostname, Metric metric) { this.hostname = hostname; - this.resource = resource; + this.metric = metric; } @Override public int hashCode() { - return Objects.hash(hostname, resource); + return Objects.hash(hostname, metric); } @Override @@ -159,65 +133,104 @@ public class NodeMetricsDb { if ( ! (o instanceof NodeMeasurementsKey)) return false; NodeMeasurementsKey other = (NodeMeasurementsKey)o; if ( ! this.hostname.equals(other.hostname)) return false; - if ( ! this.resource.equals(other.resource)) return false; + if ( ! this.metric.equals(other.metric)) return false; return true; } @Override - public String toString() { return "key to measurements of " + resource + " for " + hostname; } + public String toString() { return "key to measurements of " + metric + " for " + hostname; } } - private static class NodeMeasurements { + public static class NodeMeasurements { private final String hostname; - private final Resource resource; + private final Metric metric; private final ClusterSpec.Type type; - private final List<Measurement> measurements = new ArrayList<>(); + private final List<Measurement> measurements; - public NodeMeasurements(String hostname, Resource resource, ClusterSpec.Type type) { + // Note: This transfers ownership of the measurement list to this + private NodeMeasurements(String hostname, Metric metric, ClusterSpec.Type type, List<Measurement> measurements) { this.hostname = hostname; - this.resource = resource; + this.metric = metric; this.type = type; + this.measurements = measurements; } - void removeOlderThan(long oldestTimestamp) { - while (!measurements.isEmpty() && measurements.get(0).timestamp < oldestTimestamp) - measurements.remove(0); - } + // Public access + + public boolean isEmpty() { return measurements.isEmpty(); } - boolean isEmpty() { return measurements.isEmpty(); } + public int size() { return measurements.size(); } - int size() { return measurements.size(); } + public Measurement get(int index) { return measurements.get(index); } - Measurement get(int index) { return measurements.get(index); } + public List<Measurement> asList() { return Collections.unmodifiableList(measurements); } - void add(Measurement measurement) { measurements.add(measurement); } + public String hostname() { return hostname; } - public List<Measurement> after(long oldestTimestamp) { - return measurements.stream() - .filter(measurement -> measurement.timestamp >= oldestTimestamp) - .collect(Collectors.toList()); + public NodeMeasurements copyAfter(Instant oldestTime) { + long oldestTimestamp = oldestTime.toEpochMilli(); + return new NodeMeasurements(hostname, metric, type, + measurements.stream() + .filter(measurement -> measurement.timestamp >= oldestTimestamp) + .collect(Collectors.toList())); + } + + // Private mutation + + private void add(Measurement measurement) { measurements.add(measurement); } + + private void removeOlderThan(long oldestTimestamp) { + while (!measurements.isEmpty() && measurements.get(0).timestamp < oldestTimestamp) + measurements.remove(0); } } - private static class Measurement { + public static class Measurement { + // TODO: Order by timestamp /** The time of this measurement in epoch millis */ private final long timestamp; /** The measured value */ - private final float value; + private final double value; public Measurement(long timestamp, float value) { this.timestamp = timestamp; this.value = value; } + public double value() { return value; } + public Instant at() { return Instant.ofEpochMilli(timestamp); } + @Override public String toString() { return "measurement at " + timestamp + ": " + value; } } + public static class AutoscalingEvent { + + private final ApplicationId application; + private final long generation; + private final long timestamp; + + public AutoscalingEvent(ApplicationId application, long generation, Instant times) { + this.application = application; + this.generation = generation; + this.timestamp = times.toEpochMilli(); + } + + /** Returns the deployed application */ + public ApplicationId application() { return application; } + + /** Returns the application config generation resulting from this deployment */ + public long generation() { return generation; } + + /** Returns the time of this deployment */ + public Instant time() { return Instant.ofEpochMilli(timestamp); } + + } + } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Resource.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Resource.java index 3d5ce8881e0..7f1844efdbe 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Resource.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Resource.java @@ -12,41 +12,31 @@ public enum Resource { /** Cpu utilization ratio */ cpu { - public String metricName() { return "cpu.util"; } double idealAverageLoad() { return 0.2; } double valueFrom(NodeResources resources) { return resources.vcpu(); } - double valueFromMetric(double metricValue) { return metricValue / 100; } // % to ratio }, /** Memory utilization ratio */ memory { - public String metricName() { return "mem_total.util"; } double idealAverageLoad() { return 0.7; } double valueFrom(NodeResources resources) { return resources.memoryGb(); } - double valueFromMetric(double metricValue) { return metricValue / 100; } // % to ratio }, /** Disk utilization ratio */ disk { - public String metricName() { return "disk.util"; } double idealAverageLoad() { return 0.6; } double valueFrom(NodeResources resources) { return resources.diskGb(); } - double valueFromMetric(double metricValue) { return metricValue / 100; } // % to ratio }; - public abstract String metricName(); - /** The load we should have of this resource on average, when one node in the cluster is down */ abstract double idealAverageLoad(); abstract double valueFrom(NodeResources resources); - abstract double valueFromMetric(double metricValue); - - public static Resource fromMetric(String metricName) { + public static Resource from(Metric metric) { for (Resource resource : values()) - if (resource.metricName().equals(metricName)) return resource; - throw new IllegalArgumentException("Metric '" + metricName + "' does not map to a resource"); + if (resource.name().equals(metric.name())) return resource; + throw new IllegalArgumentException("Metric '" + metric + "' does not map to a resource"); } } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainer.java index b3c76300173..b41b7f15499 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainer.java @@ -83,7 +83,7 @@ public abstract class ApplicationMaintainer extends NodeRepositoryMaintainer { try (MaintenanceDeployment deployment = new MaintenanceDeployment(application, deployer, metric, nodeRepository())) { if ( ! deployment.isValid()) return false; // this will be done at another config server log.log(Level.INFO, application + " will be deployed, last deploy time " + getLastDeployTime(application)); - return deployment.activate(); + return deployment.activate().isPresent(); } finally { pendingDeployments.remove(application); } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java index ddee1afe21e..80077990e6a 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java @@ -5,7 +5,6 @@ import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.ClusterResources; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.Deployer; -import com.yahoo.config.provision.NodeResources; import com.yahoo.jdisc.Metric; import com.yahoo.vespa.hosted.provision.Node; import com.yahoo.vespa.hosted.provision.NodeRepository; @@ -29,6 +28,7 @@ import java.util.stream.Collectors; */ public class AutoscalingMaintainer extends NodeRepositoryMaintainer { + private final NodeMetricsDb metricsDb; private final Autoscaler autoscaler; private final Deployer deployer; private final Metric metric; @@ -40,6 +40,7 @@ public class AutoscalingMaintainer extends NodeRepositoryMaintainer { Duration interval) { super(nodeRepository, interval, metric); this.autoscaler = new Autoscaler(metricsDb, nodeRepository); + this.metricsDb = metricsDb; this.metric = metric; this.deployer = deployer; } @@ -72,7 +73,12 @@ public class AutoscalingMaintainer extends NodeRepositoryMaintainer { applications().put(application.with(cluster.get().withTarget(target)), deployment.applicationLock().get()); if (target.isPresent()) { logAutoscaling(target.get(), applicationId, clusterId, clusterNodes); - deployment.activate(); + Optional<Long> resultingGeneration = deployment.activate(); + if (resultingGeneration.isEmpty()) return; // Failed to activate + + metricsDb.add(new NodeMetricsDb.AutoscalingEvent(applicationId, + resultingGeneration.get(), + nodeRepository().clock().instant())); } } } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceDeployment.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceDeployment.java index 4e1be9c486c..75fd16697b4 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceDeployment.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceDeployment.java @@ -9,6 +9,7 @@ import com.yahoo.config.provision.TransientException; import com.yahoo.jdisc.Metric; import java.util.Objects; +import java.util.function.Supplier; import java.util.logging.Level; import com.yahoo.transaction.Mutex; import com.yahoo.vespa.hosted.provision.Node; @@ -71,33 +72,32 @@ class MaintenanceDeployment implements Closeable { } public boolean prepare() { - return doStep(() -> deployment.get().prepare()); + return doStep(() -> { deployment.get().prepare(); return 0L; }).isPresent(); } /** * Attempts to activate this deployment * - * @return whether it was successfully activated + * @return the application config generation resulting from this deployment, or empty if it was not successful */ - public boolean activate() { + public Optional<Long> activate() { return doStep(() -> deployment.get().activate()); } - private boolean doStep(Runnable action) { + private Optional<Long> doStep(Supplier<Long> step) { if (closed) throw new IllegalStateException(this + "' is closed"); - if ( ! isValid()) return false; + if ( ! isValid()) return Optional.empty(); try { - action.run(); - return true; + return Optional.of(step.get()); } catch (TransientException e) { metric.add("maintenanceDeployment.transientFailure", 1, metric.createContext(Map.of())); log.log(Level.INFO, "Failed to maintenance deploy " + application + " with a transient error: " + Exceptions.toMessageString(e)); - return false; + return Optional.empty(); } catch (RuntimeException e) { metric.add("maintenanceDeployment.failure", 1, metric.createContext(Map.of())); log.log(Level.WARNING, "Exception on maintenance deploy of " + application, e); - return false; + return Optional.empty(); } } @@ -175,7 +175,7 @@ class MaintenanceDeployment implements Closeable { if (expectedNewNode.isEmpty()) return false; if (!expectedNewNode.get().hasParent(toHost.hostname())) return false; } - if ( ! deployment.activate()) return false; + if ( deployment.activate().isEmpty()) return false; log.info(agent + " redeployed " + application + " to " + ( verifyTarget ? this : "move " + (node.hostname() + " from " + fromHost))); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirer.java index 5b7f90102ba..62c90ffe433 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirer.java @@ -68,7 +68,7 @@ public class RetiredExpirer extends NodeRepositoryMaintainer { nodeRepository().setRemovable(application, nodesToRemove); - boolean success = deployment.activate(); + boolean success = deployment.activate().isPresent(); if ( ! success) return success; String nodeList = nodesToRemove.stream().map(Node::hostname).collect(Collectors.joining(", ")); log.info("Redeployed " + application + " to deactivate retired nodes: " + nodeList); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java index 2bcbac828b8..00d1cd84e4c 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java @@ -71,6 +71,34 @@ public class AutoscalingTest { tester.autoscale(application1, cluster1.id(), min, max)); } + /** We prefer fewer nodes for container clusters as (we assume) they all use the same disk and memory */ + @Test + public void test_autoscaling_single_container_group() { + NodeResources resources = new NodeResources(3, 100, 100, 1); + ClusterResources min = new ClusterResources( 2, 1, new NodeResources(1, 1, 1, 1)); + ClusterResources max = new ClusterResources(20, 1, new NodeResources(100, 1000, 1000, 1)); + AutoscalingTester tester = new AutoscalingTester(resources); + + ApplicationId application1 = tester.applicationId("application1"); + ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + + // deploy + tester.deploy(application1, cluster1, 5, 1, resources); + + tester.addMeasurements(Resource.cpu, 0.25f, 1f, 120, application1); + ClusterResources scaledResources = tester.assertResources("Scaling up since cpu usage is too high", + 7, 1, 2.5, 80.0, 80.0, + tester.autoscale(application1, cluster1.id(), min, max)); + + tester.deploy(application1, cluster1, scaledResources); + tester.deactivateRetired(application1, cluster1, scaledResources); + + tester.addMeasurements(Resource.cpu, 0.1f, 1f, 120, application1); + tester.assertResources("Scaling down since cpu usage has gone down", + 4, 1, 2.5, 68.6, 68.6, + tester.autoscale(application1, cluster1.id(), min, max)); + } + @Test public void autoscaling_handles_disk_setting_changes() { NodeResources hostResources = new NodeResources(3, 100, 100, 1, NodeResources.DiskSpeed.slow); @@ -100,34 +128,6 @@ public class AutoscalingTest { .allMatch(n -> n.allocation().get().requestedResources().diskSpeed() == NodeResources.DiskSpeed.any); } - /** We prefer fewer nodes for container clusters as (we assume) they all use the same disk and memory */ - @Test - public void test_autoscaling_single_container_group() { - NodeResources resources = new NodeResources(3, 100, 100, 1); - ClusterResources min = new ClusterResources( 2, 1, new NodeResources(1, 1, 1, 1)); - ClusterResources max = new ClusterResources(20, 1, new NodeResources(100, 1000, 1000, 1)); - AutoscalingTester tester = new AutoscalingTester(resources); - - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "cluster1"); - - // deploy - tester.deploy(application1, cluster1, 5, 1, resources); - - tester.addMeasurements(Resource.cpu, 0.25f, 1f, 120, application1); - ClusterResources scaledResources = tester.assertResources("Scaling up since cpu usage is too high", - 7, 1, 2.5, 80.0, 80.0, - tester.autoscale(application1, cluster1.id(), min, max)); - - tester.deploy(application1, cluster1, scaledResources); - tester.deactivateRetired(application1, cluster1, scaledResources); - - tester.addMeasurements(Resource.cpu, 0.1f, 1f, 120, application1); - tester.assertResources("Scaling down since cpu usage has gone down", - 4, 1, 2.5, 68.6, 68.6, - tester.autoscale(application1, cluster1.id(), min, max)); - } - @Test public void autoscaling_respects_upper_limit() { NodeResources hostResources = new NodeResources(3, 100, 100, 1); 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 cc755c01405..9e51fa37246 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 @@ -132,7 +132,7 @@ class AutoscalingTester { float effectiveValue = (r == resource ? value : (float) r.idealAverageLoad() * otherResourcesLoad) * oneExtraNodeFactor; db.add(List.of(new NodeMetrics.MetricValue(node.hostname(), - r.metricName(), + Metric.from(r).fullName(), clock().instant().toEpochMilli(), effectiveValue * 100))); // the metrics are in % } @@ -146,7 +146,7 @@ class AutoscalingTester { clock().advance(Duration.ofMinutes(1)); for (Node node : nodes) { db.add(List.of(new NodeMetrics.MetricValue(node.hostname(), - resource.metricName(), + Metric.from(resource).fullName(), clock().instant().toEpochMilli(), value * 100))); // the metrics are in % } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDbTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDbTest.java index eaad4526591..c6809fd8369 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDbTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDbTest.java @@ -26,7 +26,7 @@ public class NodeMetricsDbTest { ProvisioningTester tester = new ProvisioningTester.Builder().build(); tester.makeReadyHosts(10, new NodeResources(10, 100, 1000, 10)) .activateTenantHosts(); - ApplicationId app1 = tester.makeApplicationId("app1"); + ApplicationId app1 = ProvisioningTester.makeApplicationId("app1"); var hosts = tester.activate(app1, ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("test")).vespaVersion("7.0").build(), @@ -45,11 +45,15 @@ public class NodeMetricsDbTest { // Avoid off-by-one bug when the below windows starts exactly on one of the above getEpochSecond() timestamps. clock.advance(Duration.ofMinutes(1)); - assertEquals(35, db.getWindow(clock.instant().minus(Duration.ofHours(6)), Resource.cpu, List.of(node0)).measurementCount()); - assertEquals( 0, db.getWindow(clock.instant().minus(Duration.ofHours(6)), Resource.memory, List.of(node0)).measurementCount()); + assertEquals(35, measurementCount(db.getMeasurements(clock.instant().minus(Duration.ofHours(6)), Metric.cpu, List.of(node0)))); + assertEquals( 0, measurementCount(db.getMeasurements(clock.instant().minus(Duration.ofHours(6)), Metric.memory, List.of(node0)))); db.gc(clock); - assertEquals( 5, db.getWindow(clock.instant().minus(Duration.ofHours(6)), Resource.cpu, List.of(node0)).measurementCount()); - assertEquals( 0, db.getWindow(clock.instant().minus(Duration.ofHours(6)), Resource.memory, List.of(node0)).measurementCount()); + assertEquals( 5, measurementCount(db.getMeasurements(clock.instant().minus(Duration.ofHours(6)), Metric.cpu, List.of(node0)))); + assertEquals( 0, measurementCount(db.getMeasurements(clock.instant().minus(Duration.ofHours(6)), Metric.memory, List.of(node0)))); + } + + private int measurementCount(List<NodeMetricsDb.NodeMeasurements> measurements) { + return measurements.stream().mapToInt(m -> m.size()).sum(); } } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsFetcherTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsFetcherTest.java index fea3e8da70a..ed6fa2c37b9 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsFetcherTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsFetcherTest.java @@ -30,8 +30,8 @@ public class NodeMetricsFetcherTest { tester.makeReadyNodes(4, resources); // Creates (in order) host-1.yahoo.com, host-2.yahoo.com, host-3.yahoo.com, host-4.yahoo.com tester.activateTenantHosts(); - ApplicationId application1 = tester.makeApplicationId(); - ApplicationId application2 = tester.makeApplicationId(); + ApplicationId application1 = ProvisioningTester.makeApplicationId(); + ApplicationId application2 = ProvisioningTester.makeApplicationId(); tester.deploy(application1, Capacity.from(new ClusterResources(2, 1, resources))); // host-1.yahoo.com, host-2.yahoo.com tester.deploy(application2, Capacity.from(new ClusterResources(2, 1, resources))); // host-4.yahoo.com, host-3.yahoo.com diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTest.java index 833daebc37a..d1a583e31c1 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTest.java @@ -5,27 +5,15 @@ 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.NodeResources; -import com.yahoo.config.provision.NodeType; -import com.yahoo.config.provision.RegionName; -import com.yahoo.config.provision.Zone; -import com.yahoo.config.provisioning.FlavorsConfig; -import com.yahoo.vespa.hosted.provision.Node; -import com.yahoo.vespa.hosted.provision.NodeRepository; -import com.yahoo.vespa.hosted.provision.autoscale.NodeMetrics; -import com.yahoo.vespa.hosted.provision.autoscale.NodeMetricsDb; -import com.yahoo.vespa.hosted.provision.autoscale.Resource; -import com.yahoo.vespa.hosted.provision.provisioning.FlavorConfigBuilder; -import com.yahoo.vespa.hosted.provision.provisioning.ProvisioningTester; +import com.yahoo.vespa.hosted.provision.autoscale.Metric; import com.yahoo.vespa.hosted.provision.testutils.MockDeployer; import org.junit.Test; import java.time.Duration; -import java.util.List; -import java.util.Map; +import java.time.Instant; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** @@ -38,34 +26,23 @@ public class AutoscalingMaintainerTest { @Test public void testAutoscalingMaintainer() { - ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east3"))).flavorsConfig(flavorsConfig()).build(); + ApplicationId app1 = AutoscalingMaintainerTester.makeApplicationId("app1"); + ClusterSpec cluster1 = AutoscalingMaintainerTester.containerClusterSpec(); - ApplicationId app1 = tester.makeApplicationId("app1"); - ClusterSpec cluster1 = tester.containerClusterSpec(); - - ApplicationId app2 = tester.makeApplicationId("app2"); - ClusterSpec cluster2 = tester.containerClusterSpec(); + ApplicationId app2 = AutoscalingMaintainerTester.makeApplicationId("app2"); + ClusterSpec cluster2 = AutoscalingMaintainerTester.containerClusterSpec(); NodeResources lowResources = new NodeResources(4, 4, 10, 0.1); NodeResources highResources = new NodeResources(6.5, 9, 20, 0.1); - Map<ApplicationId, MockDeployer.ApplicationContext> apps = Map.of( - app1, new MockDeployer.ApplicationContext(app1, cluster1, Capacity.from(new ClusterResources(2, 1, lowResources))), - app2, new MockDeployer.ApplicationContext(app2, cluster2, Capacity.from(new ClusterResources(2, 1, highResources)))); - MockDeployer deployer = new MockDeployer(tester.provisioner(), tester.clock(), apps); + AutoscalingMaintainerTester tester = new AutoscalingMaintainerTester( + new MockDeployer.ApplicationContext(app1, cluster1, Capacity.from(new ClusterResources(2, 1, lowResources))), + new MockDeployer.ApplicationContext(app2, cluster2, Capacity.from(new ClusterResources(2, 1, highResources)))); - NodeMetricsDb nodeMetricsDb = new NodeMetricsDb(tester.nodeRepository()); - AutoscalingMaintainer maintainer = new AutoscalingMaintainer(tester.nodeRepository(), - nodeMetricsDb, - deployer, - new TestMetric(), - Duration.ofMinutes(1)); - maintainer.maintain(); // noop - assertTrue(deployer.lastDeployTime(app1).isEmpty()); - assertTrue(deployer.lastDeployTime(app2).isEmpty()); - tester.makeReadyNodes(20, "flt", NodeType.host, 8); - tester.activateTenantHosts(); + tester.maintainer().maintain(); // noop + assertTrue(tester.deployer().lastDeployTime(app1).isEmpty()); + assertTrue(tester.deployer().lastDeployTime(app2).isEmpty()); tester.deploy(app1, cluster1, Capacity.from(new ClusterResources(5, 1, new NodeResources(4, 4, 10, 0.1)), new ClusterResources(5, 1, new NodeResources(4, 4, 10, 0.1)), @@ -74,40 +51,82 @@ public class AutoscalingMaintainerTest { new ClusterResources(10, 1, new NodeResources(6.5, 9, 20, 0.1)), false, true)); - maintainer.maintain(); // noop - assertTrue(deployer.lastDeployTime(app1).isEmpty()); - assertTrue(deployer.lastDeployTime(app2).isEmpty()); - - addMeasurements(Resource.cpu, 0.9f, 500, app1, tester.nodeRepository(), nodeMetricsDb); - addMeasurements(Resource.memory, 0.9f, 500, app1, tester.nodeRepository(), nodeMetricsDb); - addMeasurements(Resource.disk, 0.9f, 500, app1, tester.nodeRepository(), nodeMetricsDb); - addMeasurements(Resource.cpu, 0.9f, 500, app2, tester.nodeRepository(), nodeMetricsDb); - addMeasurements(Resource.memory, 0.9f, 500, app2, tester.nodeRepository(), nodeMetricsDb); - addMeasurements(Resource.disk, 0.9f, 500, app2, tester.nodeRepository(), nodeMetricsDb); + tester.maintainer().maintain(); // noop + assertTrue(tester.deployer().lastDeployTime(app1).isEmpty()); + assertTrue(tester.deployer().lastDeployTime(app2).isEmpty()); - maintainer.maintain(); - assertTrue(deployer.lastDeployTime(app1).isEmpty()); // since autoscaling is off - assertTrue(deployer.lastDeployTime(app2).isPresent()); - } + tester.addMeasurements(Metric.cpu, 0.9f, 500, app1); + tester.addMeasurements(Metric.memory, 0.9f, 500, app1); + tester.addMeasurements(Metric.disk, 0.9f, 500, app1); + tester.addMeasurements(Metric.cpu, 0.9f, 500, app2); + tester.addMeasurements(Metric.memory, 0.9f, 500, app2); + tester.addMeasurements(Metric.disk, 0.9f, 500, app2); - public void addMeasurements(Resource resource, float value, int count, ApplicationId applicationId, - NodeRepository nodeRepository, NodeMetricsDb db) { - List<Node> nodes = nodeRepository.getNodes(applicationId, Node.State.active); - for (int i = 0; i < count; i++) { - for (Node node : nodes) - db.add(List.of(new NodeMetrics.MetricValue(node.hostname(), - resource.metricName(), - nodeRepository.clock().instant().toEpochMilli(), - value * 100))); // the metrics are in % - } + tester.maintainer().maintain(); + assertTrue(tester.deployer().lastDeployTime(app1).isEmpty()); // since autoscaling is off + assertTrue(tester.deployer().lastDeployTime(app2).isPresent()); } - private FlavorsConfig flavorsConfig() { - FlavorConfigBuilder b = new FlavorConfigBuilder(); - b.addFlavor("flt", 30, 30, 40, 3, Flavor.Type.BARE_METAL); - b.addFlavor("cpu", 40, 20, 40, 3, Flavor.Type.BARE_METAL); - b.addFlavor("mem", 20, 40, 40, 3, Flavor.Type.BARE_METAL); - return b.build(); + @Test + public void autoscaling_discards_metric_values_from_before_rescaling() { + ApplicationId app1 = AutoscalingMaintainerTester.makeApplicationId("app1"); + ClusterSpec cluster1 = AutoscalingMaintainerTester.containerClusterSpec(); + NodeResources lowResources = new NodeResources(4, 4, 10, 0.1); + NodeResources highResources = new NodeResources(8, 8, 20, 0.1); + Capacity app1Capacity = Capacity.from(new ClusterResources(2, 1, lowResources), + new ClusterResources(4, 2, highResources)); + var tester = new AutoscalingMaintainerTester(new MockDeployer.ApplicationContext(app1, cluster1, app1Capacity)); + + // Initial deployment at time 0 + tester.deploy(app1, cluster1, app1Capacity); + + // Measure overload + tester.clock().advance(Duration.ofSeconds(1)); + tester.addMeasurements(Metric.cpu, 0.9f, 500, app1); + tester.addMeasurements(Metric.memory, 0.9f, 500, app1); + tester.addMeasurements(Metric.disk, 0.9f, 500, app1); + + // Causes autoscaling + tester.clock().advance(Duration.ofSeconds(1)); + Instant firstMaintenanceTime = tester.clock().instant(); + tester.maintainer().maintain(); + assertTrue(tester.deployer().lastDeployTime(app1).isPresent()); + assertEquals(firstMaintenanceTime.toEpochMilli(), tester.deployer().lastDeployTime(app1).get().toEpochMilli()); + assertEquals(1, tester.nodeMetricsDb().getEvents(app1).size()); + assertEquals(app1, tester.nodeMetricsDb().getEvents(app1).get(0).application()); + assertEquals(0, tester.nodeMetricsDb().getEvents(app1).get(0).generation()); + assertEquals(firstMaintenanceTime.toEpochMilli(), tester.nodeMetricsDb().getEvents(app1).get(0).time().toEpochMilli()); + + // Measure overload still, since change is not applied, but metrics are discarded + tester.clock().advance(Duration.ofSeconds(1)); + tester.addMeasurements(Metric.cpu, 0.9f, 500, app1); + tester.addMeasurements(Metric.memory, 0.9f, 500, app1); + tester.addMeasurements(Metric.disk, 0.9f, 500, app1); + tester.clock().advance(Duration.ofSeconds(1)); + tester.maintainer().maintain(); + assertEquals(firstMaintenanceTime.toEpochMilli(), tester.deployer().lastDeployTime(app1).get().toEpochMilli()); + + // Measure underload, but no autoscaling since we haven't measured we're on the new config generation + tester.clock().advance(Duration.ofSeconds(1)); + tester.addMeasurements(Metric.cpu, 0.1f, 500, app1); + tester.addMeasurements(Metric.memory, 0.1f, 500, app1); + tester.addMeasurements(Metric.disk, 0.1f, 500, app1); + tester.clock().advance(Duration.ofSeconds(1)); + tester.maintainer().maintain(); + assertEquals(firstMaintenanceTime.toEpochMilli(), tester.deployer().lastDeployTime(app1).get().toEpochMilli()); + + // Add measurement of the expected generation, leading to rescaling + tester.clock().advance(Duration.ofSeconds(1)); + tester.addMeasurements(Metric.generation, 0, 1, app1); + tester.addMeasurements(Metric.cpu, 0.1f, 500, app1); + tester.addMeasurements(Metric.memory, 0.1f, 500, app1); + tester.addMeasurements(Metric.disk, 0.1f, 500, app1); + //tester.clock().advance(Duration.ofSeconds(1)); + Instant lastMaintenanceTime = tester.clock().instant(); + tester.maintainer().maintain(); + assertEquals(lastMaintenanceTime.toEpochMilli(), tester.deployer().lastDeployTime(app1).get().toEpochMilli()); + assertEquals(2, tester.nodeMetricsDb().getEvents(app1).size()); + assertEquals(1, tester.nodeMetricsDb().getEvents(app1).get(1).generation()); } } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java new file mode 100644 index 00000000000..31af40b4377 --- /dev/null +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java @@ -0,0 +1,92 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.provision.maintenance; + +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.NodeResources; +import com.yahoo.config.provision.NodeType; +import com.yahoo.config.provision.RegionName; +import com.yahoo.config.provision.Zone; +import com.yahoo.config.provisioning.FlavorsConfig; +import com.yahoo.test.ManualClock; +import com.yahoo.vespa.hosted.provision.Node; +import com.yahoo.vespa.hosted.provision.NodeRepository; +import com.yahoo.vespa.hosted.provision.autoscale.Metric; +import com.yahoo.vespa.hosted.provision.autoscale.NodeMetrics; +import com.yahoo.vespa.hosted.provision.autoscale.NodeMetricsDb; +import com.yahoo.vespa.hosted.provision.provisioning.FlavorConfigBuilder; +import com.yahoo.vespa.hosted.provision.provisioning.ProvisioningTester; +import com.yahoo.vespa.hosted.provision.testutils.MockDeployer; + +import java.time.Duration; +import java.time.Instant; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @author bratseth + */ +public class AutoscalingMaintainerTester { + + private final ProvisioningTester provisioningTester; + private final NodeMetricsDb nodeMetricsDb; + private final AutoscalingMaintainer maintainer; + private final MockDeployer deployer; + + public AutoscalingMaintainerTester(MockDeployer.ApplicationContext ... appContexts) { + provisioningTester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east3"))) + .flavorsConfig(flavorsConfig()) + .build(); + provisioningTester.clock().setInstant(Instant.ofEpochMilli(0)); + Map<ApplicationId, MockDeployer.ApplicationContext> apps = Arrays.stream(appContexts) + .collect(Collectors.toMap(c -> c.id(), c -> c)); + deployer = new MockDeployer(provisioningTester.provisioner(), provisioningTester.clock(), apps); + nodeMetricsDb = new NodeMetricsDb(provisioningTester.nodeRepository()); + maintainer = new AutoscalingMaintainer(provisioningTester.nodeRepository(), + nodeMetricsDb, + deployer, + new TestMetric(), + Duration.ofMinutes(1)); + provisioningTester.makeReadyNodes(20, "flt", NodeType.host, 8); + provisioningTester.activateTenantHosts(); + } + + public NodeRepository nodeRepository() { return provisioningTester.nodeRepository(); } + public ManualClock clock() { return provisioningTester.clock(); } + public MockDeployer deployer() { return deployer; } + public AutoscalingMaintainer maintainer() { return maintainer; } + public NodeMetricsDb nodeMetricsDb() { return nodeMetricsDb; } + + public static ApplicationId makeApplicationId(String name) { return ProvisioningTester.makeApplicationId(name); } + public static ClusterSpec containerClusterSpec() { return ProvisioningTester.containerClusterSpec(); } + + public List<Node> deploy(ApplicationId application, ClusterSpec cluster, Capacity capacity) { + return provisioningTester.deploy(application, cluster, capacity); + } + + public void addMeasurements(Metric metric, float value, int count, ApplicationId applicationId) { + List<Node> nodes = nodeRepository().getNodes(applicationId, Node.State.active); + for (int i = 0; i < count; i++) { + for (Node node : nodes) + nodeMetricsDb.add(List.of(new NodeMetrics.MetricValue(node.hostname(), + metric.fullName(), + clock().instant().getEpochSecond(), + value * 100))); // the metrics are in % + } + } + + private FlavorsConfig flavorsConfig() { + FlavorConfigBuilder b = new FlavorConfigBuilder(); + b.addFlavor("flt", 30, 30, 40, 3, Flavor.Type.BARE_METAL); + b.addFlavor("cpu", 40, 20, 40, 3, Flavor.Type.BARE_METAL); + b.addFlavor("mem", 20, 40, 40, 3, Flavor.Type.BARE_METAL); + return b.build(); + } + +} diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainerTest.java index 9978f37e835..7cc81f218ec 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainerTest.java @@ -182,7 +182,7 @@ public class DynamicProvisioningMaintainerTest { tester.provisioningTester.activateTenantHosts(); // Allocating nodes to a host does not result in provisioning of additional capacity - ApplicationId application = tester.provisioningTester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); tester.provisioningTester.deploy(application, Capacity.from(new ClusterResources(2, 1, new NodeResources(4, 8, 50, 0.1)))); assertEquals(2, tester.nodeRepository.list().owner(application).size()); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirerTest.java index 6c22f798fe0..4185ff2c25c 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirerTest.java @@ -45,8 +45,8 @@ public class LoadBalancerExpirerTest { // Deploy two applications with a total of three load balancers ClusterSpec.Id cluster1 = ClusterSpec.Id.from("qrs"); ClusterSpec.Id cluster2 = ClusterSpec.Id.from("qrs2"); - ApplicationId app1 = tester.makeApplicationId(); - ApplicationId app2 = tester.makeApplicationId(); + ApplicationId app1 = ProvisioningTester.makeApplicationId(); + ApplicationId app2 = ProvisioningTester.makeApplicationId(); LoadBalancerId lb1 = new LoadBalancerId(app1, cluster1); LoadBalancerId lb2 = new LoadBalancerId(app2, cluster1); LoadBalancerId lb3 = new LoadBalancerId(app2, cluster2); @@ -111,7 +111,7 @@ public class LoadBalancerExpirerTest { // Prepare application ClusterSpec.Id cluster = ClusterSpec.Id.from("qrs"); - ApplicationId app = tester.makeApplicationId(); + ApplicationId app = ProvisioningTester.makeApplicationId(); LoadBalancerId lb = new LoadBalancerId(app, cluster); deployApplication(app, false, cluster); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java index bd2afb5d1c8..05b2d1e9ec9 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java @@ -14,6 +14,7 @@ import com.yahoo.config.provision.Zone; import com.yahoo.config.provisioning.FlavorsConfig; import com.yahoo.vespa.hosted.provision.Node; import com.yahoo.vespa.hosted.provision.NodeRepository; +import com.yahoo.vespa.hosted.provision.autoscale.Metric; import com.yahoo.vespa.hosted.provision.autoscale.NodeMetrics; import com.yahoo.vespa.hosted.provision.autoscale.NodeMetricsDb; import com.yahoo.vespa.hosted.provision.autoscale.Resource; @@ -38,11 +39,11 @@ public class ScalingSuggestionsMaintainerTest { public void testScalingSuggestionsMaintainer() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east3"))).flavorsConfig(flavorsConfig()).build(); - ApplicationId app1 = tester.makeApplicationId("app1"); - ClusterSpec cluster1 = tester.containerClusterSpec(); + ApplicationId app1 = ProvisioningTester.makeApplicationId("app1"); + ClusterSpec cluster1 = ProvisioningTester.containerClusterSpec(); - ApplicationId app2 = tester.makeApplicationId("app2"); - ClusterSpec cluster2 = tester.contentClusterSpec(); + ApplicationId app2 = ProvisioningTester.makeApplicationId("app2"); + ClusterSpec cluster2 = ProvisioningTester.contentClusterSpec(); NodeMetricsDb nodeMetricsDb = new NodeMetricsDb(tester.nodeRepository()); @@ -81,7 +82,7 @@ public class ScalingSuggestionsMaintainerTest { for (int i = 0; i < count; i++) { for (Node node : nodes) db.add(List.of(new NodeMetrics.MetricValue(node.hostname(), - resource.metricName(), + Metric.from(resource).fullName(), nodeRepository.clock().instant().toEpochMilli(), value * 100))); // the metrics are in % } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java index 505e53c9195..62c6c0c9426 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java @@ -38,14 +38,14 @@ public class AclProvisioningTest { // Populate repo tester.makeReadyNodes(10, new NodeResources(1, 4, 10, 1)); List<Node> dockerHost = tester.makeReadyNodes(1, new NodeResources(1, 4, 10, 1), NodeType.host); - ApplicationId zoneApplication = tester.makeApplicationId(); + ApplicationId zoneApplication = ProvisioningTester.makeApplicationId(); tester.deploy(zoneApplication, Capacity.fromRequiredNodeType(NodeType.host)); tester.makeReadyVirtualDockerNodes(1,new NodeResources(1, 4, 10, 1), dockerHost.get(0).hostname()); List<Node> proxyNodes = tester.makeReadyNodes(3, new NodeResources(1, 4, 10, 1), NodeType.proxy); // Allocate 2 nodes - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); List<Node> activeNodes = tester.deploy(application, Capacity.from(new ClusterResources(2, 1, new NodeResources(1, 4, 10, 1)), false, true)); assertEquals(2, activeNodes.size()); @@ -110,7 +110,7 @@ public class AclProvisioningTest { tester.makeReadyNodes(3, "default", NodeType.proxy); // Deploy zone application - ApplicationId zoneApplication = tester.makeApplicationId(); + ApplicationId zoneApplication = ProvisioningTester.makeApplicationId(); tester.deploy(zoneApplication, Capacity.fromRequiredNodeType(NodeType.proxy)); // Get trusted nodes for first proxy node @@ -152,7 +152,7 @@ public class AclProvisioningTest { tester.makeReadyNodes(3, "default", NodeType.controller); // Allocate - ApplicationId controllerApplication = tester.makeApplicationId(); + ApplicationId controllerApplication = ProvisioningTester.makeApplicationId(); List<Node> controllers = tester.deploy(controllerApplication, Capacity.fromRequiredNodeType(NodeType.controller)); // Controllers and hosts all trust each other @@ -172,7 +172,7 @@ public class AclProvisioningTest { } // Deploy application - var application = tester.makeApplicationId(); + var application = ProvisioningTester.makeApplicationId(); List<Node> activeNodes = deploy(application, 2); assertEquals(2, activeNodes.size()); @@ -207,7 +207,7 @@ public class AclProvisioningTest { } private List<Node> deploy(int nodeCount) { - return deploy(tester.makeApplicationId(), nodeCount); + return deploy(ProvisioningTester.makeApplicationId(), nodeCount); } private List<Node> deploy(ApplicationId application, int nodeCount) { diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningCompleteHostCalculatorTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningCompleteHostCalculatorTest.java index 2588818a9d3..d8ff34d1244 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningCompleteHostCalculatorTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningCompleteHostCalculatorTest.java @@ -32,7 +32,7 @@ public class DockerProvisioningCompleteHostCalculatorTest { .build(); tester.makeReadyHosts(9, hostFlavor.resources()).activateTenantHosts(); - ApplicationId app1 = tester.makeApplicationId("app1"); + ApplicationId app1 = ProvisioningTester.makeApplicationId("app1"); ClusterSpec cluster1 = ClusterSpec.request(ClusterSpec.Type.content, new ClusterSpec.Id("cluster1")).vespaVersion("7").build(); var initialResources = new NodeResources(2, 16, 50, 1); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java index 6ae78f9019c..d2a5e06469a 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java @@ -46,7 +46,7 @@ public class DockerProvisioningTest { @Test public void docker_application_deployment() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - ApplicationId application1 = tester.makeApplicationId(); + ApplicationId application1 = ProvisioningTester.makeApplicationId(); for (int i = 1; i < 10; i++) tester.makeReadyVirtualDockerNodes(1, dockerResources, "dockerHost" + i); @@ -78,12 +78,12 @@ public class DockerProvisioningTest { public void refuses_to_activate_on_non_active_host() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - ApplicationId zoneApplication = tester.makeApplicationId(); + ApplicationId zoneApplication = ProvisioningTester.makeApplicationId(); List<Node> parents = tester.makeReadyNodes(10, new NodeResources(2, 4, 20, 2), NodeType.host, 1); for (Node parent : parents) tester.makeReadyVirtualDockerNodes(1, dockerResources, parent.hostname()); - ApplicationId application1 = tester.makeApplicationId(); + ApplicationId application1 = ProvisioningTester.makeApplicationId(); Version wantedVespaVersion = Version.fromString("6.39"); int nodeCount = 7; List<HostSpec> nodes = tester.prepare(application1, @@ -162,11 +162,11 @@ public class DockerProvisioningTest { for (int i = 13; i <= 16; i++) tester.makeReadyVirtualDockerNode(i, dockerResources, "host4"); - ApplicationId application1 = tester.makeApplicationId(); + ApplicationId application1 = ProvisioningTester.makeApplicationId(); prepareAndActivate(application1, 2, true, tester); assertEquals(Set.of("host1", "host2"), hostsOf(tester.getNodes(application1, Node.State.active))); - ApplicationId application2 = tester.makeApplicationId(); + ApplicationId application2 = ProvisioningTester.makeApplicationId(); prepareAndActivate(application2, 2, false, tester); assertEquals("Application is assigned to separate hosts", Set.of("host3", "host4"), hostsOf(tester.getNodes(application2, Node.State.active))); @@ -185,11 +185,11 @@ public class DockerProvisioningTest { for (int i = 13; i <= 16; i++) tester.makeReadyVirtualDockerNode(i, dockerResources, "host4"); - ApplicationId application1 = tester.makeApplicationId(); + ApplicationId application1 = ProvisioningTester.makeApplicationId(); prepareAndActivate(application1, 2, false, tester); assertEquals(Set.of("host1", "host2"), hostsOf(tester.getNodes(application1, Node.State.active))); - ApplicationId application2 = tester.makeApplicationId(); + ApplicationId application2 = ProvisioningTester.makeApplicationId(); prepareAndActivate(application2, 2, true, tester); assertEquals("Application is assigned to separate hosts", Set.of("host3", "host4"), hostsOf(tester.getNodes(application2, Node.State.active))); @@ -208,7 +208,7 @@ public class DockerProvisioningTest { for (int i = 13; i <= 16; i++) tester.makeReadyVirtualDockerNode(i, dockerResources, "host4"); - ApplicationId application1 = tester.makeApplicationId(); + ApplicationId application1 = ProvisioningTester.makeApplicationId(); prepareAndActivate(application1, 2, false, tester); for (Node node : tester.getNodes(application1, Node.State.active)) assertFalse(node.allocation().get().membership().cluster().isExclusive()); @@ -237,7 +237,7 @@ public class DockerProvisioningTest { for (int i = 13; i <= 16; i++) tester.makeReadyVirtualDockerNode(i, dockerResources, "host4"); - ApplicationId application1 = tester.makeApplicationId(); + ApplicationId application1 = ProvisioningTester.makeApplicationId(); prepareAndActivate(application1, 2, true, tester); assertEquals(Set.of("host1", "host2"), hostsOf(tester.getNodes(application1, Node.State.active))); @@ -266,7 +266,7 @@ public class DockerProvisioningTest { @Test public void get_specified_flavor_not_default_flavor_for_docker() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.test, RegionName.from("corp-us-east-1"))).build(); - ApplicationId application1 = tester.makeApplicationId(); + ApplicationId application1 = ProvisioningTester.makeApplicationId(); tester.makeReadyVirtualDockerNodes(1, dockerResources, "dockerHost"); List<HostSpec> hosts = tester.prepare(application1, @@ -284,7 +284,7 @@ public class DockerProvisioningTest { try { ProvisioningTester tester = new ProvisioningTester.Builder() .zone(new Zone(Environment.prod, RegionName.from("us-east-1"))).build(); - ApplicationId application1 = tester.makeApplicationId("app1"); + ApplicationId application1 = ProvisioningTester.makeApplicationId("app1"); tester.makeReadyVirtualDockerNodes(1, dockerResources, "dockerHost1"); tester.makeReadyVirtualDockerNodes(1, dockerResources, "dockerHost2"); @@ -311,7 +311,7 @@ public class DockerProvisioningTest { .build(); tester.makeReadyHosts(2, hostFlavor.resources()).activateTenantHosts(); - ApplicationId app1 = tester.makeApplicationId("app1"); + ApplicationId app1 = ProvisioningTester.makeApplicationId("app1"); ClusterSpec cluster1 = ClusterSpec.request(ClusterSpec.Type.content, new ClusterSpec.Id("cluster1")).vespaVersion("7").build(); var resources = new NodeResources(1, 8, 10, 1); @@ -331,7 +331,7 @@ public class DockerProvisioningTest { .build(); tester.makeReadyHosts(9, hostFlavor.resources()).activateTenantHosts(); - ApplicationId app1 = tester.makeApplicationId("app1"); + ApplicationId app1 = ProvisioningTester.makeApplicationId("app1"); ClusterSpec cluster1 = ClusterSpec.request(ClusterSpec.Type.content, new ClusterSpec.Id("cluster1")).vespaVersion("7").build(); var initialResources = new NodeResources(2, 16, 50, 1); @@ -366,7 +366,7 @@ public class DockerProvisioningTest { .build(); tester.makeReadyHosts(2, hostFlavor.resources()).activateTenantHosts(); - ApplicationId app1 = tester.makeApplicationId("app1"); + ApplicationId app1 = ProvisioningTester.makeApplicationId("app1"); ClusterSpec cluster1 = ClusterSpec.request(ClusterSpec.Type.content, new ClusterSpec.Id("cluster1")).vespaVersion("7").build(); // 5 Gb requested memory becomes 5-3=2 Gb real memory, which is an illegally small amount @@ -388,7 +388,7 @@ public class DockerProvisioningTest { .build(); tester.makeReadyHosts(5, r).activateTenantHosts(); - ApplicationId app1 = tester.makeApplicationId("app1"); + ApplicationId app1 = ProvisioningTester.makeApplicationId("app1"); ClusterSpec cluster1 = ClusterSpec.request(ClusterSpec.Type.container, new ClusterSpec.Id("cluster1")).vespaVersion("7").build(); tester.activate(app1, cluster1, Capacity.from(new ClusterResources(5, 1, r))); @@ -421,7 +421,7 @@ public class DockerProvisioningTest { .build(); tester.makeReadyHosts(4, r).activateTenantHosts(); - ApplicationId app1 = tester.makeApplicationId("app1"); + ApplicationId app1 = ProvisioningTester.makeApplicationId("app1"); ClusterSpec cluster1 = ClusterSpec.request(clusterType, new ClusterSpec.Id("cluster1")).vespaVersion("7").build(); tester.activate(app1, cluster1, Capacity.from(new ClusterResources(4, 1, r))); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerAllocationTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerAllocationTest.java index 7e416bfc397..89072223341 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerAllocationTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerAllocationTest.java @@ -231,7 +231,7 @@ public class DynamicDockerAllocationTest { tester.activateTenantHosts(); //Deploy an application having 6 nodes (3 nodes in 2 groups). We only have 5 docker hosts available - ApplicationId application1 = tester.makeApplicationId(); + ApplicationId application1 = ProvisioningTester.makeApplicationId(); tester.prepare(application1, clusterSpec("myContent.t1.a1"), 6, 2, new NodeResources(1, 4, 100, 1)); fail("Two groups have been allocated to the same parent host"); @@ -247,7 +247,7 @@ public class DynamicDockerAllocationTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).flavorsConfig(flavorsConfig()).build(); // Setup test - ApplicationId application1 = tester.makeApplicationId(); + ApplicationId application1 = ProvisioningTester.makeApplicationId(); tester.makeReadyNodes(5, "host-small", NodeType.host, 32); tester.activateTenantHosts(); NodeResources flavor = new NodeResources(1, 4, 100, 1); @@ -279,7 +279,7 @@ public class DynamicDockerAllocationTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.perf, RegionName.from("us-east"))).flavorsConfig(flavorsConfig()).build(); tester.makeReadyNodes(3, "host-small", NodeType.host, 32); tester.activateTenantHosts(); - ApplicationId application1 = tester.makeApplicationId(); + ApplicationId application1 = ProvisioningTester.makeApplicationId(); List<HostSpec> hosts = tester.prepare(application1, clusterSpec("myContent.t1.a1"), 3, 1, new NodeResources(1, 4, 100, 1)); tester.activate(application1, ImmutableSet.copyOf(hosts)); @@ -292,7 +292,7 @@ public class DynamicDockerAllocationTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(SystemName.cd, Environment.test, RegionName.from("us-east"))).flavorsConfig(flavorsConfig()).build(); tester.makeReadyNodes(4, new Flavor(new NodeResources(1, 8, 120, 1, NodeResources.DiskSpeed.slow)), NodeType.host, 10, true); tester.activateTenantHosts(); - ApplicationId application1 = tester.makeApplicationId(); + ApplicationId application1 = ProvisioningTester.makeApplicationId(); List<HostSpec> hosts = tester.prepare(application1, clusterSpec("myContent.t1.a1"), 3, 1, new NodeResources(1, 4, 100, 1)); tester.activate(application1, ImmutableSet.copyOf(hosts)); } @@ -303,7 +303,7 @@ public class DynamicDockerAllocationTest { tester.makeProvisionedNodes(3, "host-small", NodeType.host, 32).forEach(node -> tester.nodeRepository().fail(node.hostname(), Agent.system, getClass().getSimpleName())); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); tester.prepare(application, clusterSpec("myContent.t2.a2"), 2, 1, new NodeResources(1, 40, 100, 1)); } @@ -313,7 +313,7 @@ public class DynamicDockerAllocationTest { tester.makeReadyNodes(2, "host-large", NodeType.host, 10, true); tester.activateTenantHosts(); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); List<HostSpec> hosts = tester.prepare(application, clusterSpec("myContent.t1.a1"), 2, 1, new NodeResources(1, 4, 100, 1)); tester.activate(application, hosts); @@ -344,7 +344,7 @@ public class DynamicDockerAllocationTest { tester.makeReadyNodes(2, new Flavor(new NodeResources(1, 8, 120, 1, NodeResources.DiskSpeed.slow)), NodeType.host, 10, true); tester.activateTenantHosts(); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("test")).vespaVersion("1").build(); NodeResources resources = new NodeResources(1, 4, 100, 1, NodeResources.DiskSpeed.any); @@ -361,7 +361,7 @@ public class DynamicDockerAllocationTest { tester.makeReadyNodes(2, new Flavor(new NodeResources(1, 8, 120, 1, NodeResources.DiskSpeed.slow)), NodeType.host, 10, true); tester.activateTenantHosts(); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("test")).vespaVersion("1").build(); NodeResources resources = new NodeResources(1, 4, 100, 1, requestDiskSpeed); @@ -383,7 +383,7 @@ public class DynamicDockerAllocationTest { tester.makeReadyNodes(2, new Flavor(new NodeResources(1, 8, 120, 1, NodeResources.DiskSpeed.slow)), NodeType.host, 10, true); tester.activateTenantHosts(); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("test")).vespaVersion("1").build(); NodeResources resources = new NodeResources(1, 4, 100, 1, NodeResources.DiskSpeed.fast); @@ -401,7 +401,7 @@ public class DynamicDockerAllocationTest { tester.makeReadyNodes(2, new Flavor(new NodeResources(5, 20, 1400, 3)), NodeType.host, 10, true); tester.activateTenantHosts(); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("test")).vespaVersion("1").build(); List<HostSpec> hosts1 = tester.prepare(application, cluster, Capacity.from(new ClusterResources(2, 1, NodeResources.fromLegacyName("d-2-8-500")), false, true)); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerProvisionTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerProvisionTest.java index 57c7c46c2d9..84850358798 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerProvisionTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerProvisionTest.java @@ -63,7 +63,7 @@ public class DynamicDockerProvisionTest { public void dynamically_provision_with_empty_node_repo() { assertEquals(0, tester.nodeRepository().list().size()); - ApplicationId application1 = tester.makeApplicationId(); + ApplicationId application1 = ProvisioningTester.makeApplicationId(); NodeResources flavor = new NodeResources(1, 4, 10, 1); mockHostProvisioner(hostProvisioner, tester.nodeRepository().flavors().getFlavorOrThrow("small")); @@ -83,7 +83,7 @@ public class DynamicDockerProvisionTest { tester.makeReadyNodes(3, "small", NodeType.host, 10); tester.activateTenantHosts(); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); NodeResources flavor = new NodeResources(1, 4, 10, 1); mockHostProvisioner(hostProvisioner, tester.nodeRepository().flavors().getFlavorOrThrow("small")); @@ -93,7 +93,7 @@ public class DynamicDockerProvisionTest { @Test public void allocates_to_hosts_already_hosting_nodes_by_this_tenant() { - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); NodeResources flavor = new NodeResources(1, 4, 10, 1); List<Integer> expectedProvisionIndexes = List.of(100, 101); @@ -126,7 +126,7 @@ public class DynamicDockerProvisionTest { public void node_indices_are_unique_even_when_a_node_is_left_in_reserved_state() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(zone).build(); NodeResources resources = new NodeResources(10, 10, 10, 10); - ApplicationId app = tester.makeApplicationId(); + ApplicationId app = ProvisioningTester.makeApplicationId(); Function<Node, Node> retireNode = node -> tester.patchNode(node, (n) -> n.withWantToRetire(true, Agent.system, Instant.now())); Function<Integer, Node> getNodeInGroup = group -> tester.nodeRepository().getNodes(app).stream() @@ -171,7 +171,7 @@ public class DynamicDockerProvisionTest { tester.activateTenantHosts(); - ApplicationId app1 = tester.makeApplicationId("app1"); + ApplicationId app1 = ProvisioningTester.makeApplicationId("app1"); ClusterSpec cluster1 = ClusterSpec.request(ClusterSpec.Type.content, new ClusterSpec.Id("cluster1")).vespaVersion("7").build(); // Deploy using real memory amount (17) @@ -217,7 +217,7 @@ public class DynamicDockerProvisionTest { tester.activateTenantHosts(); - ApplicationId app1 = tester.makeApplicationId("app1"); + ApplicationId app1 = ProvisioningTester.makeApplicationId("app1"); ClusterSpec cluster1 = ClusterSpec.request(ClusterSpec.Type.content, new ClusterSpec.Id("cluster1")).vespaVersion("7").build(); // Limits where each number is within flavor limits but but which don't contain any flavor leads to an error @@ -292,7 +292,7 @@ public class DynamicDockerProvisionTest { tester.activateTenantHosts(); - ApplicationId app1 = tester.makeApplicationId("app1"); + ApplicationId app1 = ProvisioningTester.makeApplicationId("app1"); ClusterSpec cluster1 = ClusterSpec.request(ClusterSpec.Type.content, new ClusterSpec.Id("cluster1")).vespaVersion("7").build(); tester.activate(app1, cluster1, Capacity.from(resources(4, 2, 2, 10, 200, fast, local), @@ -327,7 +327,7 @@ public class DynamicDockerProvisionTest { tester.activateTenantHosts(); - ApplicationId app1 = tester.makeApplicationId("app1"); + ApplicationId app1 = ProvisioningTester.makeApplicationId("app1"); ClusterSpec cluster1 = ClusterSpec.request(ClusterSpec.Type.content, new ClusterSpec.Id("cluster1")).vespaVersion("7").build(); tester.activate(app1, cluster1, Capacity.from(resources(4, 2, 2, 10, 200, fast, StorageType.any), diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/InPlaceResizeProvisionTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/InPlaceResizeProvisionTest.java index 71c3ec37d65..7a21b4eb7af 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/InPlaceResizeProvisionTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/InPlaceResizeProvisionTest.java @@ -60,8 +60,8 @@ public class InPlaceResizeProvisionTest { private final ProvisioningTester tester = new ProvisioningTester.Builder() .flagSource(flagSource) .zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - private final ApplicationId infraApp = tester.makeApplicationId(); - private final ApplicationId app = tester.makeApplicationId(); + private final ApplicationId infraApp = ProvisioningTester.makeApplicationId(); + private final ApplicationId app = ProvisioningTester.makeApplicationId(); @Test public void single_group_same_cluster_size_resource_increase() { @@ -128,7 +128,7 @@ public class InPlaceResizeProvisionTest { addParentHosts(4, new NodeResources(8, 16, 320, 8, fast, local)); // Allocate 2 nodes for one app that leaves exactly enough capacity for mediumResources left on the host - new PrepareHelper(tester, tester.makeApplicationId()).prepare(container1, 2, 1, mediumResources).activate(); + new PrepareHelper(tester, ProvisioningTester.makeApplicationId()).prepare(container1, 2, 1, mediumResources).activate(); // Allocate 4 nodes for another app. After this, 2 hosts should be completely full new PrepareHelper(tester, app).prepare(container1, 4, 1, mediumResources).activate(); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/MultigroupProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/MultigroupProvisioningTest.java index 09d1600e1d7..aba7ac2a530 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/MultigroupProvisioningTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/MultigroupProvisioningTest.java @@ -42,7 +42,7 @@ public class MultigroupProvisioningTest { public void test_provisioning_of_multiple_groups() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - ApplicationId application1 = tester.makeApplicationId("app1"); + ApplicationId application1 = ProvisioningTester.makeApplicationId("app1"); tester.makeReadyNodes(31, small); @@ -75,7 +75,7 @@ public class MultigroupProvisioningTest { public void test_provisioning_of_groups_with_asymmetry() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - ApplicationId application1 = tester.makeApplicationId(); + ApplicationId application1 = ProvisioningTester.makeApplicationId(); tester.makeReadyNodes(21, large); @@ -88,7 +88,7 @@ public class MultigroupProvisioningTest { public void test_provisioning_of_multiple_groups_after_flavor_migration() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - ApplicationId application1 = tester.makeApplicationId("app1"); + ApplicationId application1 = ProvisioningTester.makeApplicationId("app1"); tester.makeReadyNodes(10, small); tester.makeReadyNodes(16, large); @@ -102,7 +102,7 @@ public class MultigroupProvisioningTest { public void test_one_node_and_group_to_two() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.perf, RegionName.from("us-east"))).build(); - ApplicationId application1 = tester.makeApplicationId(); + ApplicationId application1 = ProvisioningTester.makeApplicationId(); tester.makeReadyNodes(10, small); @@ -114,7 +114,7 @@ public class MultigroupProvisioningTest { public void test_one_node_and_group_to_two_with_resource_change() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.perf, RegionName.from("us-east"))).build(); - ApplicationId application1 = tester.makeApplicationId(); + ApplicationId application1 = ProvisioningTester.makeApplicationId(); tester.makeReadyNodes(10, small); tester.makeReadyNodes(10, large); @@ -136,7 +136,7 @@ public class MultigroupProvisioningTest { .build(); tester.makeReadyHosts(6, hostFlavor.resources()).activateTenantHosts(); - ApplicationId app1 = tester.makeApplicationId("app1"); + ApplicationId app1 = ProvisioningTester.makeApplicationId("app1"); ClusterSpec cluster1 = ClusterSpec.request(ClusterSpec.Type.content, new ClusterSpec.Id("cluster1")).vespaVersion("7").build(); // Deploy with 1 group @@ -162,7 +162,7 @@ public class MultigroupProvisioningTest { .build(); tester.makeReadyHosts(6, hostFlavor.resources()).activateTenantHosts(); - ApplicationId app1 = tester.makeApplicationId("app1"); + ApplicationId app1 = ProvisioningTester.makeApplicationId("app1"); ClusterSpec cluster1 = ClusterSpec.request(ClusterSpec.Type.content, new ClusterSpec.Id("cluster1")).vespaVersion("7").build(); // Deploy with 3 groups @@ -192,7 +192,7 @@ public class MultigroupProvisioningTest { .build(); tester.makeReadyHosts(12, hostFlavor.resources()).activateTenantHosts(); - ApplicationId app1 = tester.makeApplicationId("app1"); + ApplicationId app1 = ProvisioningTester.makeApplicationId("app1"); ClusterSpec cluster1 = ClusterSpec.request(ClusterSpec.Type.content, new ClusterSpec.Id("cluster1")).vespaVersion("7").build(); // Deploy with 3 groups @@ -220,7 +220,7 @@ public class MultigroupProvisioningTest { public void test_provisioning_of_multiple_groups_after_flavor_migration_and_exiration() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - ApplicationId application1 = tester.makeApplicationId("app1"); + ApplicationId application1 = ProvisioningTester.makeApplicationId("app1"); tester.makeReadyNodes(10, small); tester.makeReadyNodes(16, large); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/NodeTypeProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/NodeTypeProvisioningTest.java index 11e7af512c3..d9265153596 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/NodeTypeProvisioningTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/NodeTypeProvisioningTest.java @@ -33,7 +33,7 @@ public class NodeTypeProvisioningTest { private final ProvisioningTester tester = new ProvisioningTester.Builder().build(); - private final ApplicationId application = tester.makeApplicationId(); // application using proxy nodes + private final ApplicationId application = ProvisioningTester.makeApplicationId(); // application using proxy nodes private final Capacity capacity = Capacity.fromRequiredNodeType(NodeType.proxy); private final ClusterSpec clusterSpec = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("test")).vespaVersion("6.42").build(); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java index 6cf5a2c8342..1c03bbc6a56 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java @@ -59,8 +59,8 @@ public class ProvisioningTest { public void application_deployment_constant_application_size() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - ApplicationId application1 = tester.makeApplicationId(); - ApplicationId application2 = tester.makeApplicationId(); + ApplicationId application1 = ProvisioningTester.makeApplicationId(); + ApplicationId application2 = ProvisioningTester.makeApplicationId(); tester.makeReadyHosts(21, defaultResources).activateTenantHosts(); @@ -141,10 +141,10 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.dev, RegionName.from("us-east"))).build(); tester.makeReadyHosts(4, defaultResources); - tester.prepareAndActivateInfraApplication(tester.makeApplicationId(), NodeType.host); + tester.prepareAndActivateInfraApplication(ProvisioningTester.makeApplicationId(), NodeType.host); // deploy - ApplicationId application1 = tester.makeApplicationId(); + ApplicationId application1 = ProvisioningTester.makeApplicationId(); SystemState state1 = prepare(application1, 1, 1, 1, 1, defaultResources, tester); tester.activate(application1, state1.allHosts); @@ -166,10 +166,10 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.dev, RegionName.from("us-east"))).build(); tester.makeReadyHosts(4, defaultResources); - tester.prepareAndActivateInfraApplication(tester.makeApplicationId(), NodeType.host); + tester.prepareAndActivateInfraApplication(ProvisioningTester.makeApplicationId(), NodeType.host); // deploy - ApplicationId application1 = tester.makeApplicationId(); + ApplicationId application1 = ProvisioningTester.makeApplicationId(); SystemState state1 = prepare(application1, tester, 1, 1, 1, 1, defaultResources, "1.2.3"); String dockerImageRepo = "docker.domain.tld/my/image"; prepare(application1, tester, 1, 1, 1 , 1 , false, defaultResources, "1.2.3", Optional.of(dockerImageRepo)); @@ -193,7 +193,7 @@ public class ProvisioningTest { public void application_deployment_variable_application_size() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - ApplicationId application1 = tester.makeApplicationId(); + ApplicationId application1 = ProvisioningTester.makeApplicationId(); tester.makeReadyHosts(24, defaultResources); tester.activateTenantHosts(); @@ -264,7 +264,7 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - ApplicationId application1 = tester.makeApplicationId(); + ApplicationId application1 = ProvisioningTester.makeApplicationId(); tester.makeReadyHosts(12, small); tester.activateTenantHosts(); @@ -299,7 +299,7 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - ApplicationId application1 = tester.makeApplicationId(); + ApplicationId application1 = ProvisioningTester.makeApplicationId(); tester.makeReadyHosts(12, small); tester.makeReadyHosts(12, large); @@ -317,7 +317,7 @@ public class ProvisioningTest { public void application_deployment_above_then_at_capacity_limit() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - ApplicationId application1 = tester.makeApplicationId(); + ApplicationId application1 = ProvisioningTester.makeApplicationId(); tester.makeReadyHosts(5, defaultResources).activateTenantHosts(); @@ -343,9 +343,9 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.dev, RegionName.from("us-east"))).build(); tester.makeReadyHosts(4, defaultResources); - tester.prepareAndActivateInfraApplication(tester.makeApplicationId(), NodeType.host); + tester.prepareAndActivateInfraApplication(ProvisioningTester.makeApplicationId(), NodeType.host); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); SystemState state = prepare(application, 2, 2, 3, 3, defaultResources, tester); assertEquals(4, state.allHosts.size()); tester.activate(application, state.allHosts); @@ -356,8 +356,8 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); tester.makeReadyHosts(13, defaultResources).activateTenantHosts(); - tester.prepareAndActivateInfraApplication(tester.makeApplicationId(), NodeType.host); - ApplicationId application = tester.makeApplicationId(); + tester.prepareAndActivateInfraApplication(ProvisioningTester.makeApplicationId(), NodeType.host); + ApplicationId application = ProvisioningTester.makeApplicationId(); { // Deploy with disk-speed any and make sure that information is retained @@ -399,9 +399,9 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.dev, RegionName.from("us-east"))).build(); tester.makeReadyHosts(4, defaultResources).activateTenantHosts(); - tester.prepareAndActivateInfraApplication(tester.makeApplicationId(), NodeType.host); + tester.prepareAndActivateInfraApplication(ProvisioningTester.makeApplicationId(), NodeType.host); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); SystemState state = prepare(application, tester, 2, 2, 3, 3, defaultResources, "6.91"); assertEquals(4, state.allHosts.size()); tester.activate(application, state.allHosts); @@ -412,9 +412,9 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.dev, RegionName.from("us-east"))).build(); tester.makeReadyHosts(4, defaultResources).activateTenantHosts(); - tester.prepareAndActivateInfraApplication(tester.makeApplicationId(), NodeType.host); + tester.prepareAndActivateInfraApplication(ProvisioningTester.makeApplicationId(), NodeType.host); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); String dockerImageRepo = "docker.domain.tld/my/image"; SystemState state = prepare(application, tester, 2, 2, 3, 3, false, defaultResources, "6.91", Optional.of(dockerImageRepo)); assertEquals(4, state.allHosts.size()); @@ -425,8 +425,9 @@ public class ProvisioningTest { public void test_deployment_size() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.test, RegionName.from("us-east"))).build(); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); tester.makeReadyHosts(4, defaultResources).activateTenantHosts(); + SystemState state = prepare(application, 2, 2, 3, 3, defaultResources, tester); assertEquals(4, state.allHosts.size()); tester.activate(application, state.allHosts); @@ -440,7 +441,7 @@ public class ProvisioningTest { .build(); tester.makeReadyHosts(4, hostFlavor.resources()).activateTenantHosts(); - ApplicationId app1 = tester.makeApplicationId("app1"); + ApplicationId app1 = ProvisioningTester.makeApplicationId("app1"); ClusterSpec cluster1 = ClusterSpec.request(ClusterSpec.Type.content, new ClusterSpec.Id("cluster1")).vespaVersion("7").build(); tester.activate(app1, cluster1, Capacity.from(new ClusterResources(2, 1, NodeResources.unspecified()), @@ -458,7 +459,7 @@ public class ProvisioningTest { .build(); tester.makeReadyHosts(31, hostFlavor.resources()).activateTenantHosts(); - ApplicationId app1 = tester.makeApplicationId("app1"); + ApplicationId app1 = ProvisioningTester.makeApplicationId("app1"); ClusterSpec cluster1 = ClusterSpec.request(ClusterSpec.Type.content, new ClusterSpec.Id("cluster1")).vespaVersion("7").build(); // Initial deployment @@ -515,7 +516,7 @@ public class ProvisioningTest { public void prod_deployment_requires_redundancy() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); tester.makeReadyHosts(10, defaultResources).activateTenantHosts(); prepare(application, 1, 2, 3, 3, defaultResources, tester); } @@ -524,7 +525,7 @@ public class ProvisioningTest { public void below_memory_resource_limit() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); tester.makeReadyHosts(10, defaultResources).activateTenantHosts(); try { prepare(application, 2, 2, 3, 3, @@ -539,7 +540,7 @@ public class ProvisioningTest { public void below_vcpu_resource_limit() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); tester.makeReadyHosts(10, defaultResources).activateTenantHosts(); try { prepare(application, 2, 2, 3, 3, @@ -556,9 +557,9 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.dev, RegionName.from("us-east"))).build(); tester.makeReadyHosts(4, new NodeResources(2, 4, 10, 2)); - tester.prepareAndActivateInfraApplication(tester.makeApplicationId(), NodeType.host); + tester.prepareAndActivateInfraApplication(ProvisioningTester.makeApplicationId(), NodeType.host); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); SystemState state = prepare(application, 2, 2, 3, 3, new NodeResources(2, 4, 10, 2), tester); assertEquals(4, state.allHosts.size()); @@ -572,7 +573,7 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.test, RegionName.from("us-east"))).build(); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); tester.makeReadyHosts(4, large).activateTenantHosts(); SystemState state = prepare(application, 2, 2, 3, 3, large, tester); assertEquals(4, state.allHosts.size()); @@ -583,7 +584,7 @@ public class ProvisioningTest { public void staging_deployment_size() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.staging, RegionName.from("us-east"))).build(); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); tester.makeReadyHosts(14, defaultResources).activateTenantHosts(); SystemState state = prepare(application, 1, 1, 1, 64, defaultResources, tester); // becomes 1, 1, 1, 1, 6 assertEquals(9, state.allHosts.size()); @@ -595,7 +596,7 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); tester.makeReadyHosts(10, defaultResources).activateTenantHosts(); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); SystemState state = prepare(application, 2, 2, 3, 3, defaultResources, tester); // Simulate expiry @@ -617,7 +618,7 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); tester.makeReadyHosts(9, defaultResources).activateTenantHosts(); // need 2+2+3+3=10 - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); try { prepare(application, 2, 2, 3, 3, defaultResources, tester); fail("Expected exception"); @@ -634,7 +635,7 @@ public class ProvisioningTest { RegionName.from("us-east"))).build(); tester.makeReadyHosts(13, defaultResources).activateTenantHosts(); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); try { prepare(application, 2, 2, 6, 3, defaultResources, tester); fail("Expected exception"); @@ -652,7 +653,7 @@ public class ProvisioningTest { RegionName.from("us-east"))).build(); tester.makeReadyHosts(13, defaultResources).activateTenantHosts(); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); prepare(application, 2, 2, 6, 3, defaultResources, tester); } @@ -660,7 +661,7 @@ public class ProvisioningTest { public void out_of_capacity_but_cannot_fail() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); tester.makeReadyHosts(4, defaultResources).activateTenantHosts(); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("music")).vespaVersion("4.5.6").build(); tester.prepare(application, cluster, Capacity.from(new ClusterResources(5, 1, NodeResources.unspecified()), false, false)); // No exception; Success @@ -670,7 +671,7 @@ public class ProvisioningTest { public void out_of_capacity_all_nodes_want_to_retire() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); // Flag all nodes for retirement List<Node> readyNodes = tester.makeReadyNodes(5, defaultResources); tester.patchNodes(readyNodes, (node) -> node.withWantToRetire(true, Agent.system, tester.clock().instant())); @@ -690,7 +691,7 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); // Create 10 nodes tester.makeReadyHosts(10, defaultResources).activateTenantHosts(); @@ -722,7 +723,7 @@ public class ProvisioningTest { public void highest_node_indexes_are_retired_first() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - ApplicationId application1 = tester.makeApplicationId(); + ApplicationId application1 = ProvisioningTester.makeApplicationId(); tester.makeReadyHosts(14, defaultResources).activateTenantHosts(); @@ -753,7 +754,7 @@ public class ProvisioningTest { .spareCount(1).build(); tester.makeReadyHosts(7, defaultResources).activateTenantHosts(); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); ClusterSpec spec = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("content1")).vespaVersion("7.1.2").build(); tester.deploy(application, spec, Capacity.from(new ClusterResources(6, 1, defaultResources))); @@ -773,7 +774,7 @@ public class ProvisioningTest { public void application_deployment_retires_nodes_that_want_to_retire() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); tester.makeReadyHosts(10, defaultResources).activateTenantHosts(); // Deploy application @@ -801,7 +802,7 @@ public class ProvisioningTest { public void application_deployment_extends_existing_reservations_on_deploy() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); tester.makeReadyHosts(2, defaultResources).activateTenantHosts(); // Deploy fails with out of capacity @@ -841,7 +842,7 @@ public class ProvisioningTest { @Test public void required_capacity_respects_prod_redundancy_requirement() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); try { prepare(application, tester, 1, 0, 1, 0, true, defaultResources, "6.42", Optional.empty()); fail("Expected exception"); @@ -853,9 +854,9 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(SystemName.dev, Environment.dev, RegionName.from("no-central"))).build(); tester.makeReadyNodes(4, defaultResources, NodeType.devhost, 1); - tester.prepareAndActivateInfraApplication(tester.makeApplicationId(), NodeType.devhost); + tester.prepareAndActivateInfraApplication(ProvisioningTester.makeApplicationId(), NodeType.devhost); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); SystemState state = prepare(application, 2, 2, 3, 3, defaultResources, tester); assertEquals(4, state.allHosts.size()); tester.activate(application, state.allHosts); @@ -864,7 +865,7 @@ public class ProvisioningTest { @Test public void cluster_spec_update_for_already_reserved_nodes() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.dev, RegionName.from("us-east"))).build(); - ApplicationId application = tester.makeApplicationId(); + ApplicationId application = ProvisioningTester.makeApplicationId(); String version1 = "6.42"; String version2 = "6.43"; tester.makeReadyNodes(2, defaultResources); @@ -881,7 +882,7 @@ public class ProvisioningTest { @Test public void change_to_and_from_combined_cluster_does_not_change_node_allocation() { var tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - var application = tester.makeApplicationId(); + var application = ProvisioningTester.makeApplicationId(); tester.makeReadyHosts(4, defaultResources).activateTenantHosts(); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java index 4c8d5caad43..078b1d372df 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java @@ -321,14 +321,14 @@ public class ProvisioningTester { return removed; } - public ApplicationId makeApplicationId() { + public static ApplicationId makeApplicationId() { return ApplicationId.from( TenantName.from(UUID.randomUUID().toString()), ApplicationName.from(UUID.randomUUID().toString()), InstanceName.from(UUID.randomUUID().toString())); } - public ApplicationId makeApplicationId(String applicationName) { + public static ApplicationId makeApplicationId(String applicationName) { return ApplicationId.from("tenant", applicationName, "default"); } @@ -518,11 +518,11 @@ public class ProvisioningTester { activate(applicationId, Set.copyOf(list)); } - public ClusterSpec containerClusterSpec() { + public static ClusterSpec containerClusterSpec() { return ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("test")).vespaVersion("6.42").build(); } - public ClusterSpec contentClusterSpec() { + public static ClusterSpec contentClusterSpec() { return ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("test")).vespaVersion("6.42").build(); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java index 0ef7071b095..b5e31e7cbdb 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java @@ -39,7 +39,7 @@ public class VirtualNodeProvisioningTest { private static final ClusterSpec containerClusterSpec = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("myContainer")).vespaVersion("6.42").build(); private ProvisioningTester tester = new ProvisioningTester.Builder().build(); - private ApplicationId applicationId = tester.makeApplicationId(); + private ApplicationId applicationId = ProvisioningTester.makeApplicationId(); @Test public void distinct_parent_host_for_each_node_in_a_cluster() { @@ -84,7 +84,7 @@ public class VirtualNodeProvisioningTest { NodeResources flavor = new NodeResources(1, 4, 10, 1); tester = new ProvisioningTester.Builder().zone(new Zone(Environment.dev, RegionName.from("us-east"))).build(); tester.makeReadyNodes(4, flavor, NodeType.host, 1); - tester.prepareAndActivateInfraApplication(tester.makeApplicationId(), NodeType.host); + tester.prepareAndActivateInfraApplication(ProvisioningTester.makeApplicationId(), NodeType.host); List<HostSpec> containerHosts = prepare(containerClusterSpec, containerNodeCount, groups, flavor); List<HostSpec> contentHosts = prepare(contentClusterSpec, contentNodeCount, groups, flavor); @@ -98,7 +98,7 @@ public class VirtualNodeProvisioningTest { { tester = new ProvisioningTester.Builder().zone(new Zone(SystemName.cd, Environment.prod, RegionName.from("us-east"))).build(); tester.makeReadyNodes(4, flavor, NodeType.host, 1); - tester.prepareAndActivateInfraApplication(tester.makeApplicationId(), NodeType.host); + tester.prepareAndActivateInfraApplication(ProvisioningTester.makeApplicationId(), NodeType.host); List<HostSpec> containerHosts = prepare(containerClusterSpec, containerNodeCount, groups); List<HostSpec> contentHosts = prepare(contentClusterSpec, contentNodeCount, groups); |