aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Marius Venstad <jvenstad@yahoo-inc.com>2017-11-02 16:17:19 +0100
committerJon Marius Venstad <jvenstad@yahoo-inc.com>2017-11-02 16:17:19 +0100
commitdc8e0d42ec88d63c1f95766d57d1c7d2ed3a4f1a (patch)
treed14ab7df64d89404f0fc7cc6d30f687d33ac0342
parent2f44386e16d6b130cebbdfff807ce4bcc8fad5a1 (diff)
Add relevant job info to application blobs
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/deployment/DeploymentApiHandler.java94
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/responses/root.json19
2 files changed, 88 insertions, 25 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/deployment/DeploymentApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/deployment/DeploymentApiHandler.java
index e4221a6c6c8..90214965718 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/deployment/DeploymentApiHandler.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/deployment/DeploymentApiHandler.java
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller.restapi.deployment;
+import com.yahoo.component.Version;
import com.yahoo.config.application.api.DeploymentSpec;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.container.jdisc.HttpRequest;
@@ -11,6 +12,7 @@ import com.yahoo.slime.Cursor;
import com.yahoo.slime.Slime;
import com.yahoo.vespa.hosted.controller.Application;
import com.yahoo.vespa.hosted.controller.Controller;
+import com.yahoo.vespa.hosted.controller.application.JobStatus;
import com.yahoo.vespa.hosted.controller.versions.VespaVersion;
import com.yahoo.vespa.hosted.controller.restapi.ErrorResponse;
import com.yahoo.vespa.hosted.controller.restapi.SlimeJsonResponse;
@@ -19,15 +21,17 @@ import com.yahoo.vespa.hosted.controller.restapi.application.EmptyJsonResponse;
import com.yahoo.vespa.hosted.controller.restapi.Path;
import com.yahoo.yolean.Exceptions;
-import java.time.Instant;
import java.util.Optional;
import java.util.concurrent.Executor;
import java.util.logging.Level;
+import static com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobError.outOfCapacity;
+import static java.util.Comparator.comparing;
+
/**
* This implements the deployment/v1 API which provides information about the status of Vespa platform and
* application deployments.
- *
+ *
* @author bratseth
*/
public class DeploymentApiHandler extends LoggingRequestHandler {
@@ -56,7 +60,7 @@ public class DeploymentApiHandler extends LoggingRequestHandler {
return ErrorResponse.internalServerError(Exceptions.toMessageString(e));
}
}
-
+
private HttpResponse handleGET(HttpRequest request) {
Path path = new Path(request.getUri().getPath());
if (path.matches("/deployment/v1/")) return root(request);
@@ -70,7 +74,7 @@ public class DeploymentApiHandler extends LoggingRequestHandler {
response.headers().put("Allow", "GET,OPTIONS");
return response;
}
-
+
private HttpResponse root(HttpRequest request) {
Slime slime = new Slime();
Cursor root = slime.setObject();
@@ -83,7 +87,7 @@ public class DeploymentApiHandler extends LoggingRequestHandler {
versionObject.setLong("date", version.releasedAt().toEpochMilli());
versionObject.setBool("controllerVersion", version.isSelfVersion());
versionObject.setBool("systemVersion", version.isCurrentSystemVersion());
-
+
Cursor configServerArray = versionObject.setArray("configServers");
for (String configServerHostnames : version.configServerHostnames()) {
Cursor configServerObject = configServerArray.addObject();
@@ -92,35 +96,50 @@ public class DeploymentApiHandler extends LoggingRequestHandler {
Cursor failingArray = versionObject.setArray("failingApplications");
for (ApplicationId id : version.statistics().failing()) {
- Optional<Application> application = controller.applications().get(id);
- if ( ! application.isPresent()) continue; // deleted just now
-
- Instant failingSince = application.get().deploymentJobs().failingSince();
- if (failingSince == null) continue; // started working just now
-
- Cursor applicationObject = failingArray.addObject();
- toSlime(application.get(), applicationObject, request);
- applicationObject.setLong("failingSince", failingSince.toEpochMilli());
+ controller.applications().get(id).ifPresent(application -> {
+ firstFailingOn(version.versionNumber(), application).ifPresent(firstFailing -> {
+ toSlime(failingArray.addObject(),
+ application,
+ firstFailing.firstFailing().get().upgrade(),
+ firstFailing.firstFailing().get().at().toEpochMilli(),
+ firstFailing.type().id(),
+ request);
+ });
+ });
}
Cursor productionArray = versionObject.setArray("productionApplications");
for (ApplicationId id : version.statistics().production()) {
- Optional<Application> application = controller.applications().get(id);
- if ( ! application.isPresent()) continue; // deleted just now
- toSlime(application.get(), productionArray.addObject(), request);
+ controller.applications().get(id).ifPresent(application -> {
+ lastProductionOn(version.versionNumber(), application).ifPresent(lastProduction -> {
+ toSlime(productionArray.addObject(),
+ application,
+ lastProduction.lastCompleted().get().upgrade(),
+ lastProduction.lastCompleted().get().at().toEpochMilli(),
+ lastProduction.type().id(),
+ request);
+ });
+ });
}
Cursor deployingArray = versionObject.setArray("deployingApplications");
for (ApplicationId id : version.statistics().deploying()) {
- Optional<Application> application = controller.applications().get(id);
- if ( ! application.isPresent()) continue; // deleted just now
- toSlime(application.get(), deployingArray.addObject(), request);
+ controller.applications().get(id).ifPresent(application -> {
+ lastDeployingTo(version.versionNumber(), application).ifPresent(lastDeploying -> {
+ toSlime(deployingArray.addObject(),
+ application,
+ lastDeploying.lastTriggered().get().upgrade(),
+ lastDeploying.lastTriggered().get().at().toEpochMilli(),
+ lastDeploying.type().id(),
+ request);
+ });
+ });
}
}
return new SlimeJsonResponse(slime);
}
- private void toSlime(Application application, Cursor object, HttpRequest request) {
+ private void toSlime(Cursor object, Application application, boolean upgrade, long at, String jobType, HttpRequest request) {
object.setString("tenant", application.id().tenant().value());
object.setString("application", application.id().application().value());
object.setString("instance", application.id().instance().value());
@@ -129,6 +148,9 @@ public class DeploymentApiHandler extends LoggingRequestHandler {
"/application/" +
application.id().application().value()).toString());
object.setString("upgradePolicy", toString(application.deploymentSpec().upgradePolicy()));
+ object.setBool("upgrade", upgrade);
+ object.setLong("at", at);
+ object.setString("jobType", jobType);
}
private static String toString(DeploymentSpec.UpgradePolicy upgradePolicy) {
@@ -138,4 +160,34 @@ public class DeploymentApiHandler extends LoggingRequestHandler {
return upgradePolicy.name();
}
+ // ----------------------------- Utilities to pick out the relevant JobRuns -- filter chains mirror the ones in VersionStatus
+
+ /** The first upgrade job to fail for this version x application */
+ private Optional<JobStatus> firstFailingOn(Version version, Application application) {
+ return application.deploymentJobs().jobStatus().values().stream()
+ .filter(jobStatus -> jobStatus.lastCompleted().isPresent())
+ .filter(jobStatus -> jobStatus.lastCompleted().get().upgrade())
+ .filter(jobStatus -> jobStatus.jobError().isPresent())
+ .filter(jobStatus -> jobStatus.jobError().get() != outOfCapacity)
+ .filter(jobStatus -> jobStatus.lastCompleted().get().version().equals(version))
+ .min(comparing(jobStatus -> jobStatus.lastCompleted().get().at()));
+ }
+
+ /** The last production job to succeed for this version x application */
+ private Optional<JobStatus> lastProductionOn(Version version, Application application) {
+ return application.deploymentJobs().jobStatus().values().stream()
+ .filter(jobStatus -> jobStatus.lastSuccess().isPresent())
+ .filter(jobStatus -> jobStatus.type().isProduction())
+ .filter(jobStatus -> jobStatus.lastSuccess().get().version().equals(version))
+ .max(comparing(jobStatus -> jobStatus.lastSuccess().get().at()));
+ }
+
+ /** The last deployment triggered for this version x application */
+ private Optional<JobStatus> lastDeployingTo(Version version, Application application) {
+ return application.deploymentJobs().jobStatus().values().stream()
+ .filter(jobStatus -> jobStatus.isRunning(controller.applications().deploymentTrigger().jobTimeoutLimit()))
+ .filter(jobStatus -> jobStatus.lastTriggered().get().version().equals(version))
+ .max(comparing(jobStatus -> jobStatus.lastTriggered().get().at()));
+ }
+
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/responses/root.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/responses/root.json
index c3968d53f85..d86596e2ca1 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/responses/root.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/responses/root.json
@@ -15,7 +15,10 @@
"application": "application1",
"instance": "default",
"url": "http://localhost:8080/application/v4/tenant/tenant1/application/application1",
- "upgradePolicy": "default"
+ "upgradePolicy": "default",
+ "upgrade": false,
+ "at": "(ignore)",
+ "jobType": "production-corp-us-east-1"
}
],
"deployingApplications": []
@@ -35,7 +38,9 @@
"instance": "default",
"url": "http://localhost:8080/application/v4/tenant/tenant1/application/application1",
"upgradePolicy": "default",
- "failingSince": "(ignore)"
+ "upgrade": true,
+ "at": "(ignore)",
+ "jobType": "staging-test"
}
],
"productionApplications": [
@@ -44,7 +49,10 @@
"application": "application2",
"instance": "default",
"url": "http://localhost:8080/application/v4/tenant/tenant2/application/application2",
- "upgradePolicy": "default"
+ "upgradePolicy": "default",
+ "upgrade": true,
+ "at": "(ignore)",
+ "jobType": "production-corp-us-east-1"
}
],
"deployingApplications": [
@@ -53,7 +61,10 @@
"application": "application1",
"instance": "default",
"url": "http://localhost:8080/application/v4/tenant/tenant1/application/application1",
- "upgradePolicy": "default"
+ "upgradePolicy": "default",
+ "upgrade": true,
+ "at": "(ignore)",
+ "jobType": "staging-test"
}
]
},