From bb576c41791e31d25e00b49c2b1e871b5d3d09c3 Mon Sep 17 00:00:00 2001 From: Jon Marius Venstad Date: Fri, 8 Nov 2019 10:31:23 +0100 Subject: Wrap Application and its JobStatuses in DeploymentStatus --- .../controller/deployment/DeploymentStatus.java | 49 ++++++++++++++++++++++ .../controller/deployment/DeploymentTrigger.java | 6 +-- .../controller/deployment/JobController.java | 16 ++++--- .../hosted/controller/deployment/JobList.java | 7 ++-- .../hosted/controller/deployment/Versions.java | 5 --- .../application/JobControllerApiHandlerHelper.java | 6 +-- 6 files changed, 67 insertions(+), 22 deletions(-) create mode 100644 controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java (limited to 'controller-server') diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java new file mode 100644 index 00000000000..1582bc144f4 --- /dev/null +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java @@ -0,0 +1,49 @@ +package com.yahoo.vespa.hosted.controller.deployment; + +import com.yahoo.config.provision.InstanceName; +import com.yahoo.vespa.hosted.controller.Application; +import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobId; +import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; + +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * Status of the deployment jobs of an {@link Application}. + * + * @author jonmv + */ +public class DeploymentStatus { + + private final Application application; + private final Map jobs; + + public DeploymentStatus(Application application, Map jobs) { + this.application = Objects.requireNonNull(application); + this.jobs = Map.copyOf(jobs); + } + + public Application application() { + return application; + } + + public Map jobs() { + return jobs; + } + + public boolean hasFailures() { + return ! JobList.from(jobs.values()) + .failing() + .not().withStatus(RunStatus.outOfCapacity) + .isEmpty(); + } + + public Map instanceJobs(InstanceName instance) { + return jobs.entrySet().stream() + .filter(entry -> entry.getKey().application().equals(application.id().instance(instance))) + .collect(Collectors.toUnmodifiableMap(entry -> entry.getKey().type(), + entry -> entry.getValue())); + } + +} diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java index ae7ff81c001..f1b93c7b3b2 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java @@ -12,7 +12,6 @@ import com.yahoo.vespa.hosted.controller.ApplicationController; import com.yahoo.vespa.hosted.controller.Controller; import com.yahoo.vespa.hosted.controller.Instance; import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId; -import com.yahoo.vespa.hosted.controller.api.identifiers.InstanceId; import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion; import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobId; import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; @@ -205,7 +204,7 @@ public class DeploymentTrigger { Versions versions = Versions.from(application.change(), application, deploymentFor(instance, jobType), controller.systemVersion()); String reason = "Job triggered manually by " + user; - var jobStatus = jobs.jobStatus(applicationId, application.deploymentSpec()); + var jobStatus = jobs.deploymentStatus(application).instanceJobs(instance.name()); return (jobType.isProduction() && ! isTested(jobStatus, versions) ? testJobs(application.deploymentSpec(), application.change(), instance, jobStatus, versions, reason, clock.instant(), __ -> true).stream() : Stream.of(deploymentJob(instance, versions, application.change(), jobType, jobStatus.get(jobType), reason, clock.instant()))) @@ -299,8 +298,9 @@ public class DeploymentTrigger { Collection instances = application.deploymentSpec().instances().stream() .flatMap(instance -> application.get(instance.name()).stream()) .collect(Collectors.toUnmodifiableList()); + DeploymentStatus deploymentStatus = this.jobs.deploymentStatus(application); for (Instance instance : instances) { - var jobStatus = this.jobs.jobStatus(instance.id(), application.deploymentSpec()); + var jobStatus = deploymentStatus.instanceJobs(instance.name()); Change change = application.change(); Optional completedAt = max(Optional.ofNullable(jobStatus.get(systemTest)) .flatMap(job -> job.lastSuccess().map(run -> run.end().get())), diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java index 331327117b5..e6c59b464a6 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java @@ -4,6 +4,7 @@ package com.yahoo.vespa.hosted.controller.deployment; import com.yahoo.component.Version; import com.yahoo.config.application.api.DeploymentSpec; import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.InstanceName; import com.yahoo.config.provision.zone.ZoneId; import com.yahoo.vespa.curator.Lock; import com.yahoo.vespa.hosted.controller.Application; @@ -54,6 +55,7 @@ import static com.yahoo.vespa.hosted.controller.deployment.Step.deactivateTester import static com.yahoo.vespa.hosted.controller.deployment.Step.endTests; import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toUnmodifiableList; +import static java.util.stream.Collectors.toUnmodifiableMap; /** * A singleton owned by the controller, which contains the state and methods for controlling deployment jobs. @@ -286,12 +288,14 @@ public class JobController { } /** Returns the job status of all declared jobs for the given instance id, indexed by job type. */ - public Map jobStatus(ApplicationId id, DeploymentSpec spec) { - return new DeploymentSteps(spec.requireInstance(id.instance()), controller::system) - .jobs().stream() - .map(type -> jobStatus(new JobId(id, type))) - .collect(Collectors.toUnmodifiableMap(status -> status.id().type(), - status -> status)); + public DeploymentStatus deploymentStatus(Application application) { + return new DeploymentStatus(application, + application.deploymentSpec().instances().stream() + .flatMap(spec -> new DeploymentSteps(spec, controller::system) + .jobs().stream() + .map(type -> jobStatus(new JobId(application.id().instance(spec.name()), type)))) + .collect(toUnmodifiableMap(status -> status.id(), + status -> status))); } /** Changes the status of the given step, for the given run, provided it is still active. */ diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobList.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobList.java index 973b718a4c6..1ef83153bef 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobList.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobList.java @@ -8,6 +8,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; import java.time.Instant; import java.util.Collection; +import java.util.List; import java.util.Optional; import java.util.function.Function; import java.util.function.Predicate; @@ -33,7 +34,7 @@ public class JobList extends AbstractFilteringList { /** Returns the subset of jobs which are currently upgrading */ public JobList upgrading() { - return matching(job -> job.isRunning() + return matching(job -> job.isRunning() && job.lastSuccess().isPresent() && job.lastSuccess().get().versions().targetPlatform().isBefore(job.lastTriggered().get().versions().targetPlatform())); } @@ -54,8 +55,8 @@ public class JobList extends AbstractFilteringList { } /** Returns the subset of jobs of the given type -- most useful when negated */ - public JobList type(JobType type) { - return matching(job -> job.id().type() == type); + public JobList type(JobType... types) { + return matching(job -> List.of(types).contains(job.id().type())); } /** Returns the subset of jobs of which are production jobs */ diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/Versions.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/Versions.java index 5d4a380411d..b2b217d0814 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/Versions.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/Versions.java @@ -80,11 +80,6 @@ public class Versions { targetApplication.equals(versions.targetApplication()); } - public boolean targetsMatch(JobStatus.JobRun jobRun) { - return targetPlatform.equals(jobRun.platform()) && - targetApplication.equals(jobRun.application()); - } - @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelper.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelper.java index 899eb546bca..9a9a9798c6d 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelper.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelper.java @@ -16,7 +16,6 @@ import com.yahoo.vespa.hosted.controller.Controller; import com.yahoo.vespa.hosted.controller.NotExistsException; import com.yahoo.vespa.hosted.controller.api.integration.LogEntry; import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion; -import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobId; import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId; import com.yahoo.vespa.hosted.controller.api.integration.deployment.SourceRevision; @@ -40,13 +39,10 @@ import java.net.URI; import java.util.ArrayDeque; import java.util.Comparator; import java.util.Deque; -import java.util.HashMap; -import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; import java.util.stream.Collectors; import static com.yahoo.config.application.api.DeploymentSpec.UpgradePolicy.conservative; @@ -81,7 +77,7 @@ class JobControllerApiHandlerHelper { Instance instance = application.require(id.instance()); Change change = application.change(); DeploymentSteps steps = new DeploymentSteps(application.deploymentSpec().requireInstance(id.instance()), controller::system); - Map status = controller.jobController().jobStatus(id, application.deploymentSpec()); + Map status = controller.jobController().deploymentStatus(application).instanceJobs(id.instance()); // The logic for pending runs imitates DeploymentTrigger logic; not good, but the trigger wiring must be re-written to reuse :S Map pendingProduction = -- cgit v1.2.3