summaryrefslogtreecommitdiffstats
path: root/hosted-api
diff options
context:
space:
mode:
authorJon Marius Venstad <jvenstad@yahoo-inc.com>2019-05-13 15:08:28 +0200
committerJon Marius Venstad <jvenstad@yahoo-inc.com>2019-05-13 15:08:28 +0200
commit03770824cee298626766df71f19af998da71b810 (patch)
treef52d8421deca020a224566605004b3ec167166e0 /hosted-api
parent202ed3ce6c69a1cba13fee602e91a2ddfd8940a0 (diff)
Encode path parts too
Diffstat (limited to 'hosted-api')
-rw-r--r--hosted-api/src/main/java/ai/vespa/hosted/api/ControllerHttpClient.java56
1 files changed, 53 insertions, 3 deletions
diff --git a/hosted-api/src/main/java/ai/vespa/hosted/api/ControllerHttpClient.java b/hosted-api/src/main/java/ai/vespa/hosted/api/ControllerHttpClient.java
index 15cb9aa01ef..9c563306cee 100644
--- a/hosted-api/src/main/java/ai/vespa/hosted/api/ControllerHttpClient.java
+++ b/hosted-api/src/main/java/ai/vespa/hosted/api/ControllerHttpClient.java
@@ -7,10 +7,12 @@ import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.TenantName;
import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.security.SslContextBuilder;
+import com.yahoo.slime.ArrayTraverser;
import com.yahoo.slime.Cursor;
import com.yahoo.slime.Inspector;
import com.yahoo.slime.JsonDecoder;
import com.yahoo.slime.JsonFormat;
+import com.yahoo.slime.ObjectTraverser;
import com.yahoo.slime.Slime;
import java.io.ByteArrayInputStream;
@@ -19,22 +21,27 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.net.URI;
+import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.Callable;
import java.util.function.Supplier;
+import java.util.stream.Stream;
import static ai.vespa.hosted.api.Method.DELETE;
import static ai.vespa.hosted.api.Method.GET;
import static ai.vespa.hosted.api.Method.POST;
-import static java.net.http.HttpRequest.BodyPublishers.ofByteArray;
import static java.net.http.HttpRequest.BodyPublishers.ofInputStream;
import static java.net.http.HttpResponse.BodyHandlers.ofByteArray;
import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.stream.Collectors.joining;
/**
* Talks to a remote controller over HTTP. Subclasses are responsible for adding authentication to the requests.
@@ -105,6 +112,18 @@ public abstract class ControllerHttpClient {
.field("compileVersion").asString();
}
+ /** Returns the sorted list of log entries after the given after from the deployment job of the given ids. */
+ public DeploymentLog deploymentLog(ApplicationId id, ZoneId zone, long run, long after) {
+ return toDeploymentLog(send(request(HttpRequest.newBuilder(runPath(id, zone, run, after))
+ .timeout(Duration.ofSeconds(10)),
+ GET)));
+ }
+
+ /** Returns the sorted list of log entries from the deployment job of the given ids. */
+ public DeploymentLog deploymentLog(ApplicationId id, ZoneId zone, long run) {
+ return deploymentLog(id, zone, run, -1);
+ }
+
protected HttpRequest request(HttpRequest.Builder request, Method method, Supplier<InputStream> data) {
return request.method(method.name(), ofInputStream(data)).build();
}
@@ -146,7 +165,14 @@ public abstract class ControllerHttpClient {
private URI deploymentJobPath(ApplicationId id, ZoneId zone) {
return concatenated(instancePath(id),
- "deploy", zone.environment().value() + "-" + zone.region().value().replaceAll("vaas-", ""));
+ "deploy", jobNameOf(zone));
+ }
+
+ private URI runPath(ApplicationId id, ZoneId zone, long run, long after) {
+ return withQuery(concatenated(instancePath(id),
+ "job", jobNameOf(zone),
+ "run", Long.toString(run)),
+ "after", Long.toString(after));
}
private URI defaultRegionPath() {
@@ -154,7 +180,17 @@ public abstract class ControllerHttpClient {
}
private static URI concatenated(URI base, String... parts) {
- return base.resolve(String.join("/", parts) + "/");
+ return base.resolve(Stream.of(parts).map(part -> URLEncoder.encode(part, UTF_8)).collect(joining("/")) + "/");
+ }
+
+ private static URI withQuery(URI base, String name, String value) {
+ return base.resolve( "?" + (base.getRawQuery() != null ? base.getRawQuery() + "&" : "")
+ + URLEncoder.encode(name, UTF_8) + "=" + URLEncoder.encode(value, UTF_8));
+ }
+
+ // TODO jvenstad: remove when vaas is no longer part of region names.
+ private static String jobNameOf(ZoneId zone) {
+ return zone.environment().value() + "-" + zone.region().value().replaceAll("vaas-", "");
}
private HttpResponse<byte[]> send(HttpRequest request) {
@@ -238,6 +274,20 @@ public abstract class ControllerHttpClient {
rootObject.field("run").asLong());
}
+ private static DeploymentLog toDeploymentLog(HttpResponse<byte[]> response) {
+ Inspector rootObject = toInspector(response);
+ List<DeploymentLog.Entry> entries = new ArrayList<>();
+ rootObject.field("log").traverse((ObjectTraverser) (__, entryArray) ->
+ entryArray.traverse((ArrayTraverser) (___, entryObject) -> {
+ entries.add(new DeploymentLog.Entry(Instant.ofEpochMilli(entryObject.field("at").asLong()),
+ entryObject.field("type").asString(),
+ entryObject.field("message").asString()));
+ }));
+ return new DeploymentLog(entries,
+ rootObject.field("active").asBool(),
+ rootObject.field("lastId").asLong());
+ }
+
private static Slime toSlime(byte[] data) {
return new JsonDecoder().decode(new Slime(), data);
}