summaryrefslogtreecommitdiffstats
path: root/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java
diff options
context:
space:
mode:
Diffstat (limited to 'controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java103
1 files changed, 59 insertions, 44 deletions
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 80a325e3dc8..0006845b888 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
@@ -57,6 +57,7 @@ import static java.util.Optional.empty;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.partitioningBy;
+import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
/**
@@ -226,17 +227,21 @@ public class DeploymentTrigger {
&& buildService.isRunning(BuildJob.of(application.id(), application.deploymentJobs().projectId().getAsLong(), jobType.jobName()));
}
- public void forceTrigger(ApplicationId applicationId, JobType jobType) {
+ public List<JobType> forceTrigger(ApplicationId applicationId, JobType jobType) {
Application application = applications().require(applicationId);
if (jobType == component) {
buildService.trigger(BuildJob.of(applicationId, application.deploymentJobs().projectId().getAsLong(), jobType.jobName()));
- return;
+ return singletonList(component);
}
State target = targetFor(application, application.change(), jobType);
- if (isVerified(application, target, jobType))
- trigger(deploymentJob(application, target, application.change(), jobType, ">:o:< Triggered by force! (-o-) |-o-| (=oo=) ", clock.instant(), Collections.emptySet()));
- else
- ; // TODO jvenstad: Test it!
+ String reason = ">:o:< Triggered by force! (-o-) |-o-| (=oo=)";
+ if (isVerified(application, target, jobType)) {
+ trigger(deploymentJob(application, target, application.change(), jobType, reason, clock.instant(), Collections.emptySet()));
+ return singletonList(jobType);
+ }
+ List<Job> testJobs = testJobsFor(application, target, reason, clock.instant());
+ testJobs.forEach(this::trigger);
+ return testJobs.stream().map(Job::jobType).collect(toList());
}
private Job deploymentJob(Application application, State target, Change change, JobType jobType, String reason, Instant availableSince, Collection<JobType> concurrentlyWith) {
@@ -267,26 +272,38 @@ public class DeploymentTrigger {
* Finds the next step to trigger for the given application, if any, and returns these as a list.
*/
private List<Job> computeReadyJobs(ApplicationId id) {
+ /*
+ find testJobs
+ find productionSteps
+
+ completedAt = EPOCH
+
+
+
+
+
+
+
+
+
+
+ */
+
+
+
+
+
List<Job> jobs = new ArrayList<>();
applications().get(id).ifPresent(application -> {
List<Step> steps = application.deploymentSpec().steps().isEmpty()
? singletonList(new DeploymentSpec.DeclaredZone(test))
: application.deploymentSpec().steps();
- List<Step> productionSteps = new ArrayList<>(steps);
- productionSteps.removeIf(step -> ! step.deploysTo(prod) && ! step.zones().isEmpty());
- List<Step> testSteps = new ArrayList<>(steps);
- testSteps.removeAll(productionSteps);
+ List<Step> productionSteps = steps.stream().filter(step -> step.deploysTo(prod) || step.zones().isEmpty()).collect(toList());
- boolean complete = ! productionSteps.isEmpty();
- Optional<Instant> completedAt = application.deploymentJobs().statusOf(stagingTest).flatMap(JobStatus::lastSuccess).map(JobRun::at);
+ Optional<Instant> completedAt = Optional.of(Instant.EPOCH); // Delays before first production job are ignored.
String reason = "New change available";
- State testTarget = null;
- Instant testAvailableSince = null;
- JobType testFor = null;
+ List<Job> testJobs = null;
- // Loop through all production steps and find
- // a) any incomplete and ready production jobs which are already verified, and / or
- // b) any tests which are required to verify the first incomplete production job
for (Step step : productionSteps) {
Set<JobType> stepJobs = step.zones().stream().map(order::toJob).collect(toSet());
Map<Optional<Instant>, List<JobType>> jobsByCompletion = stepJobs.stream().collect(groupingBy(job -> completedAt(application.change(), application, job)));
@@ -297,16 +314,9 @@ public class DeploymentTrigger {
if (completedAt.isPresent())
jobs.add(deploymentJob(application, target, application.change(), job, reason, completedAt.get(), stepJobs));
}
- else if (testTarget == null) {
- testTarget = target;
- testAvailableSince = completedAt.orElse(clock.instant());
- testFor = job;
- }
+ else if (testJobs == null)
+ testJobs = testJobsFor(application, target, "Testing deployment for " + job.jobName(), completedAt.orElse(clock.instant()));
}
-
- complete = false;
- completedAt = empty();
- break;
}
else { // All jobs are complete -- find the time of completion of this step.
if (stepJobs.isEmpty()) { // No jobs means this is delay step.
@@ -321,29 +331,34 @@ public class DeploymentTrigger {
}
}
- if (productionSteps.isEmpty()) {
- testTarget = targetFor(application, application.change(), systemTest);
- testFor = systemTest;
- testAvailableSince = clock.instant();
- }
- if (testTarget != null)
- for (Step step : testSteps) {
- for (JobType jobType : step.zones().stream().map(order::toJob).collect(Collectors.toList())) {
- Optional<JobRun> completion = successOn(application, jobType, testTarget.targetPlatform, testTarget.targetApplication);
- if (completion.isPresent())
- testAvailableSince = completion.get().at();
- else if (isVerified(application, testTarget, jobType))
- jobs.add(deploymentJob(application, testTarget, application.change(), jobType, "Testing deployment for " + testFor.jobName(), testAvailableSince, emptySet()));
- }
- }
+ if (testJobs == null)
+ testJobs = testJobsFor(application, targetFor(application, application.change(), systemTest), "Testing last changes outside prod", clock.instant());
+ jobs.addAll(testJobs);
// TODO jvenstad: Replace with completion of individual parts of Change.
- if (complete)
+ if (steps.stream().flatMap(step -> step.zones().stream()).map(order::toJob)
+ .allMatch(job -> completedAt(application.change(), application, job).isPresent()))
applications().lockIfPresent(id, lockedApplication -> applications().store(lockedApplication.withChange(Change.empty())));
});
return jobs;
}
+ private List<Job> testJobsFor(Application application, State target, String reason, Instant availableSince) {
+ List<Step> steps = application.deploymentSpec().steps();
+ if (steps.isEmpty()) steps = singletonList(new DeploymentSpec.DeclaredZone(test));
+ List<Job> jobs = new ArrayList<>();
+ for (Step step : steps.stream().filter(step -> step.deploysTo(test) || step.deploysTo(staging)).collect(toList())) {
+ for (JobType jobType : step.zones().stream().map(order::toJob).collect(toList())) {
+ Optional<JobRun> completion = successOn(application, jobType, target.targetPlatform, target.targetApplication);
+ if (completion.isPresent())
+ availableSince = completion.get().at();
+ else if (isVerified(application, target, jobType))
+ jobs.add(deploymentJob(application, target, application.change(), jobType, reason, availableSince, emptySet()));
+ }
+ }
+ return jobs;
+ }
+
private boolean isVerified(Application application, State state, JobType jobType) {
if (jobType.environment() == staging)
return successOn(application, systemTest, state.targetPlatform, state.targetApplication).isPresent();
@@ -403,7 +418,7 @@ public class DeploymentTrigger {
return application.deploymentJobs().jobStatus().keySet().parallelStream()
.filter(job -> job.isProduction())
.filter(job -> isRunning(application, job))
- .collect(Collectors.toList());
+ .collect(toList());
}
private ApplicationController applications() {