diff options
author | Jon Marius Venstad <venstad@gmail.com> | 2019-10-07 14:28:46 +0200 |
---|---|---|
committer | Jon Marius Venstad <venstad@gmail.com> | 2019-10-08 08:59:34 +0200 |
commit | 4d25b8fa9d51c4c7feb2ad16fb73c7d729e1b0e3 (patch) | |
tree | e2f0b2b079514c7e60f7c447dd2ae85c4948c643 /controller-server | |
parent | 09a59e25ad2bc2b1e378c8e059e2a8be80f0aac5 (diff) |
Store latest submission version explicitly
Diffstat (limited to 'controller-server')
4 files changed, 59 insertions, 23 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 c83f366cb67..6ce785630bb 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 @@ -43,6 +43,7 @@ public class Application { private final Instant createdAt; private final DeploymentSpec deploymentSpec; private final ValidationOverrides validationOverrides; + private final Optional<ApplicationVersion> latestVersion; private final OptionalLong projectId; private final boolean internal; private final Change change; @@ -59,14 +60,14 @@ public class Application { public Application(TenantAndApplicationId id, Instant now) { this(id, now, DeploymentSpec.empty, ValidationOverrides.empty, Change.empty(), Change.empty(), Optional.empty(), Optional.empty(), Optional.empty(), OptionalInt.empty(), - new ApplicationMetrics(0, 0), Set.of(), OptionalLong.empty(), false, List.of()); + new ApplicationMetrics(0, 0), Set.of(), OptionalLong.empty(), false, 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, - OptionalInt majorVersion, ApplicationMetrics metrics, Set<PublicKey> deployKeys, - OptionalLong projectId, boolean internal, Collection<Instance> instances) { + OptionalInt majorVersion, ApplicationMetrics metrics, Set<PublicKey> deployKeys, OptionalLong projectId, + boolean internal, Optional<ApplicationVersion> latestVersion, Collection<Instance> instances) { this.id = Objects.requireNonNull(id, "id cannot be null"); this.createdAt = Objects.requireNonNull(createdAt, "instant of creation cannot be null"); this.deploymentSpec = Objects.requireNonNull(deploymentSpec, "deploymentSpec cannot be null"); @@ -81,6 +82,7 @@ public class Application { this.deployKeys = Objects.requireNonNull(deployKeys, "deployKeys cannot be null"); this.projectId = Objects.requireNonNull(projectId, "projectId cannot be null"); this.internal = internal; + this.latestVersion = Objects.requireNonNull(latestVersion, "latestVersion cannot be null"); this.instances = ImmutableSortedMap.copyOf(instances.stream().collect(Collectors.toMap(Instance::name, Function.identity()))); } @@ -97,6 +99,9 @@ public class Application { /** Returns the project id of this application, if it has any. */ public OptionalLong projectId() { return projectId; } + /** Returns the last submitted version of this application. */ + public Optional<ApplicationVersion> latestVersion() { return latestVersion; } + /** Returns whether this application is run on the internal deployment pipeline. */ // TODO jonmv: Remove, as will be always true. public boolean internal() { return internal; } 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 19921595dc2..46d1d436521 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 @@ -5,6 +5,7 @@ import com.yahoo.config.application.api.DeploymentSpec; import com.yahoo.config.application.api.ValidationOverrides; import com.yahoo.config.provision.InstanceName; import com.yahoo.vespa.curator.Lock; +import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion; import com.yahoo.vespa.hosted.controller.api.integration.organization.IssueId; import com.yahoo.vespa.hosted.controller.api.integration.organization.User; import com.yahoo.vespa.hosted.controller.application.Change; @@ -45,6 +46,7 @@ public class LockedApplication { private final Set<PublicKey> deployKeys; private final OptionalLong projectId; private final boolean internal; + private final Optional<ApplicationVersion> latestVersion; private final Map<InstanceName, Instance> instances; /** @@ -58,14 +60,14 @@ public class LockedApplication { application.deploymentSpec(), application.validationOverrides(), application.change(), application.outstandingChange(), application.deploymentIssueId(), application.ownershipIssueId(), application.owner(), application.majorVersion(), application.metrics(), application.deployKeys(), - application.projectId(), application.internal(), application.instances()); + application.projectId(), application.internal(), application.latestVersion(), application.instances()); } private LockedApplication(Lock lock, TenantAndApplicationId id, Instant createdAt, DeploymentSpec deploymentSpec, ValidationOverrides validationOverrides, Change change, Change outstandingChange, Optional<IssueId> deploymentIssueId, Optional<IssueId> ownershipIssueId, Optional<User> owner, OptionalInt majorVersion, ApplicationMetrics metrics, Set<PublicKey> deployKeys, - OptionalLong projectId, boolean internal, + OptionalLong projectId, boolean internal, Optional<ApplicationVersion> latestVersion, Map<InstanceName, Instance> instances) { this.lock = lock; this.id = id; @@ -82,6 +84,7 @@ public class LockedApplication { this.deployKeys = deployKeys; this.projectId = projectId; this.internal = internal; + this.latestVersion = latestVersion; this.instances = Map.copyOf(instances); } @@ -89,7 +92,7 @@ public class LockedApplication { public Application get() { return new Application(id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, deployKeys, - projectId, internal, instances.values()); + projectId, internal, latestVersion, instances.values()); } public LockedApplication withNewInstance(InstanceName instance) { @@ -97,7 +100,7 @@ public class LockedApplication { instances.put(instance, new Instance(id.instance(instance))); return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, deployKeys, - projectId, internal, instances); + projectId, internal, latestVersion, instances); } public LockedApplication with(InstanceName instance, UnaryOperator<Instance> modification) { @@ -105,7 +108,7 @@ public class LockedApplication { instances.put(instance, modification.apply(instances.get(instance))); return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, deployKeys, - projectId, internal, instances); + projectId, internal, latestVersion, instances); } public LockedApplication without(InstanceName instance) { @@ -113,61 +116,67 @@ public class LockedApplication { instances.remove(instance); return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, deployKeys, - projectId, internal, instances); + projectId, internal, latestVersion, instances); + } + + public LockedApplication withNewSubmission(ApplicationVersion latestVersion) { + return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, + deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, deployKeys, + projectId, internal, Optional.of(latestVersion), instances); } public LockedApplication withBuiltInternally(boolean builtInternally) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, deployKeys, - projectId, builtInternally, instances); + projectId, builtInternally, latestVersion, instances); } public LockedApplication withProjectId(OptionalLong projectId) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, deployKeys, - projectId, internal, instances); + projectId, internal, latestVersion, instances); } public LockedApplication withDeploymentIssueId(IssueId issueId) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, Optional.ofNullable(issueId), ownershipIssueId, owner, majorVersion, metrics, deployKeys, - projectId, internal, instances); + projectId, internal, latestVersion, instances); } public LockedApplication with(DeploymentSpec deploymentSpec) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, deployKeys, - projectId, internal, instances); + projectId, internal, latestVersion, instances); } public LockedApplication with(ValidationOverrides validationOverrides) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, deployKeys, - projectId, internal, instances); + projectId, internal, latestVersion, instances); } public LockedApplication withChange(Change change) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, deployKeys, - projectId, internal, instances); + projectId, internal, latestVersion, instances); } public LockedApplication withOutstandingChange(Change outstandingChange) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, deployKeys, - projectId, internal, instances); + projectId, internal, latestVersion, instances); } public LockedApplication withOwnershipIssueId(IssueId issueId) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, deploymentIssueId, Optional.of(issueId), owner, majorVersion, metrics, deployKeys, - projectId, internal, instances); + projectId, internal, latestVersion, instances); } public LockedApplication withOwner(User owner) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, deploymentIssueId, ownershipIssueId, Optional.of(owner), majorVersion, metrics, deployKeys, - projectId, internal, instances); + projectId, internal, latestVersion, instances); } /** Set a major version for this, or set to null to remove any major version override */ @@ -175,13 +184,13 @@ public class LockedApplication { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, deploymentIssueId, ownershipIssueId, owner, majorVersion == null ? OptionalInt.empty() : OptionalInt.of(majorVersion), - metrics, deployKeys, projectId, internal, instances); + metrics, deployKeys, projectId, internal, latestVersion, instances); } public LockedApplication with(ApplicationMetrics metrics) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, deployKeys, - projectId, internal, instances); + projectId, internal, latestVersion, instances); } public LockedApplication withDeployKey(PublicKey pemDeployKey) { @@ -189,7 +198,7 @@ public class LockedApplication { keys.add(pemDeployKey); return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, keys, - projectId, internal, instances); + projectId, internal, latestVersion, instances); } public LockedApplication withoutDeployKey(PublicKey pemDeployKey) { @@ -197,7 +206,7 @@ public class LockedApplication { keys.remove(pemDeployKey); return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, change, outstandingChange, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, keys, - projectId, internal, instances); + projectId, internal, latestVersion, instances); } @Override 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 e67d5aea45d..d0af4b09a3b 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 @@ -75,6 +75,7 @@ public class ApplicationSerializer { private static final String instancesField = "instances"; private static final String deployingField = "deployingField"; private static final String projectIdField = "projectId"; + private static final String latestVersionField = "latestVersion"; private static final String builtInternallyField = "builtInternally"; private static final String pinnedField = "pinned"; private static final String outstandingChangeField = "outstandingChangeField"; @@ -181,6 +182,7 @@ public class ApplicationSerializer { root.setDouble(queryQualityField, application.metrics().queryServiceQuality()); root.setDouble(writeQualityField, application.metrics().writeServiceQuality()); deployKeysToSlime(application.deployKeys(), root.setArray(pemDeployKeysField)); + application.latestVersion().ifPresent(version -> toSlime(version, root.setObject(latestVersionField))); instancesToSlime(application, root.setArray(instancesField)); return slime; } @@ -360,11 +362,23 @@ public class ApplicationSerializer { Set<PublicKey> deployKeys = deployKeysFromSlime(root.field(pemDeployKeysField)); List<Instance> instances = instancesFromSlime(id, deploymentSpec, root.field(instancesField)); OptionalLong projectId = Serializers.optionalLong(root.field(projectIdField)); + Optional<ApplicationVersion> latestVersion = latestVersionFromSlimeWithFallback(root.field(latestVersionField), instances); boolean builtInternally = root.field(builtInternallyField).asBool(); return new Application(id, createdAt, deploymentSpec, validationOverrides, deploying, outstandingChange, deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics, - deployKeys, projectId, builtInternally, instances); + deployKeys, projectId, builtInternally, latestVersion, instances); + } + + private Optional<ApplicationVersion> latestVersionFromSlimeWithFallback(Inspector latestVersionObject, List<Instance> instances) { + if (latestVersionObject.valid()) + return Optional.of(applicationVersionFromSlime(latestVersionObject)); + + return instances.stream() + .flatMap(instance -> instance.deploymentJobs().statusOf(JobType.component).stream()) + .flatMap(status -> status.lastSuccess().stream()) + .map(JobStatus.JobRun::application) + .findFirst(); } private List<Instance> instancesFromSlime(TenantAndApplicationId id, DeploymentSpec deploymentSpec, Inspector field) { 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 447bce0a544..aa413aafcf9 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 @@ -100,6 +100,11 @@ public class ApplicationSerializerTest { List<JobStatus> statusList = new ArrayList<>(); + JobStatus.JobRun componentJob = JobStatus.JobRun.triggering(Version.emptyVersion, applicationVersion1, empty(), + empty(), "New commit", Instant.ofEpochMilli(400)) + .completion(100, Instant.ofEpochMilli(500)); + statusList.add(JobStatus.initial(JobType.component) + .withCompletion(componentJob, empty())); statusList.add(JobStatus.initial(JobType.systemTest) .withTriggering(Version.fromString("5.6.7"), ApplicationVersion.unknown, empty(), "Test", Instant.ofEpochMilli(7)) .withCompletion(30, empty(), Instant.ofEpochMilli(8)) @@ -144,12 +149,15 @@ public class ApplicationSerializerTest { Set.of(publicKey, otherPublicKey), projectId, true, + empty(), instances); Application serialized = APPLICATION_SERIALIZER.fromSlime(APPLICATION_SERIALIZER.toSlime(original)); assertEquals(original.id(), serialized.id()); assertEquals(original.createdAt(), serialized.createdAt()); + assertEquals(applicationVersion1, serialized.latestVersion().get()); // TODO jonmv: remove once this is released + assertEquals(applicationVersion1, APPLICATION_SERIALIZER.fromSlime(APPLICATION_SERIALIZER.toSlime(serialized)).latestVersion().get()); assertEquals(original.deploymentSpec().xmlForm(), serialized.deploymentSpec().xmlForm()); assertEquals(original.validationOverrides().xmlForm(), serialized.validationOverrides().xmlForm()); |