diff options
author | Jon Marius Venstad <jvenstad@yahoo-inc.com> | 2017-11-02 16:17:19 +0100 |
---|---|---|
committer | Jon Marius Venstad <jvenstad@yahoo-inc.com> | 2017-11-02 16:17:19 +0100 |
commit | dc8e0d42ec88d63c1f95766d57d1c7d2ed3a4f1a (patch) | |
tree | d14ab7df64d89404f0fc7cc6d30f687d33ac0342 | |
parent | 2f44386e16d6b130cebbdfff807ce4bcc8fad5a1 (diff) |
Add relevant job info to application blobs
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" } ] }, |