aboutsummaryrefslogtreecommitdiffstats
path: root/controller-api
diff options
context:
space:
mode:
authorØyvind Grønnesby <oyving@verizonmedia.com>2021-04-28 12:21:57 +0200
committerØyvind Grønnesby <oyving@verizonmedia.com>2021-04-28 12:21:57 +0200
commitdd2ef6cfc4d3d6e3735d1cb553f7ae2560a7f1ff (patch)
treee1ba3a56439bb3c16022b60d2a7ab3534037827e /controller-api
parenta0db2b1020ea53aa356a7547a23d4e1dfaa851c0 (diff)
parente79af49a3159e5505cd3e5f2605c299d38fe40cd (diff)
Merge remote-tracking branch 'origin/master' into ogronnesby/billing-api-v2
Diffstat (limited to 'controller-api')
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/model/ClusterMetrics.java11
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Cluster.java5
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServer.java4
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServerException.java53
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/LoadBalancer.java6
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Log.java1
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Node.java15
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/NodeRepository.java31
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ProvisionResource.java3
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ScalingEventData.java12
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/ChangeRequest.java2
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/ChangeRequestClient.java3
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/ChangeRequestSource.java9
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/HostAction.java72
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/MockChangeRequestClient.java2
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/VespaChangeRequest.java98
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java1
17 files changed, 261 insertions, 67 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/model/ClusterMetrics.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/model/ClusterMetrics.java
index cc10041992c..cb29d5854a0 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/model/ClusterMetrics.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/model/ClusterMetrics.java
@@ -1,7 +1,6 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller.api.application.v4.model;
-import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
@@ -16,15 +15,16 @@ public class ClusterMetrics {
public static final String DOCUMENT_COUNT = "documentCount";
public static final String FEED_LATENCY = "feedLatency";
public static final String QUERY_LATENCY = "queryLatency";
+ public static final String FEEDING_BLOCKED = "feedingBlocked";
private final String clusterId;
private final String clusterType;
private final Map<String, Double> metrics;
- public ClusterMetrics(String clusterId, String clusterType) {
+ public ClusterMetrics(String clusterId, String clusterType, Map<String, Double> metrics) {
this.clusterId = clusterId;
this.clusterType = clusterType;
- this.metrics = new HashMap<>();
+ this.metrics = Map.copyOf(metrics);
}
public String getClusterId() {
@@ -55,9 +55,8 @@ public class ClusterMetrics {
return Optional.ofNullable(metrics.get(QUERY_LATENCY));
}
- public ClusterMetrics addMetric(String name, double value) {
- metrics.put(name, value);
- return this;
+ public Optional<Double> feedingBlocked() {
+ return Optional.ofNullable(metrics.get(FEEDING_BLOCKED));
}
}
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 d356f5eb89f..07de259be2f 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
@@ -107,16 +107,19 @@ public class Cluster {
private final ClusterResources from, to;
private final Instant at;
+ private final Optional<Instant> completion;
- public ScalingEvent(ClusterResources from, ClusterResources to, Instant at) {
+ public ScalingEvent(ClusterResources from, ClusterResources to, Instant at, Optional<Instant> completion) {
this.from = from;
this.to = to;
this.at = at;
+ this.completion = completion;
}
public ClusterResources from() { return from; }
public ClusterResources to() { return to; }
public Instant at() { return at; }
+ public Optional<Instant> completion() { return completion; }
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServer.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServer.java
index ed545dc35d1..81c4d7be483 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServer.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServer.java
@@ -39,7 +39,7 @@ public interface ConfigServer {
void reindex(DeploymentId deployment, List<String> clusterNames, List<String> documentTypes, boolean indexedOnly);
- Optional<ApplicationReindexing> getReindexing(DeploymentId deployment);
+ ApplicationReindexing getReindexing(DeploymentId deployment);
void disableReindexing(DeploymentId deployment);
@@ -47,7 +47,7 @@ public interface ConfigServer {
void restart(DeploymentId deployment, RestartFilter restartFilter);
- void deactivate(DeploymentId deployment) throws NotFoundException;
+ void deactivate(DeploymentId deployment);
boolean isSuspended(DeploymentId deployment);
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServerException.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServerException.java
index 4240b0d9fa6..d651eda7139 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServerException.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServerException.java
@@ -1,38 +1,32 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+// Copyright Verizon Media. 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.net.URI;
-import java.util.Objects;
+import com.yahoo.slime.Inspector;
+import com.yahoo.slime.SlimeUtils;
+import org.apache.hc.core5.http.ClassicHttpRequest;
+
+import java.util.stream.Stream;
/**
- * @author Tony Vaagenes
+ * An exception due to server error, a bad request, or similar.
+ *
+ * @author jonmv
*/
public class ConfigServerException extends RuntimeException {
- private final URI serverUri;
- private final ErrorCode errorCode;
- private final String serverMessage;
+ private final ErrorCode code;
+ private final String message;
- public ConfigServerException(URI serverUri, String context, String serverMessage, ErrorCode errorCode, Throwable cause) {
- super(context + ": " + serverMessage, cause);
- this.serverUri = Objects.requireNonNull(serverUri);
- this.errorCode = Objects.requireNonNull(errorCode);
- this.serverMessage = Objects.requireNonNull(serverMessage);
+ public ConfigServerException(ErrorCode code, String message, String context) {
+ super(context + ": " + message);
+ this.code = code;
+ this.message = message;
}
- public ErrorCode getErrorCode() {
- return errorCode;
- }
+ public ErrorCode code() { return code; }
- public URI getServerUri() {
- return serverUri;
- }
+ public String message() { return message; }
- public String getServerMessage() {
- return serverMessage;
- }
-
- // TODO: Copied from Vespa. Expose these in Vespa and use them here
public enum ErrorCode {
APPLICATION_LOCK_FAILURE,
BAD_REQUEST,
@@ -46,7 +40,18 @@ public class ConfigServerException extends RuntimeException {
UNKNOWN_VESPA_VERSION,
PARENT_HOST_NOT_READY,
CERTIFICATE_NOT_READY,
- LOAD_BALANCER_NOT_READY
+ LOAD_BALANCER_NOT_READY,
+ INCOMPLETE_RESPONSE
+ }
+
+ public static ConfigServerException readException(byte[] body, String context) {
+ Inspector root = SlimeUtils.jsonToSlime(body).get();
+ String codeName = root.field("error-code").asString();
+ ErrorCode code = Stream.of(ErrorCode.values())
+ .filter(value -> value.name().equals(codeName))
+ .findAny().orElse(ErrorCode.INCOMPLETE_RESPONSE);
+ String message = root.field("message").valid() ? root.field("message").asString() : "(no message)";
+ return new ConfigServerException(code, message, context);
}
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/LoadBalancer.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/LoadBalancer.java
index 05bdf3c3412..d2f19f4df9f 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/LoadBalancer.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/LoadBalancer.java
@@ -18,11 +18,11 @@ public class LoadBalancer {
private final String id;
private final ApplicationId application;
private final ClusterSpec.Id cluster;
- private final HostName hostname;
+ private final Optional<HostName> hostname;
private final State state;
private final Optional<String> dnsZone;
- public LoadBalancer(String id, ApplicationId application, ClusterSpec.Id cluster, HostName hostname, State state,
+ public LoadBalancer(String id, ApplicationId application, ClusterSpec.Id cluster, Optional<HostName> hostname, State state,
Optional<String> dnsZone) {
this.id = Objects.requireNonNull(id, "id must be non-null");
this.application = Objects.requireNonNull(application, "application must be non-null");
@@ -44,7 +44,7 @@ public class LoadBalancer {
return cluster;
}
- public HostName hostname() {
+ public Optional<HostName> hostname() {
return hostname;
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Log.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Log.java
index ba5d740d0e1..29c3253c9c0 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Log.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Log.java
@@ -11,5 +11,6 @@ public class Log {
public long time;
public String level;
public String message;
+ public boolean applicationPackage;
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Node.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Node.java
index d1078b5e30c..0f9e12d8cf2 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Node.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Node.java
@@ -64,6 +64,7 @@ public class Node {
private final Set<String> additionalIpAddresses;
private final String openStackId;
private final Optional<String> switchHostname;
+ private final Optional<String> modelName;
public Node(HostName hostname, Optional<HostName> parentHostname, State state, NodeType type, NodeResources resources, Optional<ApplicationId> owner,
Version currentVersion, Version wantedVersion, Version currentOsVersion, Version wantedOsVersion,
@@ -72,7 +73,7 @@ public class Node {
int cost, String flavor, String clusterId, ClusterType clusterType, boolean retired, boolean wantToRetire, boolean wantToDeprovision,
boolean wantToRebuild, Optional<TenantName> reservedTo, Optional<ApplicationId> exclusiveTo,
DockerImage wantedDockerImage, DockerImage currentDockerImage, Map<String, JsonNode> reports, List<NodeHistory> history,
- Set<String> additionalIpAddresses, String openStackId, Optional<String> switchHostname) {
+ Set<String> additionalIpAddresses, String openStackId, Optional<String> switchHostname, Optional<String> modelName) {
this.hostname = hostname;
this.parentHostname = parentHostname;
this.state = state;
@@ -108,6 +109,7 @@ public class Node {
this.openStackId = openStackId;
this.additionalIpAddresses = additionalIpAddresses;
this.switchHostname = switchHostname;
+ this.modelName = modelName;
}
public HostName hostname() {
@@ -244,6 +246,8 @@ public class Node {
return switchHostname;
}
+ public Optional<String> modelName() { return modelName; }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -326,6 +330,7 @@ public class Node {
private Set<String> additionalIpAddresses = new HashSet<>();
private String openStackId;
private Optional<String> switchHostname = Optional.empty();
+ private Optional<String> modelName = Optional.empty();
public Builder() { }
@@ -365,6 +370,7 @@ public class Node {
this.additionalIpAddresses = node.additionalIpAddresses;
this.openStackId = node.openStackId;
this.switchHostname = node.switchHostname;
+ this.modelName = node.modelName;
}
public Builder hostname(HostName hostname) {
@@ -537,12 +543,17 @@ public class Node {
return this;
}
+ public Builder modelName(String modelName) {
+ this.modelName = Optional.ofNullable(modelName);
+ return this;
+ }
+
public Node build() {
return new Node(hostname, parentHostname, state, type, resources, owner, currentVersion, wantedVersion,
currentOsVersion, wantedOsVersion, currentFirmwareCheck, wantedFirmwareCheck, serviceState,
suspendedSince, restartGeneration, wantedRestartGeneration, rebootGeneration, wantedRebootGeneration,
cost, flavor, clusterId, clusterType, retired, wantToRetire, wantToDeprovision, wantToRebuild, reservedTo, exclusiveTo,
- wantedDockerImage, currentDockerImage, reports, history, additionalIpAddresses, openStackId, switchHostname);
+ wantedDockerImage, currentDockerImage, reports, history, additionalIpAddresses, openStackId, switchHostname, modelName);
}
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/NodeRepository.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/NodeRepository.java
index 72592e16bfd..ac4ff0a80a0 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/NodeRepository.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/NodeRepository.java
@@ -36,36 +36,21 @@ public interface NodeRepository {
void deleteNode(ZoneId zone, String hostname);
- void setState(ZoneId zone, NodeState nodeState, String nodename);
+ void setState(ZoneId zone, NodeState nodeState, String hostname);
NodeRepositoryNode getNode(ZoneId zone, String hostname);
+ // TODO: Migrate any callers to list() and remove this method
NodeList listNodes(ZoneId zone);
- NodeList listNodes(ZoneId zone, ApplicationId application);
-
- NodeList listNodes(ZoneId zone, List<HostName> hostnames);
-
/** List all nodes in given zone */
- default List<Node> list(ZoneId zone) {
- return listNodes(zone).nodes().stream()
- .map(NodeRepository::toNode)
- .collect(Collectors.toUnmodifiableList());
- }
+ List<Node> list(ZoneId zone, boolean includeDeprovisioned);
/** List all nodes in zone having given hostnames */
- default List<Node> list(ZoneId zone, List<HostName> hostnames) {
- return listNodes(zone, hostnames).nodes().stream()
- .map(NodeRepository::toNode)
- .collect(Collectors.toUnmodifiableList());
- }
+ List<Node> list(ZoneId zone, List<HostName> hostnames);
/** List all nodes in zone owned by given application */
- default List<Node> list(ZoneId zone, ApplicationId application) {
- return listNodes(zone, application).nodes().stream()
- .map(NodeRepository::toNode)
- .collect(Collectors.toUnmodifiableList());
- }
+ List<Node> list(ZoneId zone, ApplicationId application);
/** List all nodes in states, in zone owned by given application */
default List<Node> list(ZoneId zone, ApplicationId application, Set<Node.State> states) {
@@ -111,7 +96,7 @@ public interface NodeRepository {
/** Checks whether the zone has the spare capacity to remove the given hosts */
boolean isReplaceable(ZoneId zoneId, List<HostName> hostNames);
- private static Node toNode(NodeRepositoryNode node) {
+ static Node toNode(NodeRepositoryNode node) {
var application = Optional.ofNullable(node.getOwner())
.map(owner -> ApplicationId.from(owner.getTenant(), owner.getApplication(),
owner.getInstance()));
@@ -156,7 +141,8 @@ public interface NodeRepository {
node.getHistory(),
node.getAdditionalIpAddresses(),
node.getOpenStackId(),
- Optional.ofNullable(node.getSwitchHostname()));
+ Optional.ofNullable(node.getSwitchHostname()),
+ Optional.ofNullable(node.getModelName()));
}
private static String clusterIdOf(NodeMembership nodeMembership) {
@@ -200,6 +186,7 @@ public interface NodeRepository {
case failed: return Node.State.failed;
case parked: return Node.State.parked;
case breakfixed: return Node.State.breakfixed;
+ case deprovisioned: return Node.State.deprovisioned;
}
return Node.State.unknown;
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ProvisionResource.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ProvisionResource.java
index 26243a28ee0..5714e3d5f6d 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ProvisionResource.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ProvisionResource.java
@@ -2,7 +2,6 @@
package com.yahoo.vespa.hosted.controller.api.integration.noderepository;
import com.yahoo.config.provision.TenantName;
-import com.yahoo.vespa.hosted.controller.api.integration.configserver.NodeRepoStats;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
@@ -44,7 +43,7 @@ public interface ProvisionResource {
@GET
@Path("/node/")
- NodeList listNodes(@QueryParam("recursive") boolean recursive);
+ NodeList listNodes(@QueryParam("recursive") boolean recursive, @QueryParam("includeDeprovisioned") boolean includeDeprovisioned);
@GET
@Path("/node/")
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ScalingEventData.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ScalingEventData.java
index b33a7436522..1ac24695afe 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ScalingEventData.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ScalingEventData.java
@@ -7,6 +7,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.Cluster;
import java.time.Instant;
+import java.util.Optional;
/**
* @author bratseth
@@ -24,8 +25,17 @@ public class ScalingEventData {
@JsonProperty("at")
public Long at;
+ @JsonProperty("completion")
+ public Long completion;
+
public Cluster.ScalingEvent toScalingEvent() {
- return new Cluster.ScalingEvent(from.toClusterResources(), to.toClusterResources(), Instant.ofEpochMilli(at));
+ return new Cluster.ScalingEvent(from.toClusterResources(), to.toClusterResources(), Instant.ofEpochMilli(at),
+ toOptionalInstant(completion));
+ }
+
+ private Optional<Instant> toOptionalInstant(Long epochMillis) {
+ if (epochMillis == null) return Optional.empty();
+ return Optional.of(Instant.ofEpochMilli(epochMillis));
}
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/ChangeRequest.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/ChangeRequest.java
index 31665c8ae0a..11adc1f7bb6 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/ChangeRequest.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/ChangeRequest.java
@@ -16,7 +16,7 @@ public class ChangeRequest {
private final Approval approval;
private final Impact impact;
- private ChangeRequest(String id, ChangeRequestSource changeRequestSource, List<String> impactedSwitches, List<String> impactedHosts, Approval approval, Impact impact) {
+ public ChangeRequest(String id, ChangeRequestSource changeRequestSource, List<String> impactedSwitches, List<String> impactedHosts, Approval approval, Impact impact) {
this.id = Objects.requireNonNull(id);
this.changeRequestSource = Objects.requireNonNull(changeRequestSource);
this.impactedSwitches = Objects.requireNonNull(impactedSwitches);
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/ChangeRequestClient.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/ChangeRequestClient.java
index e8ff768927f..f8f54567bea 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/ChangeRequestClient.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/ChangeRequestClient.java
@@ -8,7 +8,8 @@ import java.util.List;
*/
public interface ChangeRequestClient {
- List<ChangeRequest> getUpcomingChangeRequests();
+ /** Get upcoming change requests and updated status of previously stored requests */
+ List<ChangeRequest> getChangeRequests(List<ChangeRequest> changeRequests);
void approveChangeRequests(List<ChangeRequest> changeRequests);
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/ChangeRequestSource.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/ChangeRequestSource.java
index 63f6c256766..6cf0f6e0ebd 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/ChangeRequestSource.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/ChangeRequestSource.java
@@ -2,8 +2,11 @@
package com.yahoo.vespa.hosted.controller.api.integration.vcmr;
import java.time.ZonedDateTime;
+import java.util.List;
import java.util.Objects;
+import static com.yahoo.vespa.hosted.controller.api.integration.vcmr.ChangeRequestSource.Status.*;
+
/**
* @author olaa
*/
@@ -17,7 +20,7 @@ public class ChangeRequestSource {
private final ZonedDateTime plannedEndTime;
- private ChangeRequestSource(String system, String id, String url, Status status, ZonedDateTime plannedStartTime, ZonedDateTime plannedEndTime) {
+ public ChangeRequestSource(String system, String id, String url, Status status, ZonedDateTime plannedStartTime, ZonedDateTime plannedEndTime) {
this.system = Objects.requireNonNull(system);
this.id = Objects.requireNonNull(id);
this.url = Objects.requireNonNull(url);
@@ -80,6 +83,10 @@ public class ChangeRequestSource {
return Objects.hash(system, id, status, url, plannedStartTime, plannedEndTime);
}
+ public boolean isClosed() {
+ return List.of(CLOSED, CANCELED, COMPLETE).contains(status);
+ }
+
public enum Status {
DRAFT,
WAITING_FOR_APPROVAL,
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/HostAction.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/HostAction.java
new file mode 100644
index 00000000000..5a018475e9f
--- /dev/null
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/HostAction.java
@@ -0,0 +1,72 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.controller.api.integration.vcmr;
+
+import java.time.Instant;
+import java.util.Objects;
+
+/**
+ * @author olaa
+ *
+ * Contains planned/current action for a host impacted by a change request
+ */
+public class HostAction {
+
+ private final String hostname;
+ private final State state;
+ private final Instant lastUpdated;
+
+ public HostAction(String hostname, State state, Instant lastUpdated) {
+ this.hostname = hostname;
+ this.state = state;
+ this.lastUpdated = lastUpdated;
+ }
+
+ public String getHostname() {
+ return hostname;
+ }
+
+ public State getState() {
+ return state;
+ }
+
+ public Instant getLastUpdated() {
+ return lastUpdated;
+ }
+
+ public HostAction withState(State state) {
+ return new HostAction(hostname, state, this.state == state ? lastUpdated : Instant.now());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ HostAction that = (HostAction) o;
+ return Objects.equals(hostname, that.hostname) &&
+ state == that.state &&
+ Objects.equals(lastUpdated, that.lastUpdated);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(hostname, state, lastUpdated);
+ }
+
+ @Override
+ public String toString() {
+ return "HostAction{" +
+ "hostname='" + hostname + '\'' +
+ ", state=" + state +
+ ", lastUpdated=" + lastUpdated +
+ '}';
+ }
+
+ public enum State {
+ REQUIRES_OPERATOR_ACTION,
+ PENDING_RETIREMENT,
+ NONE,
+ RETIRING,
+ RETIRED,
+ COMPLETE
+ }
+}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/MockChangeRequestClient.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/MockChangeRequestClient.java
index e85c0afcb0e..10175f36991 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/MockChangeRequestClient.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/MockChangeRequestClient.java
@@ -13,7 +13,7 @@ public class MockChangeRequestClient implements ChangeRequestClient {
private List<ChangeRequest> approvedChangeRequests = new ArrayList<>();
@Override
- public List<ChangeRequest> getUpcomingChangeRequests() {
+ public List<ChangeRequest> getChangeRequests(List<ChangeRequest> changeRequests) {
return upcomingChangeRequests;
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/VespaChangeRequest.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/VespaChangeRequest.java
new file mode 100644
index 00000000000..a8be4a77c71
--- /dev/null
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/vcmr/VespaChangeRequest.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.controller.api.integration.vcmr;
+
+import com.yahoo.config.provision.zone.ZoneId;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @author olaa
+ */
+public class VespaChangeRequest extends ChangeRequest {
+
+ private final Status status;
+ private final ZoneId zoneId;
+ // TODO: Create applicationActionPlan
+ private final List<HostAction> hostActionPlan;
+
+ public VespaChangeRequest(String id, ChangeRequestSource changeRequestSource, List<String> impactedSwitches, List<String> impactedHosts, Approval approval, Impact impact, Status status, List<HostAction> hostActionPlan, ZoneId zoneId) {
+ super(id, changeRequestSource, impactedSwitches, impactedHosts, approval, impact);
+ this.status = status;
+ this.hostActionPlan = hostActionPlan;
+ this.zoneId = zoneId;
+ }
+ public VespaChangeRequest(ChangeRequest changeRequest, ZoneId zoneId) {
+ this(changeRequest.getId(), changeRequest.getChangeRequestSource(), changeRequest.getImpactedSwitches(),
+ changeRequest.getImpactedHosts(), changeRequest.getApproval(), changeRequest.getImpact(), Status.PENDING_ASSESSMENT, List.of(), zoneId);
+ }
+
+ public Status getStatus() {
+ return status;
+ }
+
+ public List<HostAction> getHostActionPlan() {
+ return hostActionPlan;
+ }
+
+ public ZoneId getZoneId() {
+ return zoneId;
+ }
+
+ public VespaChangeRequest withStatus(Status status) {
+ return new VespaChangeRequest(getId(), getChangeRequestSource(), getImpactedSwitches(), getImpactedHosts(), getApproval(), getImpact(), status, hostActionPlan, zoneId);
+ }
+
+ public VespaChangeRequest withSource(ChangeRequestSource source) {
+ return new VespaChangeRequest(getId(), source, getImpactedSwitches(), getImpactedHosts(), getApproval(), getImpact(), status, hostActionPlan, zoneId);
+ }
+
+ public VespaChangeRequest withApproval(Approval approval) {
+ return new VespaChangeRequest(getId(), getChangeRequestSource(), getImpactedSwitches(), getImpactedHosts(), approval, getImpact(), status, hostActionPlan, zoneId);
+ }
+
+ public VespaChangeRequest withActionPlan(List<HostAction> hostActionPlan) {
+ return new VespaChangeRequest(getId(), getChangeRequestSource(), getImpactedSwitches(), getImpactedHosts(), getApproval(), getImpact(), status, hostActionPlan, zoneId);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ if (!super.equals(o)) return false;
+ VespaChangeRequest that = (VespaChangeRequest) o;
+ return status == that.status &&
+ Objects.equals(hostActionPlan, that.hostActionPlan) &&
+ Objects.equals(zoneId, that.zoneId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), status, hostActionPlan, zoneId);
+ }
+
+ @Override
+ public String toString() {
+ return "VespaChangeRequest{" +
+ "id='" + getId() + '\'' +
+ ", changeRequestSource=" + getChangeRequestSource() +
+ ", impactedSwitches=" + getImpactedSwitches() +
+ ", impactedHosts=" + getImpactedHosts() +
+ ", approval=" + getApproval() +
+ ", impact=" + getImpact() +
+ ", status=" + status +
+ ", zoneId=" + zoneId +
+ ", hostActionPlan=" + hostActionPlan +
+ '}';
+ }
+
+ public enum Status {
+ COMPLETED,
+ IN_PROGRESS,
+ PENDING_ACTION,
+ PENDING_ASSESSMENT,
+ REQUIRES_OPERATOR_ACTION,
+ NOOP
+ }
+}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java
index 1387f4a4eaa..558beb20e66 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java
@@ -54,6 +54,7 @@ enum PathGroup {
tenantInfo(Matcher.tenant,
"/application/v4/tenant/{tenant}/application/",
"/application/v4/tenant/{tenant}/info/",
+ "/application/v4/tenant/{tenant}/notifications",
"/routing/v1/status/tenant/{tenant}/{*}"),
tenantKeys(Matcher.tenant,