diff options
author | Jon Bratseth <bratseth@yahoo-inc.com> | 2016-06-15 23:09:44 +0200 |
---|---|---|
committer | Jon Bratseth <bratseth@yahoo-inc.com> | 2016-06-15 23:09:44 +0200 |
commit | 72231250ed81e10d66bfe70701e64fa5fe50f712 (patch) | |
tree | 2728bba1131a6f6e5bdf95afec7d7ff9358dac50 /orchestrator-restapi |
Publish
Diffstat (limited to 'orchestrator-restapi')
12 files changed, 503 insertions, 0 deletions
diff --git a/orchestrator-restapi/OWNERS b/orchestrator-restapi/OWNERS new file mode 100644 index 00000000000..9ecc8472a21 --- /dev/null +++ b/orchestrator-restapi/OWNERS @@ -0,0 +1,2 @@ +bakksjo +hakon diff --git a/orchestrator-restapi/README b/orchestrator-restapi/README new file mode 100644 index 00000000000..537cdd95c8f --- /dev/null +++ b/orchestrator-restapi/README @@ -0,0 +1 @@ +REST API definitions for orchestrator. diff --git a/orchestrator-restapi/README.md b/orchestrator-restapi/README.md new file mode 100644 index 00000000000..367a4cfbdf3 --- /dev/null +++ b/orchestrator-restapi/README.md @@ -0,0 +1,5 @@ +# REST API definitions for Orchestrator. + +Having the API definitions in a separate module makes it easier +to build clients without duplicating code. It also makes it +harder to introduce bugs due to mismatching paths, parameters etc. diff --git a/orchestrator-restapi/pom.xml b/orchestrator-restapi/pom.xml new file mode 100644 index 00000000000..58480cf0423 --- /dev/null +++ b/orchestrator-restapi/pom.xml @@ -0,0 +1,47 @@ +<?xml version="1.0"?> +<!-- Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. --> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 + http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>com.yahoo.vespa</groupId> + <artifactId>parent</artifactId> + <version>6-SNAPSHOT</version> + <relativePath>../parent/pom.xml</relativePath> + </parent> + <artifactId>orchestrator-restapi</artifactId> + <version>6-SNAPSHOT</version> + <packaging>container-plugin</packaging> + <name>${project.artifactId}</name> + <dependencies> + <dependency> + <groupId>javax.ws.rs</groupId> + <artifactId>javax.ws.rs-api</artifactId> + <version>2.0</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-annotations</artifactId> + <version>${jackson2.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>com.google.code.findbugs</groupId> + <artifactId>jsr305</artifactId> + <version>1.3.9</version> + <scope>provided</scope> + </dependency> + </dependencies> + <build> + <plugins> + <plugin> + <groupId>com.yahoo.vespa</groupId> + <artifactId>bundle-plugin</artifactId> + <extensions>true</extensions> + </plugin> + </plugins> + </build> +</project> diff --git a/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/ApplicationSuspensionApi.java b/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/ApplicationSuspensionApi.java new file mode 100644 index 00000000000..e40e06062c2 --- /dev/null +++ b/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/ApplicationSuspensionApi.java @@ -0,0 +1,90 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.orchestrator.restapi; + +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import java.util.Set; + +/** + * Definition of Orchestrator's REST API for suspensions of applications aka application instances. + * + * Implementing classes must not put any JAX-RS annotation on the overridden methods. Doing so will cause all + * method annotations in this interface to be ignored by the JAX-RS container (see section 3.6 of JSR-339). + * + * @author <a href="mailto:smorgrav@yahoo-inc.com">Toby</a> + */ +public interface ApplicationSuspensionApi { + /** + * Path prefix for this api. Resources implementing this API should use this with a @Path annotation. + */ + String PATH_PREFIX = "/v1/suspensions/applications"; + + /** + * Lists all applications that is currently suspended. + * + * HTTP Behavior: + * Always 200 + * + * @return A list of application ids of suspended applications + */ + @GET + @Produces(MediaType.APPLICATION_JSON) + Set<String> getApplications(); + + /** + * Shows the Orchestrator status for an application instance + * + * HTTP Behavior: + * 204 if the application is suspended + * 400 if the applicationId is invalid + * 404 if the application is not suspended + * + * @param applicationIdString the fully qualified application id. + */ + @GET + @Path("/{application}") + @Produces(MediaType.APPLICATION_JSON) + void getApplication(@PathParam("application") String applicationIdString); + + /** + * Ask for permission to temporarily suspend all services for an application instance. + * + * On success all content nodes for this application instance have been set in maintenance mode. + * + * Once the application is ready to resume normal operations, it must finish with resume() (see below). + * + * If the application has already been granted permission to suspend all services, requesting + * suspension again is idempotent and will succeed. + * + * HTTP Behavior: + * 204 is the suspend operation was successful + * 400 if the applicationId is invalid + * 409 if the suspend was denied + * + * @param applicationIdString the fully qualified application id. + */ + @POST + void suspend(String applicationIdString); + + /** + * Resume normal operations for all services for an application + * instance that has previously been allowed suspension. + * + * If the host is already registered as running normal operations, then resume() is idempotent + * and will succeed. + * + * HTTP Behavior: + * Returns 204 is the resume operation was successful (or the application was not suspended) + * Returns 400 if the applicationId is invalid + * + * @param applicationIdString the fully qualified application id. + */ + @DELETE + @Path("/{application}") + void resume(@PathParam("application") String applicationIdString); +} diff --git a/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/HostApi.java b/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/HostApi.java new file mode 100644 index 00000000000..bdcc4fe51d0 --- /dev/null +++ b/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/HostApi.java @@ -0,0 +1,69 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.orchestrator.restapi; + +import com.yahoo.vespa.orchestrator.restapi.wire.GetHostResponse; +import com.yahoo.vespa.orchestrator.restapi.wire.UpdateHostResponse; + +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +/** + * Definition of Orchestrator's REST API for hosts. + * + * Implementing classes must not put any JAX-RS annotation on the overridden methods. Doing so will cause all + * method annotations in this interface to be ignored by the JAX-RS container (see section 3.6 of JSR-339). + * + * @author <a href="mailto:bakksjo@yahoo-inc.com">Oyvind Bakksjo</a> + */ +public interface HostApi { + /** + * Path prefix for this api. Resources implementing this API should use this with a @Path annotation. + */ + String PATH_PREFIX = "/v1/hosts"; + + /** + * Shows the Orchestrator state of a host. + * + * @param hostNameString the fully qualified host name + */ + @GET + @Path("/{hostname}") + @Produces(MediaType.APPLICATION_JSON) + GetHostResponse getHost(@PathParam("hostname") String hostNameString); + + /** + * Ask for permission to temporarily suspend all services on a host. + * + * On success, none, some, or all services on the host may already have been effectively suspended, + * e.g. as of Feb 2015, a content node would already be set in the maintenance state. + * + * Once the host is ready to resume normal operations, it must finish with resume() (see below). + * + * If the host has already been granted permission to suspend all services, requesting + * suspension again is idempotent and will succeed. + * + * @param hostNameString the fully qualified host name. + */ + @PUT + @Path("/{hostname}/suspended") + @Produces(MediaType.APPLICATION_JSON) + UpdateHostResponse suspend(@PathParam("hostname") String hostNameString); + + /** + * Resume normal operations for all services on a host that has previously been allowed suspension. + * + * If the host is already registered as running normal operations, then resume() is idempotent + * and will succeed. + * + * @param hostNameString the fully qualified host name. + */ + @DELETE + @Path("/{hostname}/suspended") + @Produces(MediaType.APPLICATION_JSON) + UpdateHostResponse resume(@PathParam("hostname") String hostNameString); +} diff --git a/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/HostSuspensionApi.java b/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/HostSuspensionApi.java new file mode 100644 index 00000000000..3456e5ae3ae --- /dev/null +++ b/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/HostSuspensionApi.java @@ -0,0 +1,31 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.orchestrator.restapi; + +import com.yahoo.vespa.orchestrator.restapi.wire.BatchHostSuspendRequest; +import com.yahoo.vespa.orchestrator.restapi.wire.BatchOperationResult; + +import javax.ws.rs.Consumes; +import javax.ws.rs.PUT; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +public interface HostSuspensionApi { + /** + * Path prefix for this api. Resources implementing this API should use this with a @Path annotation. + */ + String PATH_PREFIX = "/v1/suspensions/hosts"; + + /** + * Ask for permission to temporarily suspend all services on a set of hosts. + * + * See HostApi::suspend for semantics of suspending a host. + * + * On failure, it tries to resume ALL hosts. It needs to try to resume all hosts because any or all hosts + * may have been suspended in an earlier attempt. Ending with resumption of all hosts makes sure other + * batch-requests for suspension of hosts succeed. + */ + @PUT + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + BatchOperationResult suspendAll(BatchHostSuspendRequest request); +} diff --git a/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/wire/BatchHostSuspendRequest.java b/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/wire/BatchHostSuspendRequest.java new file mode 100644 index 00000000000..eca9e10f3b7 --- /dev/null +++ b/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/wire/BatchHostSuspendRequest.java @@ -0,0 +1,48 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.orchestrator.restapi.wire; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import javax.annotation.concurrent.Immutable; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +@Immutable +public class BatchHostSuspendRequest { + public static final String PARENT_HOSTNAME_FIELD = "parentHostname"; + public static final String HOSTNAMES_FIELD = "hostnames"; + + public final Optional<String> parentHostname; + public final Optional<List<String>> hostnames; + + @JsonCreator + public BatchHostSuspendRequest( + @JsonProperty(PARENT_HOSTNAME_FIELD) String parentHostname, + @JsonProperty(HOSTNAMES_FIELD) List<String> hostnames) { + this.parentHostname = Optional.ofNullable(parentHostname); + this.hostnames = Optional.ofNullable(hostnames).map(Collections::unmodifiableList); + } + + /** + * @return The hostname of the parent of the hostnames, if applicable, which can be used for debugging. + */ + @JsonProperty(PARENT_HOSTNAME_FIELD) + public Optional<String> getParentHostname() { + return parentHostname; + } + + @JsonProperty(HOSTNAMES_FIELD) + public Optional<List<String>> getHostnames() { + return hostnames; + } + + @Override + public String toString() { + return "BatchHostSuspendRequest{" + + "parentHostname=" + parentHostname + + ", hostnames=" + hostnames + + '}'; + } +} diff --git a/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/wire/BatchOperationResult.java b/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/wire/BatchOperationResult.java new file mode 100644 index 00000000000..b4689247cc3 --- /dev/null +++ b/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/wire/BatchOperationResult.java @@ -0,0 +1,33 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.orchestrator.restapi.wire; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Optional; + +public class BatchOperationResult { + private static final String FAILURE_REASON = "failure-reason"; + + private final Optional<String> failureReason; + // private final List<String> suppressedFailures; + + public static BatchOperationResult successResult() { + return new BatchOperationResult(null); + } + + @JsonCreator + public BatchOperationResult( + @JsonProperty(FAILURE_REASON) String failureReason) { + this.failureReason = Optional.ofNullable(failureReason); + } + + @JsonProperty(FAILURE_REASON) + public Optional<String> getFailureReason() { + return failureReason; + } + + public boolean success() { + return !failureReason.isPresent(); + } +} 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 new file mode 100644 index 00000000000..a3ff86423e0 --- /dev/null +++ b/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/wire/GetHostResponse.java @@ -0,0 +1,55 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.orchestrator.restapi.wire; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Objects; + +/* + * @author andreer + */ +public class GetHostResponse { + + public static final String FIELD_NAME_HOSTNAME = "hostname"; + public static final String FIELD_NAME_STATE = "state"; + + private final String hostname; + private final String state; + + @JsonCreator + public GetHostResponse( + @JsonProperty(FIELD_NAME_HOSTNAME) final String hostname, + @JsonProperty(FIELD_NAME_STATE) final String state) { + this.hostname = hostname; + this.state = state; + } + + @JsonProperty(FIELD_NAME_HOSTNAME) + public String hostname() { + return hostname; + } + + @JsonProperty(FIELD_NAME_STATE) + public String state() { + return state; + } + + @Override + public boolean equals(final Object o) { + if (!(o instanceof GetHostResponse)) { + return false; + } + + final GetHostResponse other = (GetHostResponse) o; + if (!Objects.equals(this.hostname, other.hostname)) return false; + if (!Objects.equals(this.state, other.state)) return false; + + return true; + } + + @Override + public int hashCode() { + return Objects.hash(hostname, state); + } +} diff --git a/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/wire/HostStateChangeDenialReason.java b/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/wire/HostStateChangeDenialReason.java new file mode 100644 index 00000000000..37366e6efd3 --- /dev/null +++ b/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/wire/HostStateChangeDenialReason.java @@ -0,0 +1,66 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.orchestrator.restapi.wire; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Objects; + +/* + * A reason to reject a host state change request + * @author andreer + */ +public class HostStateChangeDenialReason { + + public static final String FIELD_NAME_CONSTRAINT = "constraint"; + public static final String FIELD_NAME_SERVICE_TYPE = "service-type"; + public static final String FIELD_NAME_MESSAGE = "message"; + + private final String constraintName; + private final String serviceType; + private final String message; + + @JsonCreator + public HostStateChangeDenialReason( + @JsonProperty(FIELD_NAME_CONSTRAINT) final String constraintName, + @JsonProperty(FIELD_NAME_SERVICE_TYPE) final String serviceType, + @JsonProperty(FIELD_NAME_MESSAGE) final String message) { + this.constraintName = constraintName; + this.serviceType = serviceType; + this.message = message; + } + + @JsonProperty(FIELD_NAME_CONSTRAINT) + public String constraintName() { + return constraintName; + } + + @JsonProperty(FIELD_NAME_SERVICE_TYPE) + public String serviceType() { + return serviceType; + } + + @JsonProperty(FIELD_NAME_MESSAGE) + public String message() { + return message; + } + + @Override + public boolean equals(final Object o) { + if (!(o instanceof HostStateChangeDenialReason)) { + return false; + } + + final HostStateChangeDenialReason other = (HostStateChangeDenialReason) o; + if (!Objects.equals(this.constraintName, other.constraintName)) return false; + if (!Objects.equals(this.serviceType, other.serviceType)) return false; + if (!Objects.equals(this.message, other.message)) return false; + + return true; + } + + @Override + public int hashCode() { + return Objects.hash(constraintName, serviceType, message); + } +} diff --git a/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/wire/UpdateHostResponse.java b/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/wire/UpdateHostResponse.java new file mode 100644 index 00000000000..20921dec4de --- /dev/null +++ b/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/wire/UpdateHostResponse.java @@ -0,0 +1,56 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.orchestrator.restapi.wire; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import javax.annotation.Nullable; +import java.util.Objects; + +/* + * @author andreer + */ +public class UpdateHostResponse { + + public static final String FIELD_NAME_HOSTNAME = "hostname"; + public static final String FIELD_NAME_REASON = "reason"; + + private final String hostname; + private final HostStateChangeDenialReason hostStateChangeDenialReason; + + @JsonCreator + public UpdateHostResponse( + @JsonProperty(FIELD_NAME_HOSTNAME) final String hostname, + @JsonProperty(FIELD_NAME_REASON) @Nullable final HostStateChangeDenialReason hostStateChangeDenialReason) { + this.hostname = hostname; + this.hostStateChangeDenialReason = hostStateChangeDenialReason; + } + + @JsonProperty(FIELD_NAME_HOSTNAME) + public String hostname() { + return hostname; + } + + @JsonProperty(FIELD_NAME_REASON) @Nullable + public HostStateChangeDenialReason reason() { + return hostStateChangeDenialReason; + } + + @Override + public boolean equals(final Object o) { + if (!(o instanceof UpdateHostResponse)) { + return false; + } + + final UpdateHostResponse other = (UpdateHostResponse) o; + if (!Objects.equals(this.hostname, other.hostname)) return false; + if (!Objects.equals(this.hostStateChangeDenialReason, other.hostStateChangeDenialReason)) return false; + + return true; + } + + @Override + public int hashCode() { + return Objects.hash(hostname, hostStateChangeDenialReason); + } +} |