diff options
9 files changed, 104 insertions, 25 deletions
diff --git a/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/wire/GetHostResponse.java b/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/wire/GetHostResponse.java index 3f14579dfba..2a582020bb3 100644 --- a/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/wire/GetHostResponse.java +++ b/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/wire/GetHostResponse.java @@ -18,6 +18,7 @@ public class GetHostResponse { public static final String FIELD_NAME_HOSTNAME = "hostname"; public static final String FIELD_NAME_STATE = "state"; + public static final String FIELD_NAME_SUSPENDED_SINCE = "suspendedSince"; public static final String FIELD_NAME_APPLICATION_URL = "applicationUrl"; public static final String FIELD_NAME_SERVICES = "services"; @@ -25,15 +26,18 @@ public class GetHostResponse { private final String state; private final String applicationUrl; private final List<HostService> services; + private final String suspendedSince; @JsonCreator public GetHostResponse( @JsonProperty(FIELD_NAME_HOSTNAME) String hostname, @JsonProperty(FIELD_NAME_STATE) String state, + @JsonProperty(FIELD_NAME_SUSPENDED_SINCE) String suspendedSince, @JsonProperty(FIELD_NAME_APPLICATION_URL) String applicationUrl, @JsonProperty(FIELD_NAME_SERVICES) List<HostService> services) { this.hostname = hostname; this.state = state; + this.suspendedSince = suspendedSince; this.applicationUrl = applicationUrl; this.services = services; } @@ -48,6 +52,11 @@ public class GetHostResponse { return state; } + @JsonProperty(FIELD_NAME_SUSPENDED_SINCE) + public String suspendedSince() { + return suspendedSince; + } + @JsonProperty(FIELD_NAME_APPLICATION_URL) public String applicationUrl() { return applicationUrl; @@ -65,12 +74,13 @@ public class GetHostResponse { GetHostResponse that = (GetHostResponse) o; return Objects.equals(hostname, that.hostname) && Objects.equals(state, that.state) && + Objects.equals(suspendedSince, that.suspendedSince) && Objects.equals(applicationUrl, that.applicationUrl) && Objects.equals(services, that.services); } @Override public int hashCode() { - return Objects.hash(hostname, state, applicationUrl, services); + return Objects.hash(hostname, state, suspendedSince, applicationUrl, services); } } diff --git a/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/wire/WireHostInfo.java b/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/wire/WireHostInfo.java new file mode 100644 index 00000000000..39c93291bad --- /dev/null +++ b/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/wire/WireHostInfo.java @@ -0,0 +1,38 @@ +package com.yahoo.vespa.orchestrator.restapi.wire; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.time.Instant; +import java.util.Objects; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class WireHostInfo { + private static final String HOST_STATUS_FIELD = "hostStatus"; + private static final String SUSPENDED_SINCE_FIELD = "suspendedSince"; + + private final String hostStatus; + private final String suspendedSinceUtcOrNull; + + /** + * @param hostStatus The host status, e.g. NO_REMARKS. + * @param suspendedSinceUtcOrNull The time the host was suspended in the format + * {@link Instant#toString()}, or null if not suspended + * (NO_REMARKS). + */ + @JsonCreator + public WireHostInfo(@JsonProperty(HOST_STATUS_FIELD) String hostStatus, + @JsonProperty(SUSPENDED_SINCE_FIELD) String suspendedSinceUtcOrNull) { + this.hostStatus = Objects.requireNonNull(hostStatus); + this.suspendedSinceUtcOrNull = suspendedSinceUtcOrNull; + } + + @JsonProperty(HOST_STATUS_FIELD) + public String hostStatus() { return hostStatus; } + + @JsonProperty(SUSPENDED_SINCE_FIELD) + public String getSuspendedSinceUtcOrNull() { return suspendedSinceUtcOrNull; } +} diff --git a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/Host.java b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/Host.java index bda9505d72b..8f5f00af7a0 100644 --- a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/Host.java +++ b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/Host.java @@ -4,23 +4,23 @@ package com.yahoo.vespa.orchestrator; import com.yahoo.vespa.applicationmodel.ApplicationInstanceReference; import com.yahoo.vespa.applicationmodel.HostName; import com.yahoo.vespa.applicationmodel.ServiceInstance; -import com.yahoo.vespa.orchestrator.status.HostStatus; +import com.yahoo.vespa.orchestrator.status.HostInfo; import java.util.List; public class Host { private final HostName hostName; - private final HostStatus hostStatus; + private final HostInfo hostInfo; private final ApplicationInstanceReference applicationInstanceReference; private final List<ServiceInstance> serviceInstances; public Host(HostName hostName, - HostStatus hostStatus, + HostInfo hostInfo, ApplicationInstanceReference applicationInstanceReference, List<ServiceInstance> serviceInstances) { this.hostName = hostName; - this.hostStatus = hostStatus; + this.hostInfo = hostInfo; this.applicationInstanceReference = applicationInstanceReference; this.serviceInstances = serviceInstances; } @@ -29,8 +29,8 @@ public class Host { return hostName; } - public HostStatus getHostStatus() { - return hostStatus; + public HostInfo getHostInfo() { + return hostInfo; } public ApplicationInstanceReference getApplicationInstanceReference() { diff --git a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/OrchestratorImpl.java b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/OrchestratorImpl.java index 414548f8bdc..fbe6864274c 100644 --- a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/OrchestratorImpl.java +++ b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/OrchestratorImpl.java @@ -114,9 +114,10 @@ public class OrchestratorImpl implements Orchestrator { .filter(serviceInstance -> hostName.equals(serviceInstance.hostName())) .collect(Collectors.toList()); + HostInfo hostInfo = statusService.getHostInfo(applicationInstance.reference(), hostName); HostStatus hostStatus = getNodeStatus(applicationInstance.reference(), hostName); - return new Host(hostName, hostStatus, applicationInstance.reference(), serviceInstances); + return new Host(hostName, hostInfo, applicationInstance.reference(), serviceInstances); } @Override diff --git a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/resources/HostResource.java b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/resources/HostResource.java index 4bb93ffa3cb..fc5c5eb5004 100644 --- a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/resources/HostResource.java +++ b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/resources/HostResource.java @@ -31,6 +31,7 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import java.net.URI; +import java.time.Instant; import java.util.List; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -72,7 +73,8 @@ public class HostResource implements HostApi { return new GetHostResponse( host.getHostName().s(), - host.getHostStatus().name(), + host.getHostInfo().status().name(), + host.getHostInfo().suspendedSince().map(Instant::toString).orElse(null), applicationUri.toString(), hostServices); } catch (UncheckedTimeoutException e) { diff --git a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/resources/InstanceResource.java b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/resources/InstanceResource.java index 7b8a74d7fe2..fbb8f445db0 100644 --- a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/resources/InstanceResource.java +++ b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/resources/InstanceResource.java @@ -14,6 +14,8 @@ import com.yahoo.vespa.applicationmodel.ServiceType; import com.yahoo.vespa.orchestrator.InstanceLookupService; import com.yahoo.vespa.orchestrator.OrchestratorUtil; import com.yahoo.vespa.orchestrator.restapi.wire.SlobrokEntryResponse; +import com.yahoo.vespa.orchestrator.restapi.wire.WireHostInfo; +import com.yahoo.vespa.orchestrator.status.HostInfo; import com.yahoo.vespa.orchestrator.status.HostInfos; import com.yahoo.vespa.orchestrator.status.StatusService; import com.yahoo.vespa.service.manager.MonitorManager; @@ -29,9 +31,10 @@ import javax.ws.rs.QueryParam; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import java.time.Instant; import java.util.List; -import java.util.Map; import java.util.Set; +import java.util.TreeMap; import java.util.stream.Collectors; import static com.yahoo.vespa.orchestrator.OrchestratorUtil.getHostsUsedByApplicationInstance; @@ -82,13 +85,23 @@ public class InstanceResource { .orElseThrow(() -> new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build())); HostInfos hostInfos = statusService.getHostInfosByApplicationResolver().apply(applicationInstance.reference()); - Map<HostName, String> hostStatusMap = getHostsUsedByApplicationInstance(applicationInstance) - .stream() - .collect(Collectors.toMap(hostName -> hostName, - hostName -> hostInfos.getOrNoRemarks(hostName).status().asString())); + TreeMap<HostName, WireHostInfo> hostStatusMap = + getHostsUsedByApplicationInstance(applicationInstance) + .stream() + .collect(Collectors.toMap( + hostName -> hostName, + hostName -> hostInfoToWire(hostInfos.getOrNoRemarks(hostName)), + (u, v) -> { throw new IllegalStateException(); }, + TreeMap::new)); return InstanceStatusResponse.create(applicationInstance, hostStatusMap); } + private WireHostInfo hostInfoToWire(HostInfo hostInfo) { + String hostStatusString = hostInfo.status().asString(); + String suspendedSinceUtcOrNull = hostInfo.suspendedSince().map(Instant::toString).orElse(null); + return new WireHostInfo(hostStatusString, suspendedSinceUtcOrNull); + } + @GET @Path("/{instanceId}/slobrok") @Produces(MediaType.APPLICATION_JSON) diff --git a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/resources/InstanceStatusResponse.java b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/resources/InstanceStatusResponse.java index 068423f7d24..313c73e5c68 100644 --- a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/resources/InstanceStatusResponse.java +++ b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/resources/InstanceStatusResponse.java @@ -4,10 +4,12 @@ package com.yahoo.vespa.orchestrator.resources; import com.fasterxml.jackson.annotation.JsonProperty; import com.yahoo.vespa.applicationmodel.ApplicationInstance; import com.yahoo.vespa.applicationmodel.HostName; -import com.yahoo.vespa.orchestrator.status.HostInfo; +import com.yahoo.vespa.orchestrator.restapi.wire.WireHostInfo; import java.util.Map; import java.util.Objects; +import java.util.TreeMap; +import java.util.stream.Collectors; /* * @author andreer @@ -15,16 +17,16 @@ import java.util.Objects; public class InstanceStatusResponse { private final ApplicationInstance applicationInstance; - private final Map<HostName, String> hostStates; + private final TreeMap<HostName, WireHostInfo> hostInfos; - private InstanceStatusResponse(ApplicationInstance applicationInstance, Map<HostName, String> hostStates) { + private InstanceStatusResponse(ApplicationInstance applicationInstance, TreeMap<HostName, WireHostInfo> hostInfos) { this.applicationInstance = applicationInstance; - this.hostStates = hostStates; + this.hostInfos = hostInfos; } public static InstanceStatusResponse create( ApplicationInstance applicationInstance, - Map<HostName, String> hostStates) { + TreeMap<HostName, WireHostInfo> hostStates) { return new InstanceStatusResponse(applicationInstance, hostStates); } @@ -35,14 +37,24 @@ public class InstanceStatusResponse { @JsonProperty("hostStates") public Map<HostName, String> hostStates() { - return hostStates; + // TODO: Remove this once all clients have been moved to hostStatus. + return hostInfos.entrySet().stream() + .collect(Collectors.toMap( + entry -> entry.getKey(), + entry -> entry.getValue().hostStatus() + )); + } + + @JsonProperty("hostInfos") + public TreeMap<HostName, WireHostInfo> hostInfos() { + return hostInfos; } @Override public String toString() { return "InstanceStatusResponse{" + "applicationInstance=" + applicationInstance + - ", hostStates=" + hostStates + + ", hostInfos=" + hostInfos + '}'; } @@ -52,11 +64,11 @@ public class InstanceStatusResponse { if (o == null || getClass() != o.getClass()) return false; InstanceStatusResponse that = (InstanceStatusResponse) o; return Objects.equals(applicationInstance, that.applicationInstance) && - Objects.equals(hostStates, that.hostStates); + Objects.equals(hostInfos, that.hostInfos); } @Override public int hashCode() { - return Objects.hash(applicationInstance, hostStates); + return Objects.hash(applicationInstance, hostInfos); } } diff --git a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/OrchestratorImplTest.java b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/OrchestratorImplTest.java index a2c99b86ae2..77ec824da54 100644 --- a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/OrchestratorImplTest.java +++ b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/OrchestratorImplTest.java @@ -435,7 +435,8 @@ public class OrchestratorImplTest { Host host = orchestrator.getHost(hostName); assertEquals(reference, host.getApplicationInstanceReference()); assertEquals(hostName, host.getHostName()); - assertEquals(HostStatus.ALLOWED_TO_BE_DOWN, host.getHostStatus()); + assertEquals(HostStatus.ALLOWED_TO_BE_DOWN, host.getHostInfo().status()); + assertTrue(host.getHostInfo().suspendedSince().isPresent()); assertEquals(2, host.getServiceInstances().size()); } diff --git a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/resources/HostResourceTest.java b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/resources/HostResourceTest.java index b19f96a5867..dc26c1a3770 100644 --- a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/resources/HostResourceTest.java +++ b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/resources/HostResourceTest.java @@ -37,6 +37,7 @@ import com.yahoo.vespa.orchestrator.restapi.wire.GetHostResponse; import com.yahoo.vespa.orchestrator.restapi.wire.PatchHostRequest; import com.yahoo.vespa.orchestrator.restapi.wire.PatchHostResponse; import com.yahoo.vespa.orchestrator.restapi.wire.UpdateHostResponse; +import com.yahoo.vespa.orchestrator.status.HostInfo; import com.yahoo.vespa.orchestrator.status.HostStatus; import com.yahoo.vespa.orchestrator.status.MutableStatusRegistry; import com.yahoo.vespa.orchestrator.status.StatusService; @@ -348,7 +349,7 @@ public class HostResourceTest { Host host = new Host( hostName, - HostStatus.ALLOWED_TO_BE_DOWN, + HostInfo.createSuspended(HostStatus.ALLOWED_TO_BE_DOWN, Instant.EPOCH), new ApplicationInstanceReference( new TenantId("tenantId"), new ApplicationInstanceId("applicationId")), @@ -358,6 +359,7 @@ public class HostResourceTest { assertEquals("https://foo.com/bar", response.applicationUrl()); assertEquals("hostname", response.hostname()); assertEquals("ALLOWED_TO_BE_DOWN", response.state()); + assertEquals("1970-01-01T00:00:00Z", response.suspendedSince()); assertEquals(1, response.services().size()); assertEquals("clusterId", response.services().get(0).clusterId); assertEquals("configId", response.services().get(0).configId); |