diff options
author | Jon Bratseth <bratseth@gmail.com> | 2023-01-02 16:55:03 +0100 |
---|---|---|
committer | Jon Bratseth <bratseth@gmail.com> | 2023-01-02 16:55:03 +0100 |
commit | 20a6b5041b179a382a90ca37382a0b6ba3f963f7 (patch) | |
tree | 08997145ac9497279caacf295b0b09261cdce1de | |
parent | e5d908c70f1063b05c965e989af1da8c4cb393b1 (diff) |
Output load in target/suggested block
14 files changed, 346 insertions, 200 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Cluster.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Cluster.java index d2b1f6a0803..b7a71cc7b91 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Cluster.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Cluster.java @@ -20,12 +20,9 @@ public class Cluster { private final ClusterResources min; private final ClusterResources max; private final ClusterResources current; - private final Optional<ClusterResources> target; - private final Optional<ClusterResources> suggested; - private final Utilization utilization; + private final Autoscaling target; + private final Autoscaling suggested; private final List<ScalingEvent> scalingEvents; - private final String autoscalingStatusCode; - private final String autoscalingStatus; private final Duration scalingDuration; public Cluster(ClusterSpec.Id id, @@ -33,12 +30,9 @@ public class Cluster { ClusterResources min, ClusterResources max, ClusterResources current, - Optional<ClusterResources> target, - Optional<ClusterResources> suggested, - Utilization utilization, + Autoscaling target, + Autoscaling suggested, List<ScalingEvent> scalingEvents, - String autoscalingStatusCode, - String autoscalingStatus, Duration scalingDuration) { this.id = id; this.type = type; @@ -47,24 +41,26 @@ public class Cluster { this.current = current; this.target = target; this.suggested = suggested; - this.utilization = utilization; this.scalingEvents = scalingEvents; - this.autoscalingStatusCode = autoscalingStatusCode; - this.autoscalingStatus = autoscalingStatus; this.scalingDuration = scalingDuration; } public ClusterSpec.Id id() { return id; } + public ClusterSpec.Type type() { return type; } + public ClusterResources min() { return min; } + public ClusterResources max() { return max; } + public ClusterResources current() { return current; } - public Optional<ClusterResources> target() { return target; } - public Optional<ClusterResources> suggested() { return suggested; } - public Utilization utilization() { return utilization; } + + public Autoscaling target() { return target; } + + public Autoscaling suggested() { return suggested; } + public List<ScalingEvent> scalingEvents() { return scalingEvents; } - public String autoscalingStatusCode() { return autoscalingStatusCode; } - public String autoscalingStatus() { return autoscalingStatus; } + public Duration scalingDuration() { return scalingDuration; } @Override @@ -72,40 +68,6 @@ public class Cluster { return "cluster '" + id + "'"; } - public static class Utilization { - - private final double idealCpu, peakCpu; - private final double idealMemory, peakMemory; - private final double idealDisk, peakDisk; - - public Utilization(double idealCpu, double peakCpu, - double idealMemory, double peakMemory, - double idealDisk, double peakDisk) { - this.idealCpu = idealCpu; - this.peakCpu = peakCpu; - - this.idealMemory = idealMemory; - this.peakMemory = peakMemory; - - this.idealDisk = idealDisk; - this.peakDisk = peakDisk; - } - - public double idealCpu() { return idealCpu; } - public double peakCpu() { return peakCpu; } - - public double idealMemory() { return idealMemory; } - public double peakMemory() { return peakMemory; } - - public double idealDisk() { return idealDisk; } - public double peakDisk() { return peakDisk; } - - public static Utilization empty() { return new Utilization(0, 0, - 0, 0, - 0, 0); } - - } - public static class ScalingEvent { private final ClusterResources from, to; @@ -119,10 +81,13 @@ public class Cluster { this.completion = completion; } - public ClusterResources from() { return from; } - public ClusterResources to() { return to; } - public Instant at() { return at; } - public Optional<Instant> completion() { return completion; } + public ClusterResources from() {return from;} + + public ClusterResources to() {return to;} + + public Instant at() {return at;} + + public Optional<Instant> completion() {return completion;} @Override public boolean equals(Object o) { @@ -140,12 +105,74 @@ public class Cluster { @Override public String toString() { return "ScalingEvent{" + - "from=" + from + - ", to=" + to + - ", at=" + at + - ", completion=" + completion + - '}'; + "from=" + from + + ", to=" + to + + ", at=" + at + + ", completion=" + completion + + '}'; } } + public static class Autoscaling { + + private final String status; + private final String description; + private final Optional<ClusterResources> resources; + private final Instant at; + private final Load peak; + private final Load ideal; + + public Autoscaling(String status, String description, Optional<ClusterResources> resources, Instant at, + Load peak, Load ideal) { + this.status = status; + this.description = description; + this.resources = resources; + this.at = at; + this.peak = peak; + this.ideal = ideal; + } + + public String status() {return status;} + public String description() {return description;} + public Optional<ClusterResources> resources() { + return resources; + } + public Instant at() {return at;} + public Load peak() {return peak;} + public Load ideal() {return ideal;} + + @Override + public boolean equals(Object o) { + if (!(o instanceof Autoscaling other)) return false; + if (!this.status.equals(other.status)) return false; + if (!this.description.equals(other.description)) return false; + if (!this.resources.equals(other.resources)) return false; + if (!this.at.equals(other.at)) return false; + if (!this.peak.equals(other.peak)) return false; + if (!this.ideal.equals(other.ideal)) return false; + return true; + } + + @Override + public int hashCode() { + return Objects.hash(status, description, at, peak, ideal); + } + + @Override + public String toString() { + return (resources.isPresent() ? "Autoscaling to " + resources : "Don't autoscale") + + (description.isEmpty() ? "" : ": " + description); + } + + public static Autoscaling empty() { + return new Autoscaling("unavailable", + "", + Optional.empty(), + Instant.EPOCH, + Load.zero(), + Load.zero()); + } + + } + } diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Load.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Load.java index 548fac7d11b..f954d0c8392 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Load.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Load.java @@ -1,6 +1,8 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.api.integration.configserver; +import java.util.Objects; + /** * @author bratseth */ @@ -20,10 +22,20 @@ public class Load { public double memory() { return memory; } public double disk() { return disk; } + @Override public String toString() { return "load: cpu " + cpu + ", memory " + memory + ", disk " + disk; } + @Override + public int hashCode() { return Objects.hash(cpu, memory, disk); } + + @Override + public boolean equals(Object o) { + if ( ! (o instanceof Load other)) return false; + return cpu == other.cpu && memory == other.memory && disk == other.disk; + } + public static Load zero() { return new Load(0, 0, 0); } } diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/AutoscalingData.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/AutoscalingData.java new file mode 100644 index 00000000000..3541799b0d0 --- /dev/null +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/AutoscalingData.java @@ -0,0 +1,44 @@ +package com.yahoo.vespa.hosted.controller.api.integration.noderepository; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.yahoo.vespa.hosted.controller.api.integration.configserver.Cluster; +import com.yahoo.vespa.hosted.controller.api.integration.configserver.Load; + +import java.time.Duration; +import java.time.Instant; +import java.util.Optional; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class AutoscalingData { + + @JsonProperty("status") + public String status; + + @JsonProperty("description") + public String description; + + @JsonProperty("resources") + public ClusterResourcesData resources; + + @JsonProperty("at") + public Long at; + + @JsonProperty("peak") + public LoadData peak; + + @JsonProperty("ideal") + public LoadData ideal; + + public Cluster.Autoscaling toAutoscaling() { + return new Cluster.Autoscaling(status == null ? "" : status, + description == null ? "" : description, + resources == null ? Optional.empty() : Optional.ofNullable(resources.toClusterResources()), + at == null ? Instant.EPOCH : Instant.ofEpochMilli(at), + peak == null ? Load.zero() : peak.toLoad(), + ideal == null ? Load.zero() : ideal.toLoad()); + } + +} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ClusterData.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ClusterData.java index 574b6149508..539f0545c88 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ClusterData.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ClusterData.java @@ -21,24 +21,25 @@ public class ClusterData { @JsonProperty("type") public String type; + @JsonProperty("min") public ClusterResourcesData min; + @JsonProperty("max") public ClusterResourcesData max; + @JsonProperty("current") public ClusterResourcesData current; + @JsonProperty("suggested") - public ClusterResourcesData suggested; + public AutoscalingData suggested; + @JsonProperty("target") - public ClusterResourcesData target; - @JsonProperty("utilization") - public ClusterUtilizationData utilization; + public AutoscalingData target; + @JsonProperty("scalingEvents") public List<ScalingEventData> scalingEvents; - @JsonProperty("autoscalingStatusCode") - public String autoscalingStatusCode; - @JsonProperty("autoscalingStatus") - public String autoscalingStatus; + @JsonProperty("scalingDuration") public Long scalingDuration; @@ -48,13 +49,10 @@ public class ClusterData { min.toClusterResources(), max.toClusterResources(), current.toClusterResources(), - target == null ? Optional.empty() : Optional.of(target.toClusterResources()), - suggested == null ? Optional.empty() : Optional.of(suggested.toClusterResources()), - utilization == null ? Cluster.Utilization.empty() : utilization.toClusterUtilization(), + target == null ? Cluster.Autoscaling.empty() : target.toAutoscaling(), + suggested == null ? Cluster.Autoscaling.empty() : suggested.toAutoscaling(), scalingEvents == null ? List.of() : scalingEvents.stream().map(data -> data.toScalingEvent()).toList(), - autoscalingStatusCode, - autoscalingStatus, scalingDuration == null ? Duration.ofMillis(0) : Duration.ofMillis(scalingDuration)); } diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ClusterResourcesData.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ClusterResourcesData.java index 801ee4ee853..2a9ab1e3a55 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ClusterResourcesData.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ClusterResourcesData.java @@ -23,6 +23,7 @@ public class ClusterResourcesData { public NodeResources resources; public ClusterResources toClusterResources() { + if (resources == null) return null; // TODO: Compatibility, remove after January 2023 return new ClusterResources(nodes, groups, resources.toNodeResources()); } diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ClusterUtilizationData.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ClusterUtilizationData.java deleted file mode 100644 index b4fee25d1ad..00000000000 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ClusterUtilizationData.java +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.hosted.controller.api.integration.noderepository; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.yahoo.vespa.hosted.controller.api.integration.configserver.Cluster; - -/** - * Utilization ratios - * - * @author bratseth - */ -@JsonIgnoreProperties(ignoreUnknown = true) -@JsonInclude(JsonInclude.Include.NON_NULL) -public class ClusterUtilizationData { - - @JsonProperty("idealCpu") - public Double idealCpu; - @JsonProperty("peakCpu") - public Double peakCpu; - - @JsonProperty("idealMemory") - public Double idealMemory; - @JsonProperty("peakMemory") - public Double peakMemory; - - @JsonProperty("idealDisk") - public Double idealDisk; - @JsonProperty("peakDisk") - public Double peakDisk; - - public Cluster.Utilization toClusterUtilization() { - return new Cluster.Utilization(idealCpu, peakCpu, idealMemory, peakMemory, idealDisk, peakDisk); - } - -} diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java index fcf7aaf0a82..c8597cff405 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java @@ -64,6 +64,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.configserver.Cluster; import com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServerException; import com.yahoo.vespa.hosted.controller.api.integration.configserver.DeploymentResult; import com.yahoo.vespa.hosted.controller.api.integration.configserver.DeploymentResult.LogEntry; +import com.yahoo.vespa.hosted.controller.api.integration.configserver.Load; import com.yahoo.vespa.hosted.controller.api.integration.configserver.LoadBalancer; import com.yahoo.vespa.hosted.controller.api.integration.configserver.Node; import com.yahoo.vespa.hosted.controller.api.integration.configserver.NodeFilter; @@ -74,7 +75,6 @@ import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId; import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId; import com.yahoo.vespa.hosted.controller.api.integration.deployment.SourceRevision; -import com.yahoo.vespa.hosted.controller.api.integration.dns.VpcEndpointService.VpcEndpoint; import com.yahoo.vespa.hosted.controller.api.integration.noderepository.RestartFilter; import com.yahoo.vespa.hosted.controller.api.integration.secrets.TenantSecretStore; import com.yahoo.vespa.hosted.controller.api.role.Role; @@ -1348,14 +1348,12 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler { toSlime(cluster.min(), clusterObject.setObject("min")); toSlime(cluster.max(), clusterObject.setObject("max")); toSlime(cluster.current(), clusterObject.setObject("current")); - if (cluster.target().isPresent() - && ! cluster.target().get().justNumbers().equals(cluster.current().justNumbers())) - toSlime(cluster.target().get(), clusterObject.setObject("target")); - cluster.suggested().ifPresent(suggested -> toSlime(suggested, clusterObject.setObject("suggested"))); - utilizationToSlime(cluster.utilization(), clusterObject.setObject("utilization")); + toSlime(cluster.target(), cluster, clusterObject.setObject("target")); + toSlime(cluster.suggested(), cluster, clusterObject.setObject("suggested")); + legacyUtilizationToSlime(cluster.target().peak(), cluster.target().ideal(), clusterObject.setObject("utilization")); // TODO: Remove after January 2023 scalingEventsToSlime(cluster.scalingEvents(), clusterObject.setArray("scalingEvents")); - clusterObject.setString("autoscalingStatusCode", cluster.autoscalingStatusCode()); - clusterObject.setString("autoscalingStatus", cluster.autoscalingStatus()); + clusterObject.setString("autoscalingStatusCode", cluster.target().status()); // TODO: Remove after January 2023 + clusterObject.setString("autoscalingStatus", cluster.target().description()); // TODO: Remove after January 2023 clusterObject.setLong("scalingDuration", cluster.scalingDuration().toMillis()); } return new SlimeJsonResponse(slime); @@ -2702,15 +2700,35 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler { object.setDouble("cost", cost); } - private void utilizationToSlime(Cluster.Utilization utilization, Cursor utilizationObject) { - utilizationObject.setDouble("idealCpu", utilization.idealCpu()); - utilizationObject.setDouble("peakCpu", utilization.peakCpu()); + private void toSlime(Cluster.Autoscaling autoscaling, Cluster cluster, Cursor autoscalingObject) { + // TODO: Remove after January 2023 + if (autoscaling.resources().isPresent() + && ! autoscaling.resources().get().justNumbers().equals(cluster.current().justNumbers())) + toSlime(autoscaling.resources().get(), autoscalingObject); - utilizationObject.setDouble("idealMemory", utilization.idealMemory()); - utilizationObject.setDouble("peakMemory", utilization.peakMemory()); + autoscalingObject.setString("status", autoscaling.status()); + autoscalingObject.setString("description", autoscaling.description()); + autoscaling.resources().ifPresent(resources -> toSlime(resources, autoscalingObject.setObject("resources"))); + autoscalingObject.setLong("at", autoscaling.at().toEpochMilli()); + toSlime(autoscaling.peak(), autoscalingObject.setObject("peak")); + toSlime(autoscaling.ideal(), autoscalingObject.setObject("ideal")); + } + + private void toSlime(Load load, Cursor loadObject) { + loadObject.setDouble("cpu", load.cpu()); + loadObject.setDouble("memory", load.memory()); + loadObject.setDouble("disk", load.disk()); + } + + private void legacyUtilizationToSlime(Load peak, Load ideal, Cursor utilizationObject) { + utilizationObject.setDouble("idealCpu", ideal.cpu()); + utilizationObject.setDouble("peakCpu", peak.cpu()); + + utilizationObject.setDouble("idealMemory", ideal.memory()); + utilizationObject.setDouble("peakMemory", peak.memory()); - utilizationObject.setDouble("idealDisk", utilization.idealDisk()); - utilizationObject.setDouble("peakDisk", utilization.peakDisk()); + utilizationObject.setDouble("idealDisk", ideal.disk()); + utilizationObject.setDouble("peakDisk", peak.disk()); } private void scalingEventsToSlime(List<Cluster.ScalingEvent> scalingEvents, Cursor scalingEventsArray) { diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/response/application.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/response/application.json index 4cc2ac8c47f..37da498b6ec 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/response/application.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/response/application.json @@ -100,16 +100,31 @@ } }, "suggested": { - "nodes": 2, - "groups": 1, - "resources": { - "vcpu": 2.0, - "memoryGb": 4.0, - "diskGb": 50.0, - "bandwidthGbps": 0.3, - "diskSpeed": "fast", - "storageType": "local", - "architecture": "x86_64" + "status" : "unavailable", + "description" : "", + "resources" : { + "nodes": 2, + "groups": 1, + "resources": { + "vcpu": 2.0, + "memoryGb": 4.0, + "diskGb": 50.0, + "bandwidthGbps": 0.3, + "diskSpeed": "fast", + "storageType": "local", + "architecture": "x86_64" + }, + "at" : 123, + "peak" : { + "cpu" : 0.1, + "memory" : 0.2, + "disk" : 0.3 + }, + "ideal" : { + "cpu" : 0.4, + "memory" : 0.5, + "disk" : 0.6 + } } }, "scalingDuration": 90000 diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java index badf7832ccb..448bb9ac15f 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java @@ -30,6 +30,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.configserver.Cluster; import com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServer; import com.yahoo.vespa.hosted.controller.api.integration.configserver.ContainerEndpoint; import com.yahoo.vespa.hosted.controller.api.integration.configserver.DeploymentResult; +import com.yahoo.vespa.hosted.controller.api.integration.configserver.Load; import com.yahoo.vespa.hosted.controller.api.integration.configserver.LoadBalancer; import com.yahoo.vespa.hosted.controller.api.integration.configserver.LoadBalancer.PrivateServiceInfo; import com.yahoo.vespa.hosted.controller.api.integration.configserver.Node; @@ -43,7 +44,6 @@ import com.yahoo.vespa.hosted.controller.api.integration.noderepository.RestartF import com.yahoo.vespa.hosted.controller.api.integration.secrets.TenantSecretStore; import com.yahoo.vespa.hosted.controller.application.SystemApplication; import com.yahoo.vespa.hosted.controller.application.pkg.ApplicationPackage; -import wiremock.org.checkerframework.checker.units.qual.A; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -116,17 +116,17 @@ public class ConfigServerMock extends AbstractComponent implements ConfigServer new ClusterResources(2, 1, new NodeResources(1, 4, 20, 1, slow, remote)), new ClusterResources(2, 1, new NodeResources(4, 16, 90, 1, slow, remote)), current, - Optional.of(new ClusterResources(2, 1, new NodeResources(3, 8, 50, 1, slow, remote))), - Optional.empty(), - new Cluster.Utilization(0.2, 0.35, - 0.5, 0.65, - 0.8, 1.0), + new Cluster.Autoscaling("ideal", + "Cluster is ideally scaled", + Optional.of(new ClusterResources(2, 1, new NodeResources(3, 8, 50, 1, slow, remote))), + Instant.ofEpochMilli(123), + new Load(0.35, 0.65, 1.0), + new Load(0.2, 0.5, 0.8)), + Cluster.Autoscaling.empty(), List.of(new Cluster.ScalingEvent(new ClusterResources(0, 0, NodeResources.unspecified()), current, Instant.ofEpochMilli(1234), Optional.of(Instant.ofEpochMilli(2234)))), - "ideal", - "Cluster is ideally scaled", Duration.ofMinutes(6)); nodeRepository.putApplication(zone, new com.yahoo.vespa.hosted.controller.api.integration.configserver.Application(application, diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-clusters.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-clusters.json index 238368260eb..c013ccb00fe 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-clusters.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-clusters.json @@ -52,7 +52,48 @@ "diskSpeed": "slow", "storageType": "remote" }, - "cost": 0.29 + "cost": 0.29, + "status": "ideal", + "description": "Cluster is ideally scaled", + "resources": { + "nodes": 2, + "groups": 1, + "nodeResources": { + "vcpu": 3.0, + "memoryGb": 8.0, + "diskGb": 50.0, + "bandwidthGbps": 1.0, + "diskSpeed": "slow", + "storageType": "remote" + }, + "cost": 0.29 + }, + "at" : 123, + "peak": { + "cpu": 0.35, + "memory": 0.65, + "disk": 1.0 + }, + "ideal": { + "cpu": 0.2, + "memory": 0.5, + "disk": 0.8 + } + }, + "suggested": { + "status": "unavailable", + "description": "", + "at": 0, + "peak": { + "cpu": 0.0, + "memory": 0.0, + "disk": 0.0 + }, + "ideal": { + "cpu": 0.0, + "memory": 0.0, + "disk": 0.0 + } }, "utilization": { "idealCpu": 0.2, diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaling.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaling.java index 579f9c2514f..2989d675daa 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaling.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaling.java @@ -30,15 +30,15 @@ public class Autoscaling { this.ideal = ideal; } + public Status status() { return status; } + + public String description() { return description; } + /** Returns the resource target of this, or empty if none (meaning keep the current allocation). */ public Optional<ClusterResources> resources() { return resources; } - public Status status() { return status; } - - public String description() { return description; } - /** Returns the time this was decided. */ public Instant at() { return at; } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java index eac49a705b1..cb927c72eb5 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java @@ -9,6 +9,7 @@ import com.yahoo.vespa.hosted.provision.NodeRepository; import com.yahoo.vespa.hosted.provision.applications.Application; import com.yahoo.vespa.hosted.provision.applications.Cluster; import com.yahoo.vespa.hosted.provision.applications.ScalingEvent; +import com.yahoo.vespa.hosted.provision.autoscale.Autoscaling; import com.yahoo.vespa.hosted.provision.autoscale.Limits; import com.yahoo.vespa.hosted.provision.autoscale.Load; @@ -63,30 +64,31 @@ public class ApplicationSerializer { toSlime(limits.max(), clusterObject.setObject("max")); toSlime(currentResources, clusterObject.setObject("current")); if (cluster.shouldSuggestResources(currentResources)) - cluster.suggested().resources().ifPresent(suggested -> toSlime(suggested, clusterObject.setObject("suggested"))); - cluster.target().resources().ifPresent(target -> toSlime(target, clusterObject.setObject("target"))); - clusterUtilizationToSlime(cluster.target().ideal(), cluster.target().peak(), clusterObject.setObject("utilization")); + toSlime(cluster.suggested(), clusterObject.setObject("suggested")); + toSlime(cluster.target(), clusterObject.setObject("target")); scalingEventsToSlime(cluster.scalingEvents(), clusterObject.setArray("scalingEvents")); - clusterObject.setString("autoscalingStatusCode", cluster.target().status().name()); - clusterObject.setString("autoscalingStatus", cluster.target().description()); clusterObject.setLong("scalingDuration", cluster.scalingDuration(nodes.clusterSpec()).toMillis()); } + private static void toSlime(Autoscaling autoscaling, Cursor autoscalingObject) { + autoscalingObject.setString("status", autoscaling.status().name()); + autoscalingObject.setString("description", autoscaling.description()); + autoscaling.resources().ifPresent(resources -> toSlime(resources, autoscalingObject.setObject("resources"))); + autoscalingObject.setLong("at", autoscaling.at().toEpochMilli()); + toSlime(autoscaling.peak(), autoscalingObject.setObject("peak")); + toSlime(autoscaling.ideal(), autoscalingObject.setObject("ideal")); + } + private static void toSlime(ClusterResources resources, Cursor clusterResourcesObject) { clusterResourcesObject.setLong("nodes", resources.nodes()); clusterResourcesObject.setLong("groups", resources.groups()); NodeResourcesSerializer.toSlime(resources.nodeResources(), clusterResourcesObject.setObject("resources")); } - private static void clusterUtilizationToSlime(Load idealLoad, Load peakLoad, Cursor utilizationObject) { - utilizationObject.setDouble("idealCpu", idealLoad.cpu()); - utilizationObject.setDouble("peakCpu", peakLoad.cpu()); - - utilizationObject.setDouble("idealMemory", idealLoad.memory()); - utilizationObject.setDouble("peakMemory", peakLoad.memory()); - - utilizationObject.setDouble("idealDisk", idealLoad.disk()); - utilizationObject.setDouble("peakDisk", peakLoad.disk()); + private static void toSlime(Load load, Cursor utilizationObject) { + utilizationObject.setDouble("cpu", load.cpu()); + utilizationObject.setDouble("memory", load.memory()); + utilizationObject.setDouble("disk", load.disk()); } private static void scalingEventsToSlime(List<ScalingEvent> scalingEvents, Cursor scalingEventsArray) { diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application1.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application1.json index 18f2422e081..ead4e5fd06a 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application1.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application1.json @@ -44,39 +44,61 @@ } }, "suggested" : { - "nodes" : 6, - "groups" : 2, + "status" : "unavailable", + "description" : "", "resources" : { - "vcpu" : 3.0, - "memoryGb" : 20.0, - "diskGb" : 100.0, - "bandwidthGbps" : 1.0, - "diskSpeed" : "fast", - "storageType" : "any", - "architecture":"x86_64" + "nodes": 6, + "groups": 2, + "resources": { + "vcpu": 3.0, + "memoryGb": 20.0, + "diskGb": 100.0, + "bandwidthGbps": 1.0, + "diskSpeed": "fast", + "storageType": "any", + "architecture": "x86_64" + } + }, + "at" : 123, + "peak" : { + "cpu" : 0.0, + "memory" : 0.0, + "disk" : 0.0 + }, + "ideal" : { + "cpu" : 0.0, + "memory" : 0.0, + "disk" : 0.0 } }, "target" : { - "nodes" : 4, - "groups" : 1, + "status" : "unavailable", + "description" : "", "resources" : { - "vcpu" : 3.0, - "memoryGb" : 16.0, - "diskGb" : 100.0, - "bandwidthGbps" : 1.0, - "diskSpeed" : "fast", - "storageType" : "any", - "architecture":"x86_64" + "nodes" : 4, + "groups" : 1, + "resources" : { + "vcpu": 3.0, + "memoryGb": 16.0, + "diskGb": 100.0, + "bandwidthGbps": 1.0, + "diskSpeed": "fast", + "storageType": "any", + "architecture": "x86_64" + } + }, + "at" : 123, + "peak" : { + "cpu" : 0.0, + "memory" : 0.0, + "disk" : 0.0 + }, + "ideal" : { + "cpu" : 0.0, + "memory" : 0.0, + "disk" : 0.0 } }, - "utilization" : { - "idealCpu": 0.0, - "peakCpu": 0.0, - "idealMemory": 0.0, - "peakMemory": 0.0, - "idealDisk": 0.0, - "peakDisk": 0.0 - }, "scalingEvents" : [ { "from": { @@ -108,8 +130,6 @@ "at" : 123 } ], - "autoscalingStatusCode": "unavailable", - "autoscalingStatus": "", "scalingDuration": 600000 } } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application2.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application2.json index 03b93c897b9..f60fdf3e602 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application2.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application2.json @@ -43,13 +43,20 @@ "architecture":"x86_64" } }, - "utilization" : { - "idealCpu": 0.0, - "peakCpu": 0.0, - "idealMemory": 0.0, - "peakMemory": 0.0, - "idealDisk": 0.0, - "peakDisk": 0.0 + "target" : { + "status" : "unavailable", + "description" : "", + "at" : 0, + "peak" : { + "cpu" : 0.0, + "memory" : 0.0, + "disk" : 0.0 + }, + "ideal" : { + "cpu" : 0.0, + "memory" : 0.0, + "disk" : 0.0 + } }, "scalingEvents" : [ { @@ -82,8 +89,6 @@ "at" : 123 } ], - "autoscalingStatusCode": "unavailable", - "autoscalingStatus" : "", "scalingDuration": 43200000 } } |