diff options
14 files changed, 140 insertions, 51 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/deployment/ApplicationVersion.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/deployment/ApplicationVersion.java index 1c8b861ba51..b1dad7d814e 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/deployment/ApplicationVersion.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/deployment/ApplicationVersion.java @@ -1,6 +1,9 @@ // 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.api.integration.deployment; +import com.yahoo.component.Version; + +import java.time.Instant; import java.util.Objects; import java.util.Optional; import java.util.OptionalLong; @@ -17,7 +20,8 @@ public class ApplicationVersion implements Comparable<ApplicationVersion> { * Used in cases where application version cannot be determined, such as manual deployments (e.g. in dev * environment) */ - public static final ApplicationVersion unknown = new ApplicationVersion(Optional.empty(), OptionalLong.empty(), Optional.empty()); + public static final ApplicationVersion unknown = new ApplicationVersion(Optional.empty(), OptionalLong.empty(), + Optional.empty(), Optional.empty(), Optional.empty()); // This never changes and is only used to create a valid semantic version number, as required by application bundles private static final String majorVersion = "1.0"; @@ -25,33 +29,53 @@ public class ApplicationVersion implements Comparable<ApplicationVersion> { private final Optional<SourceRevision> source; private final Optional<String> authorEmail; private final OptionalLong buildNumber; + private final Optional<Version> compileVersion; + private final Optional<Instant> buildTime; - private ApplicationVersion(Optional<SourceRevision> source, OptionalLong buildNumber, Optional<String> authorEmail) { + private ApplicationVersion(Optional<SourceRevision> source, OptionalLong buildNumber, Optional<String> authorEmail, + Optional<Version> compileVersion, Optional<Instant> buildTime) { Objects.requireNonNull(source, "source cannot be null"); Objects.requireNonNull(buildNumber, "buildNumber cannot be null"); Objects.requireNonNull(authorEmail, "author cannot be null"); if (source.isPresent() != buildNumber.isPresent()) { throw new IllegalArgumentException("both buildNumber and source must be set together"); } + if (compileVersion.isPresent() != buildTime.isPresent()) { + throw new IllegalArgumentException("both compileVersion and buildTime must be set together"); + } if (buildNumber.isPresent() && buildNumber.getAsLong() <= 0) { throw new IllegalArgumentException("buildNumber must be > 0"); } if (authorEmail.isPresent() && ! authorEmail.get().matches("[^@]+@[^@]+")) { throw new IllegalArgumentException("Invalid author email '" + authorEmail.get() + "'."); } + if (compileVersion.isPresent() && compileVersion.get().equals(Version.emptyVersion)) { + throw new IllegalArgumentException("The empty version is not a legal compile version."); + } this.source = source; this.buildNumber = buildNumber; this.authorEmail = authorEmail; + this.compileVersion = compileVersion; + this.buildTime = buildTime; } /** Create an application package version from a completed build, without an author email */ public static ApplicationVersion from(SourceRevision source, long buildNumber) { - return new ApplicationVersion(Optional.of(source), OptionalLong.of(buildNumber), Optional.empty()); + return new ApplicationVersion(Optional.of(source), OptionalLong.of(buildNumber), Optional.empty(), + Optional.empty(), Optional.empty()); } - /** Create an application package version from a completed build, with an author email */ + /** Creates an version from a completed build and an author email. */ public static ApplicationVersion from(SourceRevision source, long buildNumber, String authorEmail) { - return new ApplicationVersion(Optional.of(source), OptionalLong.of(buildNumber), Optional.of(authorEmail)); + return new ApplicationVersion(Optional.of(source), OptionalLong.of(buildNumber), + Optional.of(authorEmail), Optional.empty(), Optional.empty()); + } + + /** Creates an version from a completed build, an author email, and build meta data. */ + public static ApplicationVersion from(SourceRevision source, long buildNumber, String authorEmail, + Version compileVersion, Instant buildTime) { + return new ApplicationVersion(Optional.of(source), OptionalLong.of(buildNumber), Optional.of(authorEmail), + Optional.of(compileVersion), Optional.of(buildTime)); } /** Returns an unique identifier for this version or "unknown" if version is not known */ @@ -74,6 +98,12 @@ public class ApplicationVersion implements Comparable<ApplicationVersion> { /** Returns the email of the author of commit of this version, if known */ public Optional<String> authorEmail() { return authorEmail; } + /** Returns the Vespa version this package was compiled against, if known. */ + public Optional<Version> compileVersion() { return compileVersion; } + + /** Returns the time this package was built, if known. */ + public Optional<Instant> buildTime() { return buildTime; } + /** Returns whether this is unknown */ public boolean isUnknown() { return this.equals(unknown); @@ -86,19 +116,23 @@ public class ApplicationVersion implements Comparable<ApplicationVersion> { ApplicationVersion that = (ApplicationVersion) o; return Objects.equals(source, that.source) && Objects.equals(authorEmail, that.authorEmail) && - Objects.equals(buildNumber, that.buildNumber); + Objects.equals(buildNumber, that.buildNumber) && + Objects.equals(compileVersion, that.compileVersion) && + Objects.equals(buildTime, that.buildTime); } @Override public int hashCode() { - return Objects.hash(source, authorEmail, buildNumber); + return Objects.hash(source, authorEmail, buildNumber, compileVersion, buildTime); } @Override public String toString() { - return "Application package version: " + id() + return "Application package version: " + id() + source.map(s -> ", " + s.toString()).orElse("") - + authorEmail.map(e -> ", " + e).orElse(""); + + authorEmail.map(e -> ", by " + e).orElse("") + + compileVersion.map(v -> ", built against " + v).orElse("") + + buildTime.map(t -> " at " + t).orElse("") ; } /** Abbreviate given commit hash to 9 characters */ diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationPackage.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationPackage.java index 40e2e4a92d1..a0b4a888727 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationPackage.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationPackage.java @@ -1,14 +1,19 @@ // 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.application; +import com.yahoo.component.Version; import com.yahoo.config.application.api.DeploymentSpec; import com.yahoo.config.application.api.ValidationOverrides; +import com.yahoo.slime.Inspector; +import com.yahoo.slime.Slime; +import com.yahoo.vespa.config.SlimeUtils; import org.apache.commons.codec.digest.DigestUtils; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; +import java.time.Instant; import java.util.Objects; import java.util.Optional; @@ -27,10 +32,12 @@ public class ApplicationPackage { private final byte[] zippedContent; private final DeploymentSpec deploymentSpec; private final ValidationOverrides validationOverrides; + private final Optional<Version> compileVersion; + private final Optional<Instant> buildTime; /** * Creates an application package from its zipped content. - * This <b>assigns ownership</b> of the given byte array to this class: + * This <b>assigns ownership</b> of the given byte array to this class; * it must not be further changed by the caller. */ public ApplicationPackage(byte[] zippedContent) { @@ -38,6 +45,10 @@ public class ApplicationPackage { this.contentHash = DigestUtils.shaHex(zippedContent); this.deploymentSpec = extractFile("deployment.xml", zippedContent).map(DeploymentSpec::fromXml).orElse(DeploymentSpec.empty); this.validationOverrides = extractFile("validation-overrides.xml", zippedContent).map(ValidationOverrides::fromXml).orElse(ValidationOverrides.empty); + Optional<Inspector> buildMetaObject = extractFileBytes("build-meta.json", zippedContent) + .map(SlimeUtils::jsonToSlime).map(Slime::get); + this.compileVersion = buildMetaObject.map(object -> Version.fromString(object.field("compileVersion").asString())); + this.buildTime = buildMetaObject.map(object -> Instant.ofEpochMilli(object.field("buildTime").asLong())); } /** Returns a hash of the content of this package */ @@ -58,12 +69,18 @@ public class ApplicationPackage { */ public ValidationOverrides validationOverrides() { return validationOverrides; } - private static Optional<Reader> extractFile(String fileName, byte[] zippedContent) { + /** Returns the platform version which package was compiled against, if known. */ + public Optional<Version> compileVersion() { return compileVersion; } + + /** Returns the time this package was built, if known. */ + public Optional<Instant> buildTime() { return buildTime; } + + private static Optional<byte[]> extractFileBytes(String fileName, byte[] zippedContent) { try (ByteArrayInputStream stream = new ByteArrayInputStream(zippedContent)) { ZipStreamReader reader = new ZipStreamReader(stream); for (ZipStreamReader.ZipEntryWithContent entry : reader.entries()) if (entry.zipEntry().getName().equals(fileName) || entry.zipEntry().getName().equals("application/" + fileName)) // TODO: Remove application/ directory support - return Optional.of(new InputStreamReader(new ByteArrayInputStream(entry.content()))); + return Optional.of(entry.content()); return Optional.empty(); } catch (IOException e) { @@ -71,4 +88,8 @@ public class ApplicationPackage { } } + private static Optional<Reader> extractFile(String fileName, byte[] zippedContent) { + return extractFileBytes(fileName, zippedContent).map(ByteArrayInputStream::new).map(InputStreamReader::new); + } + } 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 5c56c7d2280..fcead86893a 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 @@ -10,25 +10,23 @@ import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId; import com.yahoo.vespa.hosted.controller.api.integration.LogEntry; import com.yahoo.vespa.hosted.controller.api.integration.RunDataStore; import com.yahoo.vespa.hosted.controller.api.integration.configserver.NoInstanceException; +import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion; 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; import com.yahoo.vespa.hosted.controller.api.integration.deployment.TesterCloud; import com.yahoo.vespa.hosted.controller.api.integration.deployment.TesterId; import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; -import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion; import com.yahoo.vespa.hosted.controller.application.Deployment; import com.yahoo.vespa.hosted.controller.application.DeploymentJobs; import com.yahoo.vespa.hosted.controller.application.JobStatus; -import com.yahoo.vespa.hosted.controller.api.integration.deployment.SourceRevision; import com.yahoo.vespa.hosted.controller.persistence.BufferedLogStore; import com.yahoo.vespa.hosted.controller.persistence.CuratorDb; import java.net.URI; -import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; -import java.util.Deque; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -41,7 +39,6 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.UnaryOperator; import java.util.logging.Level; -import java.util.stream.Collectors; import java.util.stream.Stream; import static com.google.common.collect.ImmutableList.copyOf; @@ -229,7 +226,7 @@ public class JobController { * Accepts and stores a new application package and test jar pair under a generated application version key. */ public ApplicationVersion submit(ApplicationId id, SourceRevision revision, String authorEmail, long projectId, - byte[] packageBytes, byte[] testPackageBytes) { + ApplicationPackage applicationPackage, byte[] testPackageBytes) { AtomicReference<ApplicationVersion> version = new AtomicReference<>(); controller.applications().lockOrThrow(id, application -> { if ( ! application.get().deploymentJobs().deployedInternally()) { @@ -245,17 +242,22 @@ public class JobController { } long run = nextBuild(id); - version.set(ApplicationVersion.from(revision, run, authorEmail)); + if (applicationPackage.compileVersion().isPresent() && applicationPackage.buildTime().isPresent()) + version.set(ApplicationVersion.from(revision, run, authorEmail, + applicationPackage.compileVersion().get(), + applicationPackage.buildTime().get())); + else + version.set(ApplicationVersion.from(revision, run, authorEmail)); controller.applications().applicationStore().put(id, version.get(), - packageBytes); + applicationPackage.zippedContent()); controller.applications().applicationStore().put(TesterId.of(id), version.get(), testPackageBytes); prunePackages(id); - controller.applications().storeWithUpdatedConfig(application.withBuiltInternally(true), new ApplicationPackage(packageBytes)); + controller.applications().storeWithUpdatedConfig(application.withBuiltInternally(true), applicationPackage); controller.applications().deploymentTrigger().notifyOfCompletion(DeploymentJobs.JobReport.ofSubmission(id, projectId, version.get())); }); 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 69ea36c7e3a..147b2edee3e 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 @@ -81,6 +81,8 @@ public class ApplicationSerializer { private final String branchField = "branchField"; private final String commitField = "commitField"; private final String authorEmailField = "authorEmailField"; + private final String compileVersionField = "compileVersion"; + private final String buildTimeField = "buildTime"; private final String lastQueriedField = "lastQueried"; private final String lastWrittenField = "lastWritten"; private final String lastQueriesPerSecondField = "lastQueriesPerSecond"; @@ -231,6 +233,8 @@ public class ApplicationSerializer { object.setLong(applicationBuildNumberField, applicationVersion.buildNumber().getAsLong()); toSlime(applicationVersion.source().get(), object.setObject(sourceRevisionField)); applicationVersion.authorEmail().ifPresent(email -> object.setString(authorEmailField, email)); + applicationVersion.compileVersion().ifPresent(version -> object.setString(compileVersionField, version.toString())); + applicationVersion.buildTime().ifPresent(time -> object.setLong(buildTimeField, time.toEpochMilli())); } } @@ -406,12 +410,21 @@ public class ApplicationSerializer { if ( ! object.valid()) return ApplicationVersion.unknown; OptionalLong applicationBuildNumber = optionalLong(object.field(applicationBuildNumberField)); Optional<SourceRevision> sourceRevision = sourceRevisionFromSlime(object.field(sourceRevisionField)); - if (!sourceRevision.isPresent() || !applicationBuildNumber.isPresent()) { + if ( ! sourceRevision.isPresent() || ! applicationBuildNumber.isPresent()) { return ApplicationVersion.unknown; } - return object.field(authorEmailField).valid() - ? ApplicationVersion.from(sourceRevision.get(), applicationBuildNumber.getAsLong(), object.field(authorEmailField).asString()) - : ApplicationVersion.from(sourceRevision.get(), applicationBuildNumber.getAsLong()); + Optional<String> authorEmail = optionalString(object.field(authorEmailField)); + Optional<Version> compileVersion = optionalString(object.field(compileVersionField)).map(Version::fromString); + Optional<Instant> buildTime = optionalInstant(object.field(buildTimeField)); + + if ( ! authorEmail.isPresent()) + return ApplicationVersion.from(sourceRevision.get(), applicationBuildNumber.getAsLong()); + + if ( ! compileVersion.isPresent() || ! buildTime.isPresent()) + return ApplicationVersion.from(sourceRevision.get(), applicationBuildNumber.getAsLong(), authorEmail.get()); + + return ApplicationVersion.from(sourceRevision.get(), applicationBuildNumber.getAsLong(), authorEmail.get(), + compileVersion.get(), buildTime.get()); } private Optional<SourceRevision> sourceRevisionFromSlime(Inspector object) { diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializer.java index ef91a2e5a15..32c92e6f135 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializer.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializer.java @@ -68,6 +68,8 @@ class RunSerializer { private static final String branchField = "branch"; private static final String commitField = "commit"; private static final String authorEmailField = "authorEmail"; + private static final String compileVersionField = "compileVersion"; + private static final String buildTimeField = "buildTime"; private static final String buildField = "build"; private static final String sourceField = "source"; private static final String lastTestRecordField = "lastTestRecord"; @@ -123,9 +125,16 @@ class RunSerializer { versionObject.field(branchField).asString(), versionObject.field(commitField).asString()); long buildNumber = versionObject.field(buildField).asLong(); - return versionObject.field(authorEmailField).valid() - ? ApplicationVersion.from(revision, buildNumber, versionObject.field(authorEmailField).asString()) - : ApplicationVersion.from(revision, buildNumber); + + if ( ! versionObject.field(authorEmailField).valid()) + return ApplicationVersion.from(revision, buildNumber); + + if ( ! versionObject.field(compileVersionField).valid() || ! versionObject.field(buildTimeField).valid()) + return ApplicationVersion.from(revision, buildNumber, versionObject.field(authorEmailField).asString()); + + return ApplicationVersion.from(revision, buildNumber, versionObject.field(authorEmailField).asString(), + Version.fromString(versionObject.field(compileVersionField).asString()), + Instant.ofEpochMilli(versionObject.field(buildTimeField).asLong())); } Slime toSlime(Iterable<Run> runs) { @@ -173,6 +182,8 @@ class RunSerializer { versionsObject.setLong(buildField, applicationVersion.buildNumber() .orElseThrow(() -> new IllegalArgumentException("Build number must be present in application version."))); applicationVersion.authorEmail().ifPresent(email -> versionsObject.setString(authorEmailField, email)); + applicationVersion.compileVersion().ifPresent(version -> versionsObject.setString(compileVersionField, version.toString())); + applicationVersion.buildTime().ifPresent(time -> versionsObject.setLong(buildTimeField, time.toEpochMilli())); } static String valueOf(Step step) { 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 8f8a3ad7f55..56e1e746d04 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 @@ -1321,9 +1321,9 @@ public class ApplicationApiHandler extends LoggingRequestHandler { String authorEmail = submitOptions.field("authorEmail").asString(); long projectId = Math.max(1, submitOptions.field("projectId").asLong()); - byte[] applicationZip = dataParts.get(EnvironmentResource.APPLICATION_ZIP); + ApplicationPackage applicationPackage = new ApplicationPackage(dataParts.get(EnvironmentResource.APPLICATION_ZIP)); controller.applications().verifyApplicationIdentityConfiguration(TenantName.from(tenant), - new ApplicationPackage(applicationZip), + applicationPackage, Optional.of(getUserPrincipal(request).getIdentity())); return JobControllerApiHandlerHelper.submitResponse(controller.jobController(), @@ -1332,7 +1332,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler { sourceRevision, authorEmail, projectId, - applicationZip, + applicationPackage, dataParts.get(EnvironmentResource.APPLICATION_TEST_ZIP)); } 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 a3dc3f1e706..7d49ffe8139 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,6 +16,7 @@ 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.zone.ZoneId; import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion; +import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.application.Change; import com.yahoo.vespa.hosted.controller.application.Deployment; import com.yahoo.vespa.hosted.controller.application.JobStatus; @@ -27,6 +28,7 @@ import com.yahoo.vespa.hosted.controller.deployment.RunLog; import com.yahoo.vespa.hosted.controller.deployment.Run; import com.yahoo.vespa.hosted.controller.deployment.Step; import com.yahoo.vespa.hosted.controller.deployment.Versions; +import com.yahoo.vespa.hosted.controller.restapi.MessageResponse; import com.yahoo.vespa.hosted.controller.restapi.SlimeJsonResponse; import com.yahoo.vespa.hosted.controller.versions.VespaVersion; @@ -398,19 +400,16 @@ class JobControllerApiHandlerHelper { * @return Response with the new application version */ static HttpResponse submitResponse(JobController jobController, String tenant, String application, - SourceRevision sourceRevision, String authorEmail, - long projectId, byte[] appPackage, byte[] testPackage) { + SourceRevision sourceRevision, String authorEmail, long projectId, + ApplicationPackage applicationPackage, byte[] testPackage) { ApplicationVersion version = jobController.submit(ApplicationId.from(tenant, application, "default"), sourceRevision, authorEmail, projectId, - appPackage, + applicationPackage, testPackage); - Slime slime = new Slime(); - Cursor responseObject = slime.setObject(); - responseObject.setString("version", version.id()); - return new SlimeJsonResponse(slime); + return new MessageResponse(version.toString()); } /** Aborts any job of the given type. */ diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java index b7a881c672e..1199f0229b6 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java @@ -155,7 +155,8 @@ public class ControllerTest { .region("deep-space-9") .build(); try { - tester.controller().jobController().submit(app1.id(), BuildJob.defaultSourceRevision, "a@b", 2, applicationPackage.zippedContent(), new byte[0]); + tester.controller().jobController().submit(app1.id(), BuildJob.defaultSourceRevision, "a@b", + 2, applicationPackage, new byte[0]); fail("Expected exception due to illegal deployment spec."); } catch (IllegalArgumentException e) { diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalDeploymentTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalDeploymentTester.java index 80cbbfa2c30..35e7aea5efe 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalDeploymentTester.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalDeploymentTester.java @@ -89,7 +89,7 @@ public class InternalDeploymentTester { * Submits a new application, and returns the version of the new submission. */ public ApplicationVersion newSubmission() { - ApplicationVersion version = jobs.submit(appId, BuildJob.defaultSourceRevision, "a@b", 2, applicationPackage.zippedContent(), new byte[0]); + ApplicationVersion version = jobs.submit(appId, BuildJob.defaultSourceRevision, "a@b", 2, applicationPackage, new byte[0]); tester.applicationStore().put(appId, version, applicationPackage.zippedContent()); tester.applicationStore().put(testerId, version, new byte[0]); return version; diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/JobRunnerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/JobRunnerTest.java index 7e6e892891a..8ebb8c108c0 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/JobRunnerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/JobRunnerTest.java @@ -7,6 +7,7 @@ import com.yahoo.vespa.athenz.api.OktaAccessToken; import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId; import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion; import com.yahoo.vespa.hosted.controller.api.integration.deployment.SourceRevision; +import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester; import com.yahoo.vespa.hosted.controller.deployment.JobController; import com.yahoo.vespa.hosted.controller.deployment.Run; @@ -64,6 +65,7 @@ import static org.junit.Assert.fail; */ public class JobRunnerTest { + private static final ApplicationPackage applicationPackage = new ApplicationPackage(new byte[0]); private static final Versions versions = new Versions(Version.fromString("1.2.3"), ApplicationVersion.from(new SourceRevision("repo", "branch", @@ -82,7 +84,7 @@ public class JobRunnerTest { phasedExecutor(phaser), stepRunner); ApplicationId id = tester.createApplication("real", "tenant", 1, 1L).id(); - jobs.submit(id, versions.targetApplication().source().get(), "a@b", 2, new byte[0], new byte[0]); + jobs.submit(id, versions.targetApplication().source().get(), "a@b", 2, applicationPackage, new byte[0]); jobs.start(id, systemTest, versions); try { @@ -113,7 +115,7 @@ public class JobRunnerTest { inThreadExecutor(), mappedRunner(outcomes)); ApplicationId id = tester.createApplication("real", "tenant", 1, 1L).id(); - jobs.submit(id, versions.targetApplication().source().get(), "a@b", 2, new byte[0], new byte[0]); + jobs.submit(id, versions.targetApplication().source().get(), "a@b", 2, applicationPackage, new byte[0]); Supplier<Run> run = () -> jobs.last(id, systemTest).get(); jobs.start(id, systemTest, versions); @@ -197,7 +199,7 @@ public class JobRunnerTest { Executors.newFixedThreadPool(32), waitingRunner(barrier)); ApplicationId id = tester.createApplication("real", "tenant", 1, 1L).id(); - jobs.submit(id, versions.targetApplication().source().get(), "a@b", 2, new byte[0], new byte[0]); + jobs.submit(id, versions.targetApplication().source().get(), "a@b", 2, applicationPackage, new byte[0]); RunId runId = new RunId(id, systemTest, 1); jobs.start(id, systemTest, versions); @@ -233,7 +235,7 @@ public class JobRunnerTest { inThreadExecutor(), (id, step) -> Optional.of(running)); ApplicationId id = tester.createApplication("real", "tenant", 1, 1L).id(); - jobs.submit(id, versions.targetApplication().source().get(), "a@b", 2, new byte[0], new byte[0]); + jobs.submit(id, versions.targetApplication().source().get(), "a@b", 2, applicationPackage, new byte[0]); for (int i = 0; i < jobs.historyLength(); i++) { jobs.start(id, systemTest, versions); @@ -261,7 +263,7 @@ public class JobRunnerTest { inThreadExecutor(), mappedRunner(outcomes)); ApplicationId id = tester.createApplication("real", "tenant", 1, 1L).id(); - jobs.submit(id, versions.targetApplication().source().get(), "a@b", 2, new byte[0], new byte[0]); + jobs.submit(id, versions.targetApplication().source().get(), "a@b", 2, applicationPackage, new byte[0]); jobs.start(id, systemTest, versions); tester.clock().advance(JobRunner.jobTimeout.plus(Duration.ofSeconds(1))); 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 774caea97b0..0b337eb5380 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 @@ -10,11 +10,12 @@ import com.yahoo.config.provision.HostName; import com.yahoo.vespa.config.SlimeUtils; import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.api.integration.MetricsService; +import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion; import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; +import com.yahoo.vespa.hosted.controller.api.integration.deployment.SourceRevision; 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.api.integration.zone.ZoneId; -import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion; import com.yahoo.vespa.hosted.controller.application.Change; import com.yahoo.vespa.hosted.controller.application.ClusterInfo; import com.yahoo.vespa.hosted.controller.application.ClusterUtilization; @@ -25,7 +26,6 @@ import com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobError; import com.yahoo.vespa.hosted.controller.application.DeploymentMetrics; import com.yahoo.vespa.hosted.controller.application.JobStatus; import com.yahoo.vespa.hosted.controller.application.RotationStatus; -import com.yahoo.vespa.hosted.controller.api.integration.deployment.SourceRevision; import com.yahoo.vespa.hosted.controller.rotation.RotationId; import org.junit.Test; @@ -70,7 +70,8 @@ public class ApplicationSerializerTest { List<Deployment> deployments = new ArrayList<>(); ApplicationVersion applicationVersion1 = ApplicationVersion.from(new SourceRevision("repo1", "branch1", "commit1"), 31); ApplicationVersion applicationVersion2 = ApplicationVersion - .from(new SourceRevision("repo1", "branch1", "commit1"), 32, "a@b"); + .from(new SourceRevision("repo1", "branch1", "commit1"), 32, "a@b", + Version.fromString("6.3.1"), Instant.ofEpochMilli(496)); Instant activityAt = Instant.parse("2018-06-01T10:15:30.00Z"); deployments.add(new Deployment(zone1, applicationVersion1, Version.fromString("1.2.3"), Instant.ofEpochMilli(3))); // One deployment without cluster info and utils deployments.add(new Deployment(zone2, applicationVersion2, Version.fromString("1.2.3"), Instant.ofEpochMilli(5), diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializerTest.java index d6334a9ea86..03b432588bd 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializerTest.java @@ -19,6 +19,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.Collections; import java.util.Optional; @@ -78,7 +79,9 @@ public class RunSerializerTest { "master", "f00bad"), 123, - "a@b"), + "a@b", + Version.fromString("6.3.1"), + Instant.ofEpochMilli(100)), run.versions().targetApplication()); assertEquals(new Version(1, 2, 2), run.versions().sourcePlatform().get()); assertEquals(ApplicationVersion.from(new SourceRevision("git@github.com:user/repo.git", diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/run-status.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/run-status.json index 75bbea6861d..cda3834d47d 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/run-status.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/run-status.json @@ -26,6 +26,8 @@ "commit": "f00bad", "build": 123, "authorEmail": "a@b", + "compileVersion": "6.3.1", + "buildTime": 100, "source": { "platform": "1.2.2", "repository": "git@github.com:user/repo.git", diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java index fd3b30a76c9..eaf78eda593 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java @@ -455,7 +455,7 @@ public class ApplicationApiTest extends ControllerContainerTest { tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/submit", POST) .screwdriverIdentity(SCREWDRIVER_ID) .data(createApplicationSubmissionData(applicationPackage)), - "{\"version\":\"1.0.43-d00d\"}"); + "{\"message\":\"Application package version: 1.0.43-d00d, source revision of repository 'repo', branch 'master' with commit 'd00d', by a@b\"}"); // Second attempt has a service under a different domain than the tenant of the application, and fails. ApplicationPackage packageWithServiceForWrongDomain = new ApplicationPackageBuilder() @@ -477,7 +477,7 @@ public class ApplicationApiTest extends ControllerContainerTest { tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/submit", POST) .screwdriverIdentity(SCREWDRIVER_ID) .data(createApplicationSubmissionData(packageWithService)), - "{\"version\":\"1.0.44-d00d\"}"); + "{\"message\":\"Application package version: 1.0.44-d00d, source revision of repository 'repo', branch 'master' with commit 'd00d', by a@b\"}"); tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/default/badge", GET) .userIdentity(USER_ID), |