diff options
author | Jon Marius Venstad <venstad@gmail.com> | 2020-01-02 12:49:54 +0100 |
---|---|---|
committer | Jon Marius Venstad <venstad@gmail.com> | 2020-01-07 15:28:23 +0100 |
commit | b2d9b9b58d16c618b47b2932ef1fc85b89c8ce51 (patch) | |
tree | 93ad38aeaabb3f644f4fc6a0b2f1cdb9ed631823 /controller-server | |
parent | 95efcfd4d165b064c7c60284ded1df7d481c6132 (diff) |
Compute outstanding change, instead of keeping it in sync
Diffstat (limited to 'controller-server')
12 files changed, 88 insertions, 112 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Application.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Application.java index c75f3102772..b962b260bf9 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Application.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Application.java @@ -46,7 +46,6 @@ public class Application { private final Optional<ApplicationVersion> latestVersion; private final OptionalLong projectId; private final Change change; - private final Change outstandingChange; private final Optional<IssueId> deploymentIssueId; private final Optional<IssueId> ownershipIssueId; private final Optional<User> owner; @@ -57,14 +56,14 @@ public class Application { /** Creates an empty application. */ public Application(TenantAndApplicationId id, Instant now) { - this(id, now, DeploymentSpec.empty, ValidationOverrides.empty, Change.empty(), Change.empty(), + this(id, now, DeploymentSpec.empty, ValidationOverrides.empty, Change.empty(), Optional.empty(), Optional.empty(), Optional.empty(), OptionalInt.empty(), new ApplicationMetrics(0, 0), Set.of(), OptionalLong.empty(), Optional.empty(), List.of()); } // DO NOT USE! For serialization purposes, only. public Application(TenantAndApplicationId id, Instant createdAt, DeploymentSpec deploymentSpec, ValidationOverrides validationOverrides, - Change change, Change outstandingChange, Optional<IssueId> deploymentIssueId, Optional<IssueId> ownershipIssueId, Optional<User> owner, + Change change, Optional<IssueId> deploymentIssueId, Optional<IssueId> ownershipIssueId, Optional<User> owner, OptionalInt majorVersion, ApplicationMetrics metrics, Set<PublicKey> deployKeys, OptionalLong projectId, Optional<ApplicationVersion> latestVersion, Collection<Instance> instances) { this.id = Objects.requireNonNull(id, "id cannot be null"); @@ -72,7 +71,6 @@ public class Application { this.deploymentSpec = Objects.requireNonNull(deploymentSpec, "deploymentSpec cannot be null"); this.validationOverrides = Objects.requireNonNull(validationOverrides, "validationOverrides cannot be null"); this.change = Objects.requireNonNull(change, "change cannot be null"); - this.outstandingChange = Objects.requireNonNull(outstandingChange, "outstandingChange cannot be null"); this.deploymentIssueId = Objects.requireNonNull(deploymentIssueId, "deploymentIssueId cannot be null"); this.ownershipIssueId = Objects.requireNonNull(ownershipIssueId, "ownershipIssueId cannot be null"); this.owner = Objects.requireNonNull(owner, "owner cannot be null"); @@ -124,12 +122,6 @@ public class Application { */ public Change change() { return change; } - /** - * Returns whether this has an outstanding change (in the source repository), which - * has currently not started deploying (because a deployment is (or was) already in progress - */ - public Change outstandingChange() { return outstandingChange; } - /** Returns ID of any open deployment issue filed for this */ public Optional<IssueId> deploymentIssueId() { return deploymentIssueId; diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedApplication.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedApplication.java index fa81a990c70..09666110f70 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedApplication.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedApplication.java @@ -37,7 +37,6 @@ public class LockedApplication { private final DeploymentSpec deploymentSpec; private final ValidationOverrides validationOverrides; private final Change change; - private final Change outstandingChange; private final Optional<IssueId> deploymentIssueId; private final Optional<IssueId> ownershipIssueId; private final Optional<User> owner; @@ -57,13 +56,13 @@ public class LockedApplication { LockedApplication(Application application, Lock lock) { this(Objects.requireNonNull(lock, "lock cannot be null"), application.id(), application.createdAt(), application.deploymentSpec(), application.validationOverrides(), application.change(), - application.outstandingChange(), application.deploymentIssueId(), application.ownershipIssueId(), + application.deploymentIssueId(), application.ownershipIssueId(), application.owner(), application.majorVersion(), application.metrics(), application.deployKeys(), application.projectId(), application.latestVersion(), application.instances()); } private LockedApplication(Lock lock, TenantAndApplicationId id, Instant createdAt, DeploymentSpec deploymentSpec, - ValidationOverrides validationOverrides, Change change, Change outstandingChange, + ValidationOverrides validationOverrides, Change change, Optional<IssueId> deploymentIssueId, Optional<IssueId> ownershipIssueId, Optional<User> owner, OptionalInt majorVersion, ApplicationMetrics metrics, Set<PublicKey> deployKeys, OptionalLong projectId, Optional<ApplicationVersion> latestVersion, @@ -74,7 +73,6 @@ public class LockedApplication { this.deploymentSpec = deploymentSpec; this.validationOverrides = validationOverrides; this.change = change; - this.outstandingChange = outstandingChange; this.deploymentIssueId = deploymentIssueId; this.ownershipIssueId = ownershipIssueId; this.owner = owner; @@ -88,7 +86,7 @@ public class LockedApplication { /** Returns a read-only copy of this */ public Application get() { - return new Application(id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, + return new Application(id, createdAt, deploymentSpec, validationOverrides, change, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, deployKeys, projectId, latestVersion, instances.values()); } @@ -96,7 +94,7 @@ public class LockedApplication { public LockedApplication withNewInstance(InstanceName instance) { var instances = new HashMap<>(this.instances); instances.put(instance, new Instance(id.instance(instance))); - return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, + return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, deployKeys, projectId, latestVersion, instances); } @@ -104,7 +102,7 @@ public class LockedApplication { public LockedApplication with(InstanceName instance, UnaryOperator<Instance> modification) { var instances = new HashMap<>(this.instances); instances.put(instance, modification.apply(instances.get(instance))); - return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, + return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, deployKeys, projectId, latestVersion, instances); } @@ -112,75 +110,69 @@ public class LockedApplication { public LockedApplication without(InstanceName instance) { var instances = new HashMap<>(this.instances); instances.remove(instance); - return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, + return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, deployKeys, projectId, latestVersion, instances); } public LockedApplication withNewSubmission(ApplicationVersion latestVersion) { - return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, + return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, deployKeys, projectId, Optional.of(latestVersion), instances); } public LockedApplication withProjectId(OptionalLong projectId) { - return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, + return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, deployKeys, projectId, latestVersion, instances); } public LockedApplication withDeploymentIssueId(IssueId issueId) { - return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, + return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, Optional.ofNullable(issueId), ownershipIssueId, owner, majorVersion, metrics, deployKeys, projectId, latestVersion, instances); } public LockedApplication with(DeploymentSpec deploymentSpec) { - return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, + return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, deployKeys, projectId, latestVersion, instances); } public LockedApplication with(ValidationOverrides validationOverrides) { - return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, + return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, deployKeys, projectId, latestVersion, instances); } public LockedApplication withChange(Change change) { - return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, - deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, deployKeys, - projectId, latestVersion, instances); - } - - public LockedApplication withOutstandingChange(Change outstandingChange) { - return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, + return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, deployKeys, projectId, latestVersion, instances); } public LockedApplication withOwnershipIssueId(IssueId issueId) { - return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, + return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, deploymentIssueId, Optional.of(issueId), owner, majorVersion, metrics, deployKeys, projectId, latestVersion, instances); } public LockedApplication withOwner(User owner) { - return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, + return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, deploymentIssueId, ownershipIssueId, Optional.of(owner), majorVersion, metrics, deployKeys, projectId, latestVersion, instances); } /** Set a major version for this, or set to null to remove any major version override */ public LockedApplication withMajorVersion(Integer majorVersion) { - return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, + return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, deploymentIssueId, ownershipIssueId, owner, majorVersion == null ? OptionalInt.empty() : OptionalInt.of(majorVersion), metrics, deployKeys, projectId, latestVersion, instances); } public LockedApplication with(ApplicationMetrics metrics) { - return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, + return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, deployKeys, projectId, latestVersion, instances); } @@ -188,7 +180,7 @@ public class LockedApplication { public LockedApplication withDeployKey(PublicKey pemDeployKey) { Set<PublicKey> keys = new LinkedHashSet<>(deployKeys); keys.add(pemDeployKey); - return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, + return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, keys, projectId, latestVersion, instances); } @@ -196,7 +188,7 @@ public class LockedApplication { public LockedApplication withoutDeployKey(PublicKey pemDeployKey) { Set<PublicKey> keys = new LinkedHashSet<>(deployKeys); keys.remove(pemDeployKey); - return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, + return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, keys, projectId, latestVersion, instances); } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationList.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationList.java index 7926531d1fa..e82029e53bf 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationList.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationList.java @@ -49,11 +49,6 @@ public class ApplicationList extends AbstractFilteringList<Application, Applicat // ----------------------------------- Filters - /** Returns the subset of applications which have changes left to deploy; blocked, or deploying */ - public ApplicationList withChanges() { - return matching(application -> application.change().hasTargets() || application.outstandingChange().hasTargets()); - } - /** Returns the subset of applications which are currently deploying a change */ public ApplicationList deploying() { return matching(application -> application.change().hasTargets()); 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 index e574b994870..6948e1f1dd0 100644 --- 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 @@ -120,11 +120,11 @@ public class DeploymentStatus { /** Returns the set of jobs that need to run for the application's current change to be considered complete. */ public Map<JobId, List<Versions>> jobsToRun() { Map<JobId, List<Versions>> jobs = jobsToRun(application().change()); - if (application.outstandingChange().isEmpty()) + if (outstandingChange().isEmpty()) return jobs; // Add test jobs for any outstanding change. - var testJobs = jobsToRun(application.outstandingChange().onTopOf(application.change())) + var testJobs = jobsToRun(outstandingChange().onTopOf(application.change())) .entrySet().stream() .filter(entry -> ! entry.getKey().type().isProduction()); @@ -155,16 +155,27 @@ public class DeploymentStatus { } /** + * Returns the change of this application's latest submission, if this upgrades any of its production deployments, + * and has not yet started rolling out, due to some other change or a block window being present at the time of submission. + */ + public Change outstandingChange() { + return application.latestVersion().map(Change::of) + .filter(change -> application.change().application().map(change::upgrades).orElse(true)) + .filter(change -> ! jobsToRun(change).isEmpty()) + .orElse(Change.empty()); + } + + /** * True if the job has already been triggered on the given versions, or if all test types (systemTest, stagingTest), * restricted to the job's instance if declared in that instance, have successful runs on the given versions. */ public boolean isTested(JobId job, Versions versions) { return allJobs.triggeredOn(versions).get(job).isPresent() - || Stream.of(systemTest, stagingTest) - .noneMatch(testType -> declaredTest(job.application(), testType).map(__ -> allJobs.instance(job.application().instance())) - .orElse(allJobs) - .type(testType) - .successOn(versions).isEmpty()); + || Stream.of(systemTest, stagingTest) + .noneMatch(testType -> declaredTest(job.application(), testType).map(__ -> allJobs.instance(job.application().instance())) + .orElse(allJobs) + .type(testType) + .successOn(versions).isEmpty()); } public Map<JobId, Versions> productionJobs(Change change) { diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatusList.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatusList.java index 6f4d947a3c5..c3f6947ee4a 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatusList.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatusList.java @@ -79,7 +79,7 @@ public class DeploymentStatusList extends AbstractFilteringList<DeploymentStatus /** Returns the subset of applications which have changes left to deploy; blocked, or deploying */ public DeploymentStatusList withChanges() { - return matching(status -> status.application().change().hasTargets() || status.application().outstandingChange().hasTargets()); + return matching(status -> status.application().change().hasTargets() || status.outstandingChange().hasTargets()); } /** Returns the subset of applications which are currently deploying a change */ 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 1e02c9751d4..dfd25c57e70 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 @@ -81,14 +81,11 @@ public class DeploymentTrigger { applications().lockApplicationOrThrow(id, application -> { if (acceptNewApplicationVersion(application.get())) { - application = application.withChange(application.get().change().with(version)) - .withOutstandingChange(Change.empty()); + application = application.withChange(application.get().change().with(version)); for (Run run : jobs.active(id)) if ( ! run.id().type().environment().isManuallyDeployed()) jobs.abort(run.id()); } - else - application = application.withOutstandingChange(Change.of(version)); application = application.withProjectId(OptionalLong.of(projectId)); application = application.withNewSubmission(version); @@ -191,8 +188,6 @@ public class DeploymentTrigger { /** Overrides the given application's platform and application changes with any contained in the given change. */ public void forceChange(TenantAndApplicationId applicationId, Change change) { applications().lockApplicationOrThrow(applicationId, application -> { - if (change.application().isPresent()) - application = application.withOutstandingChange(Change.empty()); applications().store(application.withChange(change.onTopOf(application.get().change()))); }); } @@ -229,49 +224,45 @@ public class DeploymentTrigger { /** Returns the set of all jobs which have changes to propagate from the upstream steps. */ private List<Job> computeReadyJobs() { - return ApplicationList.from(applications().asList()) - .withProjectId() // Need to keep this, as we have applications with deployment spec that shouldn't be orchestrated. - .withChanges() - .withDeploymentSpec() - .idList().stream() - .map(this::computeReadyJobs) - .flatMap(Collection::stream) - .collect(toList()); + return jobs.deploymentStatuses(ApplicationList.from(applications().asList()) + .withProjectId() // Need to keep this, as we have applications with deployment spec that shouldn't be orchestrated. + .withDeploymentSpec()) + .withChanges() + .asList().stream() + .map(this::computeReadyJobs) + .flatMap(Collection::stream) + .collect(toList()); } /** * Finds the next step to trigger for the given application, if any, and returns these as a list. */ - private List<Job> computeReadyJobs(TenantAndApplicationId id) { + private List<Job> computeReadyJobs(DeploymentStatus status) { List<Job> jobs = new ArrayList<>(); - applications().getApplication(id).map(controller.jobController()::deploymentStatus).ifPresent(status -> { - status.jobsToRun().forEach((job, versionsList) -> { - for (Versions versions : versionsList) - status.jobSteps().get(job).readyAt(status.application().change(), versions) - .filter(readyAt -> ! clock.instant().isBefore(readyAt)) - .ifPresent(readyAt -> { - if ( ! ( isSuspendedInAnotherZone(status.application().require(job.application().instance()), - job.type().zone(controller.system())) - && job.type().environment() == Environment.prod) - && ! status.jobs().get(job).get().isRunning()) - jobs.add(deploymentJob(status.application().require(job.application().instance()), - versions, - status.application().change(), - job.type(), - status.instanceJobs(job.application().instance()).get(job.type()), - "unknown reason", - readyAt)); - }); + status.jobsToRun().forEach((job, versionsList) -> { + for (Versions versions : versionsList) + status.jobSteps().get(job).readyAt(status.application().change(), versions) + .filter(readyAt -> ! clock.instant().isBefore(readyAt)) + .filter(__ -> ! status.jobs().get(job).get().isRunning()) + .filter(__ -> ! (job.type().isProduction() && isSuspendedInAnotherZone(status.application(), job))) + .ifPresent(readyAt -> { + jobs.add(deploymentJob(status.application().require(job.application().instance()), + versions, + status.application().change(), + job.type(), + status.instanceJobs(job.application().instance()).get(job.type()), + "unknown reason", + readyAt)); }); }); return Collections.unmodifiableList(jobs); } /** Returns whether given job should be triggered */ - private boolean isSuspendedInAnotherZone(Instance instance, ZoneId zone) { - for (Deployment deployment : instance.productionDeployments().values()) { - if ( ! deployment.zone().equals(zone) - && controller.applications().isSuspended(new DeploymentId(instance.id(), deployment.zone()))) + private boolean isSuspendedInAnotherZone(Application application, JobId job) { + for (Deployment deployment : application.require(job.application().instance()).productionDeployments().values()) { + if ( ! deployment.zone().equals(job.type().zone(controller.system())) + && controller.applications().isSuspended(new DeploymentId(job.application(), deployment.zone()))) return true; } return false; diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployer.java index b130f7107dd..d398012a71b 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployer.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployer.java @@ -4,6 +4,7 @@ package com.yahoo.vespa.hosted.controller.maintenance; import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.Instance; import com.yahoo.vespa.hosted.controller.Controller; +import com.yahoo.vespa.hosted.controller.application.Change; import java.time.Duration; @@ -21,11 +22,11 @@ public class OutstandingChangeDeployer extends Maintainer { @Override protected void maintain() { for (Application application : controller().applications().asList()) { - if ( application.outstandingChange().hasTargets() + Change change = controller().jobController().deploymentStatus(application).outstandingChange(); + if ( change.hasTargets() && application.deploymentSpec().instances().stream() .allMatch(instance -> instance.canChangeRevisionAt(controller().clock().instant()))) { - controller().applications().deploymentTrigger().triggerChange(application.id(), - application.outstandingChange()); + controller().applications().deploymentTrigger().triggerChange(application.id(), change); } } } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializer.java index 6c500ff6402..4d6c21fcd1f 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializer.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializer.java @@ -83,7 +83,6 @@ public class ApplicationSerializer { private static final String projectIdField = "projectId"; private static final String latestVersionField = "latestVersion"; private static final String pinnedField = "pinned"; - private static final String outstandingChangeField = "outstandingChangeField"; private static final String deploymentIssueField = "deploymentIssueId"; private static final String ownershipIssueIdField = "ownershipIssueId"; private static final String ownerField = "confirmedOwner"; @@ -175,7 +174,6 @@ public class ApplicationSerializer { application.deploymentIssueId().ifPresent(jiraIssueId -> root.setString(deploymentIssueField, jiraIssueId.value())); application.ownershipIssueId().ifPresent(issueId -> root.setString(ownershipIssueIdField, issueId.value())); toSlime(application.change(), root, deployingField); - toSlime(application.outstandingChange(), root, outstandingChangeField); application.owner().ifPresent(owner -> root.setString(ownerField, owner.username())); application.majorVersion().ifPresent(majorVersion -> root.setLong(majorVersionField, majorVersion)); root.setDouble(queryQualityField, application.metrics().queryServiceQuality()); @@ -339,7 +337,6 @@ public class ApplicationSerializer { DeploymentSpec deploymentSpec = DeploymentSpec.fromXml(root.field(deploymentSpecField).asString(), false); ValidationOverrides validationOverrides = ValidationOverrides.fromXml(root.field(validationOverridesField).asString()); Change deploying = changeFromSlime(root.field(deployingField)); - Change outstandingChange = changeFromSlime(root.field(outstandingChangeField)); Optional<IssueId> deploymentIssueId = Serializers.optionalString(root.field(deploymentIssueField)).map(IssueId::from); Optional<IssueId> ownershipIssueId = Serializers.optionalString(root.field(ownershipIssueIdField)).map(IssueId::from); Optional<User> owner = Serializers.optionalString(root.field(ownerField)).map(User::from); @@ -351,7 +348,7 @@ public class ApplicationSerializer { OptionalLong projectId = Serializers.optionalLong(root.field(projectIdField)); Optional<ApplicationVersion> latestVersion = latestVersionFromSlime(root.field(latestVersionField)); - return new Application(id, createdAt, deploymentSpec, validationOverrides, deploying, outstandingChange, + return new Application(id, createdAt, deploymentSpec, validationOverrides, deploying, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, deployKeys, projectId, latestVersion, instances); } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java index 0f92ecde133..ec5392f1224 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java @@ -699,6 +699,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler { "/job/", request.getUri()).toString()); + DeploymentStatus status = controller.jobController().deploymentStatus(application); application.latestVersion().ifPresent(version -> toSlime(version, object.setObject("latestVersion"))); application.projectId().ifPresent(id -> object.setLong("projectId", id)); @@ -708,15 +709,14 @@ public class ApplicationApiHandler extends LoggingRequestHandler { toSlime(object.setObject("deploying"), application.change()); // Outstanding change - if ( ! application.outstandingChange().isEmpty()) - toSlime(object.setObject("outstandingChange"), application.outstandingChange()); + if ( ! status.outstandingChange().isEmpty()) + toSlime(object.setObject("outstandingChange"), status.outstandingChange()); // Compile version. The version that should be used when building an application object.setString("compileVersion", compileVersion(application.id()).toFullString()); application.majorVersion().ifPresent(majorVersion -> object.setLong("majorVersion", majorVersion)); - DeploymentStatus status = controller.jobController().deploymentStatus(application); Cursor instancesArray = object.setArray("instances"); for (Instance instance : application.instances().values()) toSlime(instancesArray.addObject(), status, instance, application.deploymentSpec(), request); @@ -855,8 +855,8 @@ public class ApplicationApiHandler extends LoggingRequestHandler { } // Outstanding change - if ( ! application.outstandingChange().isEmpty()) { - toSlime(object.setObject("outstandingChange"), application.outstandingChange()); + if ( ! status.outstandingChange().isEmpty()) { + toSlime(object.setObject("outstandingChange"), status.outstandingChange()); } if (application.deploymentSpec().instance(instance.name()).isPresent()) { diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java index c3739f037c9..8cd938dccf6 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java @@ -292,11 +292,11 @@ public class DeploymentTriggerTest { assertEquals(0, tester.jobs().active().size()); app.submit(applicationPackage); - assertTrue(app.application().outstandingChange().hasTargets()); + assertTrue(app.deploymentStatus().outstandingChange().hasTargets()); app.runJob(systemTest).runJob(stagingTest); tester.outstandingChangeDeployer().run(); - assertTrue(app.application().outstandingChange().hasTargets()); + assertTrue(app.deploymentStatus().outstandingChange().hasTargets()); tester.triggerJobs(); assertEquals(emptyList(), tester.jobs().active()); @@ -304,7 +304,7 @@ public class DeploymentTriggerTest { tester.clock().advance(Duration.ofHours(2)); // ---------------- Exit block window: 20:30 tester.outstandingChangeDeployer().run(); - assertFalse(app.application().outstandingChange().hasTargets()); + assertFalse(app.deploymentStatus().outstandingChange().hasTargets()); tester.triggerJobs(); // Tests already run for the blocked production job. app.assertRunning(productionUsWest1); @@ -337,7 +337,7 @@ public class DeploymentTriggerTest { tester.outstandingChangeDeployer().run(); app.runJob(productionUsWest1); assertEquals(1, app.instanceJobs().get(productionUsWest1).lastSuccess().get().versions().targetApplication().buildNumber().getAsLong()); - assertEquals(2, app.application().outstandingChange().application().get().buildNumber().getAsLong()); + assertEquals(2, app.deploymentStatus().outstandingChange().application().get().buildNumber().getAsLong()); tester.triggerJobs(); // Platform upgrade keeps rolling, since it began before block window, and tests for the new revision have also started. @@ -347,13 +347,13 @@ public class DeploymentTriggerTest { // Upgrade is done, and outstanding change rolls out when block window ends. assertEquals(Change.empty(), app.application().change()); - assertTrue(app.application().outstandingChange().hasTargets()); + assertTrue(app.deploymentStatus().outstandingChange().hasTargets()); app.runJob(stagingTest).runJob(systemTest); tester.clock().advance(Duration.ofHours(1)); tester.outstandingChangeDeployer().run(); assertTrue(app.application().change().hasTargets()); - assertFalse(app.application().outstandingChange().hasTargets()); + assertFalse(app.deploymentStatus().outstandingChange().hasTargets()); app.runJob(productionUsWest1).runJob(productionUsEast3); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployerTest.java index 11c77304dd0..a822e4fca9f 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployerTest.java @@ -44,13 +44,13 @@ public class OutstandingChangeDeployerTest { tester.deploymentTrigger().triggerReadyJobs(); assertEquals(Change.of(version), app1.application().change()); - assertFalse(app1.application().outstandingChange().hasTargets()); + assertFalse(app1.deploymentStatus().outstandingChange().hasTargets()); assertEquals(1, app1.application().latestVersion().get().buildNumber().getAsLong()); app1.submit(applicationPackage, new SourceRevision("repository1", "master", "cafed00d")); - assertTrue(app1.application().outstandingChange().hasTargets()); - assertEquals("1.0.2-cafed00d", app1.application().outstandingChange().application().get().id()); + assertTrue(app1.deploymentStatus().outstandingChange().hasTargets()); + assertEquals("1.0.2-cafed00d", app1.deploymentStatus().outstandingChange().application().get().id()); app1.assertRunning(JobType.systemTest); app1.assertRunning(JobType.stagingTest); assertEquals(2, tester.jobs().active().size()); @@ -58,7 +58,7 @@ public class OutstandingChangeDeployerTest { deployer.maintain(); tester.triggerJobs(); assertEquals("No effect as job is in progress", 2, tester.jobs().active().size()); - assertEquals("1.0.2-cafed00d", app1.application().outstandingChange().application().get().id()); + assertEquals("1.0.2-cafed00d", app1.deploymentStatus().outstandingChange().application().get().id()); app1.runJob(JobType.systemTest).runJob(JobType.stagingTest).runJob(JobType.productionUsWest1) .runJob(JobType.stagingTest).runJob(JobType.systemTest); @@ -70,7 +70,7 @@ public class OutstandingChangeDeployerTest { List<Run> runs = tester.jobs().active(); assertEquals(1, runs.size()); app1.assertRunning(JobType.productionUsWest1); - assertFalse(app1.application().outstandingChange().hasTargets()); + assertFalse(app1.deploymentStatus().outstandingChange().hasTargets()); } } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java index 9d0438ba49f..14002807b96 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java @@ -124,7 +124,6 @@ public class ApplicationSerializerTest { deploymentSpec, validationOverrides, Change.of(Version.fromString("6.7")).withPin(), - Change.of(ApplicationVersion.from(new SourceRevision("repo", "master", "deadcafe"), 42)), Optional.of(IssueId.from("4321")), Optional.of(IssueId.from("1234")), Optional.of(User.from("by-username")), @@ -166,8 +165,6 @@ public class ApplicationSerializerTest { assertEquals(original.require(id1.instance()).jobPause(JobType.stagingTest), serialized.require(id1.instance()).jobPause(JobType.stagingTest)); - assertEquals(original.outstandingChange(), serialized.outstandingChange()); - assertEquals(original.ownershipIssueId(), serialized.ownershipIssueId()); assertEquals(original.owner(), serialized.owner()); assertEquals(original.majorVersion(), serialized.majorVersion()); |