aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjonmv <venstad@gmail.com>2022-04-11 21:34:42 +0200
committerjonmv <venstad@gmail.com>2022-04-11 21:38:00 +0200
commit683c74c6baa349be93c3d878638214458b8e2bb4 (patch)
tree6fca498336b09a95a7d897b614e5f79567d4a6b0
parent27af44b14a95177126ec4c1cd3deaf9a1fb4c6e5 (diff)
Use RevisionId instead of ApplicationVersion as keys
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/deployment/ApplicationStore.java18
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/deployment/ApplicationVersion.java89
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/deployment/RevisionId.java28
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Application.java17
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java26
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Instance.java8
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Change.java55
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Deployment.java28
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/InstanceList.java4
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java51
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java31
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java17
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java45
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobList.java7
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/RevisionHistory.java46
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/Versions.java75
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentUpgrader.java4
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializer.java84
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java24
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/MockCuratorDb.java24
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializer.java61
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java91
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelper.java45
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java19
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java15
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/DeploymentQuotaCalculatorTest.java6
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentContext.java11
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java229
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java34
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ApplicationStoreMock.java36
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ZoneRegistryMock.java9
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/JobRunnerTest.java18
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporterTest.java3
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployerTest.java5
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java7
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/notification/NotificationsDbTest.java3
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java41
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/BufferedLogStoreTest.java3
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializerTest.java48
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java26
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java18
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-cloud.json1
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-with-routing-policy.json1
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-without-shared-endpoints.json1
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment.json1
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-east-1-log-first-part.json2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/instance1-recursive.json2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-root.json2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/staging-test-log.json2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/system-test-details.json2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/system-test-log.json2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant1-recursive.json2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilterTest.java3
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/os/OsApiTest.java8
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/RoutingPoliciesTest.java14
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/rotation/RotationRepositoryTest.java4
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java7
59 files changed, 746 insertions, 721 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/deployment/ApplicationStore.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/deployment/ApplicationStore.java
index fef95155440..c4db0de539e 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/deployment/ApplicationStore.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/deployment/ApplicationStore.java
@@ -16,8 +16,8 @@ import java.util.Optional;
*/
public interface ApplicationStore {
- /** Returns the tenant application package of the given version. */
- byte[] get(DeploymentId deploymentId, ApplicationVersion applicationVersion);
+ /** Returns the application package of the given revision. */
+ byte[] get(DeploymentId deploymentId, RevisionId revisionId);
/** Returns the application package diff, compared to the previous build, for the given tenant, application and build number */
Optional<byte[]> getDiff(TenantName tenantName, ApplicationName applicationName, long buildNumber);
@@ -34,16 +34,16 @@ public interface ApplicationStore {
}
/** Stores the given tenant application and test packages of the given revision, and diff since previous version. */
- void put(TenantName tenant, ApplicationName application, ApplicationVersion applicationVersion, byte[] applicationPackage, byte[] testPackage, byte[] diff);
+ void put(TenantName tenant, ApplicationName application, RevisionId revision, byte[] applicationPackage, byte[] testPackage, byte[] diff);
- /** Removes application and test packages older than the given version, for the given application. */
- void prune(TenantName tenant, ApplicationName application, ApplicationVersion olderThanVersion);
+ /** Removes application and test packages older than the given revision, for the given application. */
+ void prune(TenantName tenant, ApplicationName application, RevisionId revision);
/** Removes all application and test packages for the given application, including any development package. */
void removeAll(TenantName tenant, ApplicationName application);
- /** Returns the tester application package of the given version. Does NOT contain the services.xml. */
- byte[] getTester(TenantName tenant, ApplicationName application, ApplicationVersion applicationVersion);
+ /** Returns the tester application package of the given revision. Does NOT contain the services.xml. */
+ byte[] getTester(TenantName tenant, ApplicationName application, RevisionId revision);
/** Returns the application package diff, compared to the previous build, for the given deployment and build number */
Optional<byte[]> getDevDiff(DeploymentId deploymentId, long buildNumber);
@@ -51,8 +51,8 @@ public interface ApplicationStore {
/** Removes diffs for dev packages before the given build number */
void pruneDevDiffs(DeploymentId deploymentId, long beforeBuildNumber);
- /** Stores the given application package as the development package for the given deployment and version and diff since previous version. */
- void putDev(DeploymentId deploymentId, ApplicationVersion version, byte[] applicationPackage, byte[] diff);
+ /** Stores the given application package as the development package for the given deployment and revision and diff since previous version. */
+ void putDev(DeploymentId deploymentId, RevisionId revision, byte[] applicationPackage, byte[] diff);
/** Stores the given application metadata with the current time as part of the path. */
void putMeta(TenantName tenant, ApplicationName application, Instant now, byte[] metaZip);
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 29d7005ddc7..445ca0435d4 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
@@ -20,36 +20,26 @@ import static ai.vespa.validation.Validation.requireAtLeast;
*/
public class ApplicationVersion implements Comparable<ApplicationVersion> {
- /** Should not be used, but may still exist in serialized data :S */
- public static final ApplicationVersion unknown = new ApplicationVersion(Optional.empty(), OptionalLong.empty(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), true, Optional.empty(), false, true, Optional.empty(), 0);
-
// 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";
+ private final RevisionId id;
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 final Optional<String> sourceUrl;
private final Optional<String> commit;
- private final boolean deployedDirectly;
private final Optional<String> bundleHash;
private final boolean hasPackage;
private final boolean shouldSkip;
private final Optional<String> description;
private final int risk;
- public ApplicationVersion(Optional<SourceRevision> source, OptionalLong buildNumber, Optional<String> authorEmail,
+ public ApplicationVersion(RevisionId id, Optional<SourceRevision> source, Optional<String> authorEmail,
Optional<Version> compileVersion, Optional<Instant> buildTime, Optional<String> sourceUrl,
- Optional<String> commit, boolean deployedDirectly, Optional<String> bundleHash,
+ Optional<String> commit, Optional<String> bundleHash,
boolean hasPackage, boolean shouldSkip, Optional<String> description, int risk) {
- if (buildNumber.isEmpty() && ( source.isPresent() || authorEmail.isPresent() || compileVersion.isPresent()
- || buildTime.isPresent() || sourceUrl.isPresent() || commit.isPresent()))
- throw new IllegalArgumentException("Build number must be present if any other attribute is");
-
- if (buildNumber.isPresent() && buildNumber.getAsLong() <= 0)
- throw new IllegalArgumentException("Build number must be > 0");
if (commit.isPresent() && commit.get().length() > 128)
throw new IllegalArgumentException("Commit may not be longer than 128 characters");
@@ -60,14 +50,13 @@ public class ApplicationVersion implements Comparable<ApplicationVersion> {
if (compileVersion.isPresent() && compileVersion.get().equals(Version.emptyVersion))
throw new IllegalArgumentException("The empty version is not a legal compile version.");
+ this.id = id;
this.source = source;
- this.buildNumber = buildNumber;
this.authorEmail = authorEmail;
this.compileVersion = compileVersion;
this.buildTime = buildTime;
this.sourceUrl = Objects.requireNonNull(sourceUrl, "sourceUrl cannot be null");
this.commit = Objects.requireNonNull(commit, "commit cannot be null");
- this.deployedDirectly = deployedDirectly;
this.bundleHash = bundleHash;
this.hasPackage = hasPackage;
this.shouldSkip = shouldSkip;
@@ -76,44 +65,39 @@ public class ApplicationVersion implements Comparable<ApplicationVersion> {
}
public RevisionId id() {
- return isDeployedDirectly() ? RevisionId.forDevelopment(buildNumber().orElse(0))
- : RevisionId.forProduction(buildNumber().orElseThrow());
+ return id;
}
/** 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(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), false, Optional.empty(), true, false, Optional.empty(), 0);
+ public static ApplicationVersion from(RevisionId id, SourceRevision source) {
+ return new ApplicationVersion(id, Optional.of(source), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), true, false, Optional.empty(), 0);
}
/** Creates a version from a completed build, an author email, and build metadata. */
- 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), Optional.empty(), Optional.empty(), false, Optional.empty(), true, false, Optional.empty(), 0);
+ public static ApplicationVersion from(RevisionId id, SourceRevision source, String authorEmail, Version compileVersion, Instant buildTime) {
+ return new ApplicationVersion(id, Optional.of(source), Optional.of(authorEmail), Optional.of(compileVersion), Optional.of(buildTime), Optional.empty(), Optional.empty(), Optional.empty(), true, false, Optional.empty(), 0);
}
/** Creates a minimal version for a development build. */
- public static ApplicationVersion forDevelopment(long buildNumber, Optional<Version> compileVersion) {
- return new ApplicationVersion(Optional.empty(), OptionalLong.of(buildNumber), Optional.empty(), compileVersion, Optional.empty(), Optional.empty(), Optional.empty(), true, Optional.empty(), true, false, Optional.empty(), 0);
+ public static ApplicationVersion forDevelopment(RevisionId id, Optional<Version> compileVersion) {
+ return new ApplicationVersion(id, Optional.empty(), Optional.empty(), compileVersion, Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), true, false, Optional.empty(), 0);
}
/** Creates a version from a completed build, an author email, and build metadata. */
- public static ApplicationVersion forProduction(Optional<SourceRevision> source, long buildNumber, Optional<String> authorEmail,
- Optional<Version> compileVersion, Optional<Instant> buildTime,
- Optional<String> sourceUrl, Optional<String> commit, boolean deployedDirectly,
- Optional<String> bundleHash, Optional<String> description, int risk) {
- return new ApplicationVersion(source, OptionalLong.of(buildNumber), authorEmail, compileVersion, buildTime,
- sourceUrl, commit, deployedDirectly, bundleHash, true, false, description, risk);
+ public static ApplicationVersion forProduction(RevisionId id, Optional<SourceRevision> source, Optional<String> authorEmail,
+ Optional<Version> compileVersion, Optional<Instant> buildTime, Optional<String> sourceUrl,
+ Optional<String> commit, Optional<String> bundleHash, Optional<String> description, int risk) {
+ return new ApplicationVersion(id, source, authorEmail, compileVersion, buildTime,
+ sourceUrl, commit, bundleHash, true, false, description, risk);
}
/** Returns a unique identifier for this version or "unknown" if version is not known */
// TODO jonmv: kill
public String stringId() {
- if (isUnknown()) return "unknown";
-
return source.map(SourceRevision::commit).map(ApplicationVersion::abbreviateCommit)
.or(this::commit)
- .map(commit -> String.format("%s.%d-%s", majorVersion, buildNumber.getAsLong(), commit))
- .orElseGet(() -> majorVersion + "." + buildNumber.getAsLong());
+ .map(commit -> String.format("%s.%d-%s", majorVersion, buildNumber().getAsLong(), commit))
+ .orElseGet(() -> majorVersion + "." + buildNumber().getAsLong());
}
/**
@@ -123,7 +107,7 @@ public class ApplicationVersion implements Comparable<ApplicationVersion> {
public Optional<SourceRevision> source() { return source; }
/** Returns the build number that built this version */
- public OptionalLong buildNumber() { return buildNumber; }
+ public OptionalLong buildNumber() { return OptionalLong.of(id.number()); }
/** Returns the email of the author of commit of this version, if known */
public Optional<String> authorEmail() { return authorEmail; }
@@ -154,19 +138,14 @@ public class ApplicationVersion implements Comparable<ApplicationVersion> {
/** Returns the commit name of this application version. */
public Optional<String> commit() { return commit.or(() -> source.map(SourceRevision::commit)); }
- /** Returns whether this is unknown */
- public boolean isUnknown() {
- return this.equals(unknown);
- }
-
/** Returns whether the application package for this version was deployed directly to zone */
public boolean isDeployedDirectly() {
- return deployedDirectly;
+ return ! id.isProduction();
}
/** Returns a copy of this without a package stored. */
public ApplicationVersion withoutPackage() {
- return new ApplicationVersion(source, buildNumber, authorEmail, compileVersion, buildTime, sourceUrl, commit, deployedDirectly, bundleHash, false, shouldSkip, description, risk);
+ return new ApplicationVersion(id, source, authorEmail, compileVersion, buildTime, sourceUrl, commit, bundleHash, false, shouldSkip, description, risk);
}
/** Whether we still have the package for this revision. */
@@ -176,7 +155,7 @@ public class ApplicationVersion implements Comparable<ApplicationVersion> {
/** Returns a copy of this which will not be rolled out to production. */
public ApplicationVersion skipped() {
- return new ApplicationVersion(source, buildNumber, authorEmail, compileVersion, buildTime, sourceUrl, commit, deployedDirectly, bundleHash, hasPackage, true, description, risk);
+ return new ApplicationVersion(id, source, authorEmail, compileVersion, buildTime, sourceUrl, commit, bundleHash, hasPackage, true, description, risk);
}
/** Whether we still have the package for this revision. */
@@ -204,23 +183,21 @@ public class ApplicationVersion implements Comparable<ApplicationVersion> {
if (this == o) return true;
if ( ! (o instanceof ApplicationVersion)) return false;
ApplicationVersion that = (ApplicationVersion) o;
- return Objects.equals(buildNumber, that.buildNumber)
- && Objects.equals(commit(), that.commit())
- && deployedDirectly == that.deployedDirectly;
+ return id.equals(that.id);
}
@Override
public int hashCode() {
- return Objects.hash(buildNumber, commit(), deployedDirectly);
+ return id.hashCode();
}
@Override
public String toString() {
- return "Application package version: " + stringId()
- + source.map(s -> ", " + s.toString()).orElse("")
- + authorEmail.map(e -> ", by " + e).orElse("")
- + compileVersion.map(v -> ", built against " + v).orElse("")
- + buildTime.map(t -> " at " + t).orElse("") ;
+ return id +
+ source.map(s -> ", " + s).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 */
@@ -230,13 +207,7 @@ public class ApplicationVersion implements Comparable<ApplicationVersion> {
@Override
public int compareTo(ApplicationVersion o) {
- if (buildNumber().isEmpty() || o.buildNumber().isEmpty())
- return Boolean.compare(buildNumber().isPresent(), o.buildNumber.isPresent()); // Unknown version sorts first
-
- if (deployedDirectly != o.deployedDirectly)
- return Boolean.compare( ! deployedDirectly, ! o.deployedDirectly); // Directly deployed versions sort first
-
- return Long.compare(buildNumber().getAsLong(), o.buildNumber().getAsLong());
+ return id.compareTo(o.id);
}
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/deployment/RevisionId.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/deployment/RevisionId.java
index 1e9f412d4da..2ab419b5388 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/deployment/RevisionId.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/deployment/RevisionId.java
@@ -12,48 +12,52 @@ import static ai.vespa.validation.Validation.requireAtLeast;
public class RevisionId implements Comparable<RevisionId> {
private final long number;
- private final boolean production;
+ private final JobId job;
- private RevisionId(long number, boolean production) {
+ private RevisionId(long number, JobId job) {
this.number = number;
- this.production = production;
+ this.job = job;
}
public static RevisionId forProduction(long number) {
- return new RevisionId(requireAtLeast(number, "build number", 1L), true);
+ return new RevisionId(requireAtLeast(number, "build number", 1L), null);
}
- public static RevisionId forDevelopment(long number) {
- return new RevisionId(requireAtLeast(number, "build number", 0L), false);
+ public static RevisionId forDevelopment(long number, JobId job) {
+ return new RevisionId(requireAtLeast(number, "build number", 0L), job);
}
public long number() { return number; }
- public boolean isProduction() { return production; }
+ public boolean isProduction() { return job == null; }
+
+ /** Returns the job for this, if a development revision, or throws if this is a production revision. */
+ public JobId job() { return Objects.requireNonNull(job, "production revisions have no associated job"); }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RevisionId that = (RevisionId) o;
- return number == that.number && production == that.production;
+ return number == that.number && Objects.equals(job, that.job);
}
@Override
public int hashCode() {
- return Objects.hash(number, production);
+ return Objects.hash(number, job);
}
/** Unknown, manual builds sort first, then known manual builds, then production builds, by increasing build number */
@Override
public int compareTo(RevisionId o) {
- return production != o.production ? Boolean.compare(production, o.production)
- : Long.compare(number, o.number);
+ return isProduction() != o.isProduction() ? Boolean.compare(isProduction(), o.isProduction())
+ : Long.compare(number, o.number);
}
@Override
public String toString() {
- return (production ? "prod" : "dev") + " build " + number;
+ return isProduction() ? "build " + number
+ : "dev build " + number + " for " + job.type() + " of " + job.application().instance();
}
}
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 ccdf4390d61..af8965bdeff 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
@@ -7,7 +7,7 @@ import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.InstanceName;
import com.yahoo.config.provision.zone.ZoneId;
-import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId;
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.ApplicationActivity;
@@ -186,10 +186,10 @@ public class Application {
/**
* Returns the oldest application version this has deployed in a permanent zone (not test or staging).
*/
- public Optional<ApplicationVersion> oldestDeployedApplication() {
+ public Optional<RevisionId> oldestDeployedRevision() {
return productionDeployments().values().stream().flatMap(List::stream)
- .map(Deployment::applicationVersion)
- .filter(version -> ! version.isUnknown() && ! version.isDeployedDirectly())
+ .map(Deployment::revision)
+ .filter(RevisionId::isProduction)
.min(Comparator.naturalOrder());
}
@@ -215,15 +215,6 @@ public class Application {
/** Returns the set of deploy keys for this application. */
public Set<PublicKey> deployKeys() { return deployKeys; }
- private static Optional<ApplicationVersion> requireNotUnknown(Optional<ApplicationVersion> latestVersion) {
- Objects.requireNonNull(latestVersion, "latestVersion cannot be null");
- latestVersion.ifPresent(version -> {
- if (version.isUnknown())
- throw new IllegalArgumentException("latestVersion cannot be unknown");
- });
- return latestVersion;
- }
-
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
index 01abca1b2be..5b61996083f 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
@@ -27,7 +27,6 @@ import com.yahoo.vespa.flags.StringFlag;
import com.yahoo.vespa.hosted.controller.api.application.v4.model.DeploymentData;
import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
import com.yahoo.vespa.hosted.controller.api.identifiers.InstanceId;
-import com.yahoo.vespa.hosted.controller.api.identifiers.RevisionId;
import com.yahoo.vespa.hosted.controller.api.integration.billing.BillingController;
import com.yahoo.vespa.hosted.controller.api.integration.billing.Quota;
import com.yahoo.vespa.hosted.controller.api.integration.certificates.EndpointCertificateMetadata;
@@ -42,6 +41,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationV
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ArtifactRepository;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.TesterId;
import com.yahoo.vespa.hosted.controller.api.integration.noderepository.RestartFilter;
import com.yahoo.vespa.hosted.controller.api.integration.secrets.TenantSecretStore;
@@ -163,25 +163,7 @@ public class ApplicationController {
for (InstanceName instance : application.get().deploymentSpec().instanceNames())
if ( ! application.get().instances().containsKey(instance))
application = withNewInstance(application, id.instance(instance));
- // TODO jonmv: remove when data is migrated
- // Each controller will know only about the revisions which we have packages for when they upgrade.
- // The last controller will populate any missing, historic data after it upgrades.
- // When all controllers are upgraded, we can start using the data, and remove this.
- Set<ApplicationVersion> production = new HashSet<>();
- Map<JobId, Set<ApplicationVersion>> development = new HashMap<>();
- for (InstanceName instance : application.get().instances().keySet()) {
- for (JobType type : JobType.allIn(controller.system())) {
- for (Run run : controller.jobController().runs(id.instance(instance), type).values()) {
- ApplicationVersion revision = run.versions().targetApplication();
- if ( ! revision.isDeployedDirectly()) production.add(revision);
- else development.computeIfAbsent(run.id().job(), __ -> new HashSet<>()).add(revision);
- }
- }
- }
- application = application.withRevisions(revisions -> {
- production.addAll(revisions.production()); // These are already properly set, and we want ot keep their hasPackage status.
- return RevisionHistory.ofRevisions(production, development); // All the added data is just written for now. We'll use it later.
- });
+
store(application);
});
count++;
@@ -485,7 +467,7 @@ public class ApplicationController {
throw new IllegalStateException("No deployment expected for " + job + " now, as no job is running");
Version platform = run.versions().sourcePlatform().filter(__ -> deploySourceVersions).orElse(run.versions().targetPlatform());
- ApplicationVersion revision = run.versions().sourceApplication().filter(__ -> deploySourceVersions).orElse(run.versions().targetApplication());
+ RevisionId revision = run.versions().sourceRevision().filter(__ -> deploySourceVersions).orElse(run.versions().targetRevision());
ApplicationPackage applicationPackage = new ApplicationPackage(applicationStore.get(deployment, revision));
try (Lock lock = lock(applicationId)) {
@@ -637,7 +619,7 @@ public class ApplicationController {
deploymentQuota, tenantSecretStores, operatorCertificates,
dryRun));
- return new ActivateResult(new RevisionId(applicationPackage.hash()), preparedApplication.prepareResponse(),
+ return new ActivateResult(new com.yahoo.vespa.hosted.controller.api.identifiers.RevisionId(applicationPackage.hash()), preparedApplication.prepareResponse(),
applicationPackage.zippedContent().length);
} finally {
// Even if prepare fails, routing configuration may need to be updated
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Instance.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Instance.java
index 9ca23ca5d15..402a4bf49a8 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Instance.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Instance.java
@@ -6,8 +6,8 @@ import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.InstanceName;
import com.yahoo.config.provision.zone.ZoneId;
-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.RevisionId;
import com.yahoo.vespa.hosted.controller.application.AssignedRotation;
import com.yahoo.vespa.hosted.controller.application.Change;
import com.yahoo.vespa.hosted.controller.application.Deployment;
@@ -63,16 +63,16 @@ public class Instance {
this.change = Objects.requireNonNull(change, "change cannot be null");
}
- public Instance withNewDeployment(ZoneId zone, ApplicationVersion applicationVersion, Version version,
+ public Instance withNewDeployment(ZoneId zone, RevisionId revision, Version version,
Instant instant, Map<DeploymentMetrics.Warning, Integer> warnings, QuotaUsage quotaUsage) {
// Use info from previous deployment if available, otherwise create a new one.
- Deployment previousDeployment = deployments.getOrDefault(zone, new Deployment(zone, applicationVersion,
+ Deployment previousDeployment = deployments.getOrDefault(zone, new Deployment(zone, revision,
version, instant,
DeploymentMetrics.none,
DeploymentActivity.none,
QuotaUsage.none,
OptionalDouble.empty()));
- Deployment newDeployment = new Deployment(zone, applicationVersion, version, instant,
+ Deployment newDeployment = new Deployment(zone, revision, version, instant,
previousDeployment.metrics().with(warnings),
previousDeployment.activity(),
quotaUsage,
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Change.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Change.java
index b5a4a2a71d7..64cad599168 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Change.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Change.java
@@ -3,6 +3,7 @@ package com.yahoo.vespa.hosted.controller.application;
import com.yahoo.component.Version;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId;
import java.util.Objects;
import java.util.Optional;
@@ -28,22 +29,22 @@ public final class Change {
private final Optional<Version> platform;
/** The application version we are changing to, or empty if none */
- private final Optional<ApplicationVersion> application;
+ private final Optional<RevisionId> revision;
/** Whether this change is a pin to its contained Vespa version, or to the application's current. */
private final boolean pinned;
- private Change(Optional<Version> platform, Optional<ApplicationVersion> application, boolean pinned) {
+ private Change(Optional<Version> platform, Optional<RevisionId> revision, boolean pinned) {
this.platform = requireNonNull(platform, "platform cannot be null");
- this.application = requireNonNull(application, "application cannot be null");
- if (application.isPresent() && (application.get().isUnknown() || application.get().isDeployedDirectly())) {
+ this.revision = requireNonNull(revision, "revision cannot be null");
+ if (revision.isPresent() && ( ! revision.get().isProduction())) {
throw new IllegalArgumentException("Application version to deploy must be a known version");
}
this.pinned = pinned;
}
public Change withoutPlatform() {
- return new Change(Optional.empty(), application, pinned);
+ return new Change(Optional.empty(), revision, pinned);
}
public Change withoutApplication() {
@@ -52,7 +53,7 @@ public final class Change {
/** Returns whether a change should currently be deployed */
public boolean hasTargets() {
- return platform.isPresent() || application.isPresent();
+ return platform.isPresent() || revision.isPresent();
}
/** Returns whether this is the empty change. */
@@ -64,7 +65,7 @@ public final class Change {
public Optional<Version> platform() { return platform; }
/** Returns the application version carried by this. */
- public Optional<ApplicationVersion> application() { return application; }
+ public Optional<RevisionId> revision() { return revision; }
public boolean isPinned() { return pinned; }
@@ -76,30 +77,30 @@ public final class Change {
if (pinned)
throw new IllegalArgumentException("Not allowed to set a platform version when pinned.");
- return new Change(Optional.of(platformVersion), application, pinned);
+ return new Change(Optional.of(platformVersion), revision, pinned);
}
- /** Returns a version of this change which replaces or adds this application change */
- public Change with(ApplicationVersion applicationVersion) {
- return new Change(platform, Optional.of(applicationVersion), pinned);
+ /** Returns a version of this change which replaces or adds this revision change */
+ public Change with(RevisionId revision) {
+ return new Change(platform, Optional.of(revision), pinned);
}
/** Returns a change with the versions of this, and with the platform version pinned. */
public Change withPin() {
- return new Change(platform, application, true);
+ return new Change(platform, revision, true);
}
/** Returns a change with the versions of this, and with the platform version unpinned. */
public Change withoutPin() {
- return new Change(platform, application, false);
+ return new Change(platform, revision, false);
}
/** Returns the change obtained when overwriting elements of the given change with any present in this */
public Change onTopOf(Change other) {
if (platform.isPresent())
other = other.with(platform.get());
- if (application.isPresent())
- other = other.with(application.get());
+ if (revision.isPresent())
+ other = other.with(revision.get());
if (pinned)
other = other.withPin();
return other;
@@ -112,12 +113,12 @@ public final class Change {
Change change = (Change) o;
return pinned == change.pinned &&
Objects.equals(platform, change.platform) &&
- Objects.equals(application, change.application);
+ Objects.equals(revision, change.revision);
}
@Override
public int hashCode() {
- return Objects.hash(platform, application, pinned);
+ return Objects.hash(platform, revision, pinned);
}
@Override
@@ -126,23 +127,23 @@ public final class Change {
if (pinned)
changes.add("pin to " + platform.map(Version::toString).orElse("current platform"));
else
- platform.ifPresent(version -> changes.add("upgrade to " + version.toString()));
- application.ifPresent(version -> changes.add("application change to " + version.stringId()));
+ platform.ifPresent(version -> changes.add("upgrade to " + version));
+ revision.ifPresent(revision -> changes.add("revision change to " + revision));
changes.setEmptyValue("no change");
return changes.toString();
}
- public static Change of(ApplicationVersion applicationVersion) {
- return new Change(Optional.empty(), Optional.of(applicationVersion), false);
+ public static Change of(RevisionId revision) {
+ return new Change(Optional.empty(), Optional.of(revision), false);
}
public static Change of(Version platformChange) {
return new Change(Optional.of(platformChange), Optional.empty(), false);
}
- /** Returns whether this change carries an application downgrade relative to the given version. */
- public boolean downgrades(ApplicationVersion version) {
- return application.map(version::compareTo).orElse(0) > 0;
+ /** Returns whether this change carries a revision downgrade relative to the given revision. */
+ public boolean downgrades(RevisionId revision) {
+ return this.revision.map(revision::compareTo).orElse(0) > 0;
}
/** Returns whether this change carries a platform downgrade relative to the given version. */
@@ -150,9 +151,9 @@ public final class Change {
return platform.map(version::compareTo).orElse(0) > 0;
}
- /** Returns whether this change carries an application upgrade relative to the given version. */
- public boolean upgrades(ApplicationVersion version) {
- return application.map(version::compareTo).orElse(0) < 0;
+ /** Returns whether this change carries a revision upgrade relative to the given revision. */
+ public boolean upgrades(RevisionId revision) {
+ return this.revision.map(revision::compareTo).orElse(0) < 0;
}
/** Returns whether this change carries a platform upgrade relative to the given version. */
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Deployment.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Deployment.java
index 2b79bd3f3e9..2e4afb4e004 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Deployment.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Deployment.java
@@ -3,7 +3,7 @@ package com.yahoo.vespa.hosted.controller.application;
import com.yahoo.component.Version;
import com.yahoo.config.provision.zone.ZoneId;
-import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId;
import java.time.Instant;
import java.util.Objects;
@@ -18,7 +18,7 @@ import java.util.OptionalDouble;
public class Deployment {
private final ZoneId zone;
- private final ApplicationVersion applicationVersion;
+ private final RevisionId revision;
private final Version version;
private final Instant deployTime;
private final DeploymentMetrics metrics;
@@ -26,10 +26,10 @@ public class Deployment {
private final QuotaUsage quota;
private final OptionalDouble cost;
- public Deployment(ZoneId zone, ApplicationVersion applicationVersion, Version version, Instant deployTime,
+ public Deployment(ZoneId zone, RevisionId revision, Version version, Instant deployTime,
DeploymentMetrics metrics, DeploymentActivity activity, QuotaUsage quota, OptionalDouble cost) {
this.zone = Objects.requireNonNull(zone, "zone cannot be null");
- this.applicationVersion = Objects.requireNonNull(applicationVersion, "applicationVersion cannot be null");
+ this.revision = Objects.requireNonNull(revision, "revision cannot be null");
this.version = Objects.requireNonNull(version, "version cannot be null");
this.deployTime = Objects.requireNonNull(deployTime, "deployTime cannot be null");
this.metrics = Objects.requireNonNull(metrics, "deploymentMetrics cannot be null");
@@ -41,8 +41,8 @@ public class Deployment {
/** Returns the zone this was deployed to */
public ZoneId zone() { return zone; }
- /** Returns the deployed application version */
- public ApplicationVersion applicationVersion() { return applicationVersion; }
+ /** Returns the deployed application revision */
+ public RevisionId revision() { return revision; }
/** Returns the deployed Vespa version */
public Version version() { return version; }
@@ -65,26 +65,26 @@ public class Deployment {
public OptionalDouble cost() { return cost; }
public Deployment recordActivityAt(Instant instant) {
- return new Deployment(zone, applicationVersion, version, deployTime, metrics,
+ return new Deployment(zone, revision, version, deployTime, metrics,
activity.recordAt(instant, metrics), quota, cost);
}
public Deployment withMetrics(DeploymentMetrics metrics) {
- return new Deployment(zone, applicationVersion, version, deployTime, metrics, activity, quota, cost);
+ return new Deployment(zone, revision, version, deployTime, metrics, activity, quota, cost);
}
public Deployment withQuota(QuotaUsage quota) {
- return new Deployment(zone, applicationVersion, version, deployTime, metrics, activity, quota, cost);
+ return new Deployment(zone, revision, version, deployTime, metrics, activity, quota, cost);
}
public Deployment withCost(double cost) {
if (this.cost.isPresent() && Double.compare(this.cost.getAsDouble(), cost) == 0) return this;
- return new Deployment(zone, applicationVersion, version, deployTime, metrics, activity, quota, OptionalDouble.of(cost));
+ return new Deployment(zone, revision, version, deployTime, metrics, activity, quota, OptionalDouble.of(cost));
}
public Deployment withoutCost() {
if (cost.isEmpty()) return this;
- return new Deployment(zone, applicationVersion, version, deployTime, metrics, activity, quota, OptionalDouble.empty());
+ return new Deployment(zone, revision, version, deployTime, metrics, activity, quota, OptionalDouble.empty());
}
@Override
@@ -93,7 +93,7 @@ public class Deployment {
if (o == null || getClass() != o.getClass()) return false;
Deployment that = (Deployment) o;
return zone.equals(that.zone) &&
- applicationVersion.equals(that.applicationVersion) &&
+ revision.equals(that.revision) &&
version.equals(that.version) &&
deployTime.equals(that.deployTime) &&
metrics.equals(that.metrics) &&
@@ -104,12 +104,12 @@ public class Deployment {
@Override
public int hashCode() {
- return Objects.hash(zone, applicationVersion, version, deployTime, metrics, activity, quota, cost);
+ return Objects.hash(zone, revision, version, deployTime, metrics, activity, quota, cost);
}
@Override
public String toString() {
- return "deployment to " + zone + " of " + applicationVersion + " on version " + version + " at " + deployTime;
+ return "deployment to " + zone + " of " + revision + " on version " + version + " at " + deployTime;
}
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/InstanceList.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/InstanceList.java
index 99b14bf289a..030f7678b8c 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/InstanceList.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/InstanceList.java
@@ -42,7 +42,7 @@ public class InstanceList extends AbstractFilteringList<ApplicationId, InstanceL
*/
public InstanceList compatibleWithPlatform(Version platform, Function<ApplicationId, VersionCompatibility> compatibility) {
return matching(id -> instance(id).productionDeployments().values().stream()
- .flatMap(deployment -> deployment.applicationVersion().compileVersion().stream())
+ .flatMap(deployment -> application(id).revisions().get(deployment.revision()).compileVersion().stream())
.noneMatch(version -> compatibility.apply(id).refuse(platform, version)));
}
@@ -95,7 +95,7 @@ public class InstanceList extends AbstractFilteringList<ApplicationId, InstanceL
/** Returns the subset of instances which are currently deploying a new revision */
public InstanceList changingRevision() {
- return matching(id -> instance(id).change().application().isPresent());
+ return matching(id -> instance(id).change().revision().isPresent());
}
/** Returns the subset of instances which currently have failing jobs on the given version */
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 a82e77da130..a2c5b8f4a9b 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
@@ -19,6 +19,7 @@ import com.yahoo.vespa.hosted.controller.Instance;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId;
import com.yahoo.vespa.hosted.controller.application.Change;
import com.yahoo.vespa.hosted.controller.application.Deployment;
@@ -126,9 +127,9 @@ public class DeploymentStatus {
}
/** Whether any job is failing on versions selected by the given filter, with errors other than lack of capacity in a test zone.. */
- public boolean hasFailures(Predicate<ApplicationVersion> versionFilter) {
+ public boolean hasFailures(Predicate<RevisionId> revisionFilter) {
return ! allJobs.failingHard()
- .matching(job -> versionFilter.test(job.lastTriggered().get().versions().targetApplication()))
+ .matching(job -> revisionFilter.test(job.lastTriggered().get().versions().targetRevision()))
.isEmpty();
}
@@ -263,10 +264,10 @@ public class DeploymentStatus {
Change candidate = Change.empty();
for (ApplicationVersion version : application.revisions().deployable(ascending)) {
// A revision is only a candidate if it upgrades, and does not downgrade, this instance.
- Change change = Change.of(version);
+ Change change = Change.of(version.id());
if (application.productionDeployments().getOrDefault(instance, List.of()).stream()
- .anyMatch(deployment -> change.downgrades(deployment.applicationVersion()))) continue;
- if ( ! application.require(instance).change().application().map(change::upgrades).orElse(true)) continue;
+ .anyMatch(deployment -> change.downgrades(deployment.revision()))) continue;
+ if ( ! application.require(instance).change().revision().map(change::upgrades).orElse(true)) continue;
if (hasCompleted(instance, change))
if (ascending) continue; // Keep looking for the next revision which is an upgrade, or ...
else return Change.empty(); // ... if the latest is already complete, there's nothing outstanding.
@@ -275,7 +276,7 @@ public class DeploymentStatus {
skippedCumulativeRisk += version.risk();
nextRisk = nextRisk > 0 ? nextRisk : version.risk();
// If it's not yet ready to roll out, we keep looking.
- Optional<Instant> readyAt = status.dependenciesCompletedAt(Change.of(version), Optional.empty());
+ Optional<Instant> readyAt = status.dependenciesCompletedAt(Change.of(version.id()), Optional.empty());
if (readyAt.map(now::isBefore).orElse(true)) continue;
// It's ready. If looking for the latest, max risk is 0, and we'll return now; otherwise, we _may_ keep on looking for more.
@@ -337,9 +338,9 @@ public class DeploymentStatus {
// When computing eager test jobs for outstanding changes, assume current change completes successfully.
Optional<Deployment> deployment = deploymentFor(job);
Optional<Version> existingPlatform = deployment.map(Deployment::version);
- Optional<ApplicationVersion> existingApplication = deployment.map(Deployment::applicationVersion);
- boolean deployingCompatibilityChange = areIncompatible(existingPlatform, change.application(), instance)
- || areIncompatible(change.platform(), existingApplication, instance);
+ Optional<RevisionId> existingRevision = deployment.map(Deployment::revision);
+ boolean deployingCompatibilityChange = areIncompatible(existingPlatform, change.revision(), job)
+ || areIncompatible(change.platform(), existingRevision, job);
if (assumeUpgradesSucceed) {
if (deployingCompatibilityChange) // No eager tests for this.
return;
@@ -347,34 +348,36 @@ public class DeploymentStatus {
Change currentChange = application.require(instance).change();
Versions target = Versions.from(currentChange, application, deployment, systemVersion);
existingPlatform = Optional.of(target.targetPlatform());
- existingApplication = Optional.of(target.targetApplication());
+ existingRevision = Optional.of(target.targetRevision());
}
List<Job> toRun = new ArrayList<>();
List<Change> changes = deployingCompatibilityChange ? List.of(change) : changes(job, step, change);
for (Change partial : changes) {
Job jobToRun = new Job(job.type(),
- Versions.from(partial, application, existingPlatform, existingApplication, systemVersion),
+ Versions.from(partial, application, existingPlatform, existingRevision, systemVersion),
step.readyAt(partial, Optional.of(job)),
partial);
toRun.add(jobToRun);
// Assume first partial change is applied before the second.
existingPlatform = Optional.of(jobToRun.versions.targetPlatform());
- existingApplication = Optional.of(jobToRun.versions.targetApplication());
+ existingRevision = Optional.of(jobToRun.versions.targetRevision());
}
jobs.put(job, toRun);
});
return jobs;
}
- private boolean areIncompatible(Optional<Version> platform, Optional<ApplicationVersion> application, InstanceName instance) {
+ private boolean areIncompatible(Optional<Version> platform, Optional<RevisionId> revision, JobId job) {
+ Optional<Version> compileVersion = revision.map(application.revisions()::get)
+ .flatMap(ApplicationVersion::compileVersion);
return platform.isPresent()
- && application.flatMap(ApplicationVersion::compileVersion).isPresent()
- && versionCompatibility.apply(instance).refuse(platform.get(), application.get().compileVersion().get());
+ && compileVersion.isPresent()
+ && versionCompatibility.apply(job.application().instance()).refuse(platform.get(), compileVersion.get());
}
/** Changes to deploy with the given job, possibly split in two steps. */
private List<Change> changes(JobId job, StepStatus step, Change change) {
- if (change.platform().isEmpty() || change.application().isEmpty() || change.isPinned())
+ if (change.platform().isEmpty() || change.revision().isEmpty() || change.isPinned())
return List.of(change);
if ( step.completedAt(change.withoutApplication(), Optional.of(job)).isPresent()
@@ -749,7 +752,7 @@ public class DeploymentStatus {
@Override
Optional<Instant> completedAt(Change change, Optional<JobId> dependent) {
return ( (change.platform().isEmpty() || change.platform().equals(instance.change().platform()))
- && (change.application().isEmpty() || change.application().equals(instance.change().application()))
+ && (change.revision().isEmpty() || change.revision().equals(instance.change().revision()))
|| step().steps().stream().noneMatch(step -> step.concerns(prod)))
? dependenciesCompletedAt(change, dependent).or(() -> Optional.of(Instant.EPOCH).filter(__ -> change.hasTargets()))
: Optional.empty();
@@ -763,7 +766,7 @@ public class DeploymentStatus {
while ( blocker.window().includes(current)
&& now.plus(Duration.ofDays(7)).isAfter(current)
&& ( change.platform().isPresent() && blocker.blocksVersions()
- || change.application().isPresent() && blocker.blocksRevisions())) {
+ || change.revision().isPresent() && blocker.blocksRevisions())) {
blocked = true;
current = current.plus(Duration.ofHours(1)).truncatedTo(ChronoUnit.HOURS);
}
@@ -804,7 +807,7 @@ public class DeploymentStatus {
if (job.firstFailing().isEmpty() || ! job.firstFailing().get().hasEnded()) return Optional.empty();
Versions lastVersions = job.lastCompleted().get().versions();
if (change.platform().isPresent() && ! change.platform().get().equals(lastVersions.targetPlatform())) return Optional.empty();
- if (change.application().isPresent() && ! change.application().get().equals(lastVersions.targetApplication())) return Optional.empty();
+ if (change.revision().isPresent() && ! change.revision().get().equals(lastVersions.targetRevision())) return Optional.empty();
if (job.id().type().environment().isTest() && job.isNodeAllocationFailure()) return Optional.empty();
Instant firstFailing = job.firstFailing().get().end().get();
@@ -841,14 +844,14 @@ public class DeploymentStatus {
&& ! existingDeployment.map(Deployment::version).equals(change.platform()))
return Optional.empty();
- if ( change.application().isPresent()
- && ! existingDeployment.map(Deployment::applicationVersion).equals(change.application())
+ if ( change.revision().isPresent()
+ && ! existingDeployment.map(Deployment::revision).equals(change.revision())
&& dependent.equals(job())) // Job should (re-)run in this case, but other dependents need not wait.
return Optional.empty();
Change fullChange = status.application().require(job.id().application().instance()).change();
- if (existingDeployment.map(deployment -> ! (change.upgrades(deployment.version()) || change.upgrades(deployment.applicationVersion()))
- && (fullChange.downgrades(deployment.version()) || fullChange.downgrades(deployment.applicationVersion())))
+ if (existingDeployment.map(deployment -> ! (change.upgrades(deployment.version()) || change.upgrades(deployment.revision()))
+ && (fullChange.downgrades(deployment.version()) || fullChange.downgrades(deployment.revision())))
.orElse(false))
return job.lastCompleted().flatMap(Run::end);
@@ -901,7 +904,7 @@ public class DeploymentStatus {
Optional.of(deployment),
status.systemVersion)))
.orElseGet(() -> (change.platform().isEmpty() || change.platform().get().equals(run.versions().targetPlatform()))
- && (change.application().isEmpty() || change.application().get().equals(run.versions().targetApplication()))))
+ && (change.revision().isEmpty() || change.revision().get().equals(run.versions().targetRevision()))))
.status(RunStatus.success)
.asList().stream()
.map(run -> run.end().get())
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 889ac6a6de4..54703308102 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
@@ -17,6 +17,7 @@ import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId;
import com.yahoo.vespa.hosted.controller.application.ApplicationList;
import com.yahoo.vespa.hosted.controller.application.Change;
import com.yahoo.vespa.hosted.controller.application.Deployment;
@@ -88,11 +89,11 @@ public class DeploymentTrigger {
DeploymentStatus status = jobs.deploymentStatus(application.get());
for (InstanceName instanceName : application.get().deploymentSpec().instanceNames()) {
Change outstanding = outstandingChange(status, instanceName);
- if ( outstanding.hasTargets()
+ if (outstanding.hasTargets()
&& status.instanceSteps().get(instanceName)
.readyAt(outstanding)
.map(readyAt -> ! readyAt.isAfter(clock.instant())).orElse(false)
- && acceptNewApplicationVersion(status, instanceName, outstanding.application().get())) {
+ && acceptNewRevision(status, instanceName, outstanding.revision().get())) {
application = application.with(instanceName,
instance -> withRemainingChange(instance, outstanding.onTopOf(instance.change()), status));
}
@@ -104,7 +105,9 @@ public class DeploymentTrigger {
/** Returns any outstanding change for the given instance, coupled with any necessary platform upgrade. */
private Change outstandingChange(DeploymentStatus status, InstanceName instance) {
Change outstanding = status.outstandingChange(instance);
- Optional<Version> compileVersion = outstanding.application().flatMap(ApplicationVersion::compileVersion);
+ Optional<Version> compileVersion = outstanding.revision()
+ .map(status.application().revisions()::get)
+ .flatMap(ApplicationVersion::compileVersion);
// If the outstanding revision requires a certain platform for compatibility, add that here.
VersionCompatibility compatibility = applications().versionCompatibility(status.application().id().instance(instance));
@@ -234,7 +237,7 @@ public class DeploymentTrigger {
DeploymentStatus status = jobs.deploymentStatus(application);
Change change = instance.change();
- if ( ! upgradeRevision && change.application().isPresent()) change = change.withoutApplication();
+ if ( ! upgradeRevision && change.revision().isPresent()) change = change.withoutApplication();
if ( ! upgradePlatform && change.platform().isPresent()) change = change.withoutPlatform();
Versions versions = Versions.from(change, application, status.deploymentFor(job), controller.readSystemVersion());
DeploymentStatus.Job toTrigger = new DeploymentStatus.Job(job.type(), versions, Optional.of(controller.clock().instant()), instance.change());
@@ -255,9 +258,9 @@ public class DeploymentTrigger {
private List<JobId> forceTriggerManualJob(JobId job, String reason) {
Run last = jobs.last(job).orElseThrow(() -> new IllegalArgumentException(job + " has never been run"));
Versions target = new Versions(controller.readSystemVersion(),
- last.versions().targetApplication(),
+ last.versions().targetRevision(),
Optional.of(last.versions().targetPlatform()),
- Optional.of(last.versions().targetApplication()));
+ Optional.of(last.versions().targetRevision()));
jobs.start(job.application(), job.type(), target, true, Optional.of(reason));
return List.of(job);
}
@@ -433,16 +436,16 @@ public class DeploymentTrigger {
// ---------- Change management o_O ----------
- private boolean acceptNewApplicationVersion(DeploymentStatus status, InstanceName instance, ApplicationVersion version) {
+ private boolean acceptNewRevision(DeploymentStatus status, InstanceName instance, RevisionId revision) {
if (status.application().deploymentSpec().instance(instance).isEmpty()) return false; // Unknown instance.
- boolean isChangingRevision = status.application().require(instance).change().application().isPresent();
+ boolean isChangingRevision = status.application().require(instance).change().revision().isPresent();
DeploymentInstanceSpec spec = status.application().deploymentSpec().requireInstance(instance);
- Predicate<ApplicationVersion> versionFilter = spec.revisionTarget() == DeploymentSpec.RevisionTarget.next
- ? failing -> status.application().require(instance).change().application().get().compareTo(failing) == 0
- : failing -> version.compareTo(failing) > 0;
+ Predicate<RevisionId> revisionFilter = spec.revisionTarget() == DeploymentSpec.RevisionTarget.next
+ ? failing -> status.application().require(instance).change().revision().get().compareTo(failing) == 0
+ : failing -> revision.compareTo(failing) > 0;
switch (spec.revisionChange()) {
case whenClear: return ! isChangingRevision;
- case whenFailing: return ! isChangingRevision || status.hasFailures(versionFilter);
+ case whenFailing: return ! isChangingRevision || status.hasFailures(revisionFilter);
case always: return true;
default: throw new IllegalStateException("Unknown revision upgrade policy");
}
@@ -460,7 +463,7 @@ public class DeploymentTrigger {
// ---------- Version and job helpers ----------
private Job deploymentJob(Instance instance, Versions versions, JobType jobType, JobStatus jobStatus, Instant availableSince) {
- return new Job(instance, versions, jobType, availableSince, jobStatus.isNodeAllocationFailure(), instance.change().application().isPresent());
+ return new Job(instance, versions, jobType, availableSince, jobStatus.isNodeAllocationFailure(), instance.change().revision().isPresent());
}
// ---------- Data containers ----------
@@ -495,7 +498,7 @@ public class DeploymentTrigger {
public String toString() {
return jobType + " for " + instanceId +
" on (" + versions.targetPlatform() + versions.sourcePlatform().map(version -> " <-- " + version).orElse("") +
- ", " + versions.targetApplication().stringId() + versions.sourceApplication().map(version -> " <-- " + version.stringId()).orElse("") +
+ ", " + versions.targetRevision() + versions.sourceRevision().map(version -> " <-- " + version).orElse("") +
"), ready since " + availableSince;
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java
index 0df4c0015bd..ce4bb70c174 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java
@@ -38,6 +38,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.configserver.PrepareRes
import com.yahoo.vespa.hosted.controller.api.integration.configserver.ServiceConvergence;
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.RevisionId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.TesterCloud;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.TesterId;
@@ -184,15 +185,15 @@ public class InternalStepRunner implements StepRunner {
Versions versions = controller.jobController().run(id).get().versions();
logger.log("Deploying platform version " +
versions.sourcePlatform().orElse(versions.targetPlatform()) +
- " and application version " +
- versions.sourceApplication().orElse(versions.targetApplication()).stringId() + " ...");
+ " and application " +
+ versions.sourceRevision().orElse(versions.targetRevision()) + " ...");
return deployReal(id, true, logger);
}
private Optional<RunStatus> deployReal(RunId id, DualLogger logger) {
Versions versions = controller.jobController().run(id).get().versions();
logger.log("Deploying platform version " + versions.targetPlatform() +
- " and application version " + versions.targetApplication().stringId() + " ...");
+ " and application " + versions.targetRevision() + " ...");
return deployReal(id, false, logger);
}
@@ -786,14 +787,14 @@ public class InternalStepRunner implements StepRunner {
Application application = controller.applications().requireApplication(TenantAndApplicationId.from(run.id().application()));
Notifications notifications = application.deploymentSpec().requireInstance(run.id().application().instance()).notifications();
- boolean newCommit = application.require(run.id().application().instance()).change().application()
- .map(run.versions().targetApplication()::equals)
+ boolean newCommit = application.require(run.id().application().instance()).change().revision()
+ .map(run.versions().targetRevision()::equals)
.orElse(false);
When when = newCommit ? failingCommit : failing;
List<String> recipients = new ArrayList<>(notifications.emailAddressesFor(when));
if (notifications.emailRolesFor(when).contains(author))
- run.versions().targetApplication().authorEmail().ifPresent(recipients::add);
+ application.revisions().get(run.versions().targetRevision()).authorEmail().ifPresent(recipients::add);
if (recipients.isEmpty())
return;
@@ -904,7 +905,7 @@ public class InternalStepRunner implements StepRunner {
/** Returns the application package for the tester application, assembled from a generated config, fat-jar and services.xml. */
private ApplicationPackage testerPackage(RunId id) {
- ApplicationVersion version = controller.jobController().run(id).get().versions().targetApplication();
+ RevisionId revision = controller.jobController().run(id).get().versions().targetRevision();
DeploymentSpec spec = controller.applications().requireApplication(TenantAndApplicationId.from(id.application())).deploymentSpec();
ZoneId zone = id.type().zone(controller.system());
@@ -914,7 +915,7 @@ public class InternalStepRunner implements StepRunner {
useTesterCertificate,
testerResourcesFor(zone, spec.requireInstance(id.application().instance())),
controller.controllerConfig().steprunner().testerapp());
- byte[] testPackage = controller.applications().applicationStore().getTester(id.application().tenant(), id.application().application(), version);
+ byte[] testPackage = controller.applications().applicationStore().getTester(id.application().tenant(), id.application().application(), revision);
byte[] deploymentXml = deploymentXml(id.tester(),
spec.athenzDomain(),
spec.requireInstance(id.application().instance()).athenzService(zone.environment(), zone.region()));
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 46533b8b063..57c817e6cd5 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
@@ -17,6 +17,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.LogEntry;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId;
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.TestReport;
@@ -119,7 +120,7 @@ public class JobController {
for (ApplicationId id : instances())
for (JobType type : jobs(id)) {
locked(id, type, runs -> { // Runs are not modified here, and are written as they were.
- curator.readLastRun(id, type).ifPresent(curator::writeLastRun);
+ curator.readLastRun(id, type).ifPresent(run -> curator.writeLastRun(run, controller.applications().requireApplication(TenantAndApplicationId.from(id))));
});
}
}
@@ -452,12 +453,14 @@ public class JobController {
.map(ApplicationPackage::new);
long previousBuild = previousVersion.map(latestVersion -> latestVersion.buildNumber().getAsLong()).orElse(0L);
String packageHash = applicationPackage.bundleHash() + ApplicationPackage.calculateHash(testPackageBytes);
- version.set(ApplicationVersion.forProduction(revision, 1 + previousBuild, authorEmail,
+ RevisionId revisionId = RevisionId.forProduction(1 + previousBuild);
+ version.set(ApplicationVersion.forProduction(revisionId,
+ revision,
+ authorEmail,
applicationPackage.compileVersion(),
applicationPackage.buildTime(),
sourceUrl,
revision.map(SourceRevision::commit),
- false,
Optional.of(packageHash),
description,
risk));
@@ -466,7 +469,7 @@ public class JobController {
.orElseGet(() -> ApplicationPackageDiff.diffAgainstEmpty(applicationPackage));
applications.applicationStore().put(id.tenant(),
id.application(),
- version.get(),
+ version.get().id(),
applicationPackage.zippedContent(),
testPackageBytes,
diff);
@@ -487,12 +490,12 @@ public class JobController {
private LockedApplication withPrunedPackages(LockedApplication application){
TenantAndApplicationId id = application.get().id();
- Optional<ApplicationVersion> oldestDeployed = application.get().oldestDeployedApplication();
+ Optional<RevisionId> oldestDeployed = application.get().oldestDeployedRevision();
if (oldestDeployed.isPresent()) {
controller.applications().applicationStore().prune(id.tenant(), id.application(), oldestDeployed.get());
for (ApplicationVersion version : application.get().revisions().withPackage())
- if (version.compareTo(oldestDeployed.get()) < 0)
+ if (version.id().compareTo(oldestDeployed.get()) < 0)
application = application.withRevisions(revisions -> revisions.with(version.withoutPackage()));
}
return application;
@@ -501,11 +504,11 @@ public class JobController {
/** Forget revisions no longer present in any relevant job history. */
private void pruneRevisions(Run run) {
TenantAndApplicationId applicationId = TenantAndApplicationId.from(run.id().application());
- boolean isProduction = run.versions().targetApplication().id().isProduction();
+ boolean isProduction = run.versions().targetRevision().isProduction();
(isProduction ? deploymentStatus(controller.applications().requireApplication(applicationId)).jobs().asList().stream()
: Stream.of(jobStatus(run.id().job())))
.flatMap(jobs -> jobs.runs().values().stream())
- .map(r -> r.versions().targetApplication().id())
+ .map(r -> r.versions().targetRevision())
.filter(id -> id.isProduction() == isProduction)
.min(naturalOrder())
.ifPresent(oldestRevision -> {
@@ -529,11 +532,12 @@ public class JobController {
/** Orders a run of the given type, or throws an IllegalStateException if that job type is already running. */
public void start(ApplicationId id, JobType type, Versions versions, boolean isRedeployment, JobProfile profile, Optional<String> reason) {
- if (versions.targetApplication().compileVersion()
+ ApplicationVersion revision = controller.applications().requireApplication(TenantAndApplicationId.from(id)).revisions().get(versions.targetRevision());
+ if (revision.compileVersion()
.map(version -> controller.applications().versionCompatibility(id).refuse(versions.targetPlatform(), version))
.orElse(false))
throw new IllegalArgumentException("Will not start a job with incompatible platform version (" + versions.targetPlatform() + ") " +
- "and compile versions (" + versions.targetApplication().compileVersion().get() + ")");
+ "and compile versions (" + revision.compileVersion().get() + ")");
locked(id, type, __ -> {
Optional<Run> last = last(id, type);
@@ -541,7 +545,7 @@ public class JobController {
throw new IllegalArgumentException("Cannot start " + type + " for " + id + "; it is already running!");
RunId newId = new RunId(id, type, last.map(run -> run.id().number()).orElse(0L) + 1);
- curator.writeLastRun(Run.initial(newId, versions, isRedeployment, controller.clock().instant(), profile, reason));
+ curator.writeLastRun(Run.initial(newId, versions, isRedeployment, controller.clock().instant(), profile, reason), controller.applications().requireApplication(TenantAndApplicationId.from(id)));
metric.jobStarted(newId.job());
});
}
@@ -565,21 +569,22 @@ public class JobController {
Optional<Run> lastRun = last(id, type);
lastRun.filter(run -> ! run.hasEnded()).ifPresent(run -> abortAndWait(run.id()));
- long build = 1 + lastRun.map(run -> run.versions().targetApplication().buildNumber().orElse(0)).orElse(0L);
- ApplicationVersion version = ApplicationVersion.forDevelopment(build, applicationPackage.compileVersion());
+ long build = 1 + lastRun.map(run -> run.versions().targetRevision().number()).orElse(0L);
+ RevisionId revisionId = RevisionId.forDevelopment(build, new JobId(id, type));
+ ApplicationVersion version = ApplicationVersion.forDevelopment(revisionId, applicationPackage.compileVersion());
byte[] diff = getDiff(applicationPackage, deploymentId, lastRun);
controller.applications().lockApplicationOrThrow(TenantAndApplicationId.from(id), application -> {
- controller.applications().applicationStore().putDev(deploymentId, version, applicationPackage.zippedContent(), diff);
+ controller.applications().applicationStore().putDev(deploymentId, version.id(), applicationPackage.zippedContent(), diff);
Version targetPlatform = platform.orElseGet(() -> findTargetPlatform(applicationPackage, lastRun, id));
+ controller.applications().store(application.withRevisions(revisions -> revisions.with(version)));
start(id,
type,
- new Versions(targetPlatform, version, lastRun.map(run -> run.versions().targetPlatform()), lastRun.map(run -> run.versions().targetApplication())),
+ new Versions(targetPlatform, version.id(), lastRun.map(run -> run.versions().targetPlatform()), lastRun.map(run -> run.versions().targetRevision())),
false,
dryRun ? JobProfile.developmentDryRun : JobProfile.development,
Optional.empty());
- controller.applications().store(application.withRevisions(revisions -> revisions.with(version, new JobId(id, type))));
});
locked(id, type, __ -> {
@@ -589,7 +594,7 @@ public class JobController {
/* Application package diff against previous version, or against empty version if previous does not exist or is invalid */
private byte[] getDiff(ApplicationPackage applicationPackage, DeploymentId deploymentId, Optional<Run> lastRun) {
- return lastRun.map(run -> run.versions().targetApplication())
+ return lastRun.map(run -> run.versions().targetRevision())
.map(prevVersion -> {
ApplicationPackage previous;
try {
@@ -678,19 +683,21 @@ public class JobController {
/** Locks all runs and modifies the list of historic runs for the given application and job type. */
private void locked(ApplicationId id, JobType type, Consumer<SortedMap<RunId, Run>> modifications) {
+ Application application = controller.applications().requireApplication(TenantAndApplicationId.from(id));
try (Lock __ = curator.lock(id, type)) {
SortedMap<RunId, Run> runs = new TreeMap<>(curator.readHistoricRuns(id, type));
modifications.accept(runs);
- curator.writeHistoricRuns(id, type, runs.values());
+ curator.writeHistoricRuns(id, type, runs.values(), application);
}
}
/** Locks and modifies the run with the given id, provided it is still active. */
public void locked(RunId id, UnaryOperator<Run> modifications) {
+ Application application = controller.applications().requireApplication(TenantAndApplicationId.from(id.application()));
try (Lock __ = curator.lock(id.application(), id.type())) {
active(id).ifPresent(run -> {
run = modifications.apply(run);
- curator.writeLastRun(run);
+ curator.writeLastRun(run, application);
});
}
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobList.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobList.java
index d06bdc45583..639702128d3 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobList.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobList.java
@@ -7,6 +7,7 @@ import com.yahoo.config.provision.InstanceName;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId;
import java.time.Instant;
import java.util.Collection;
@@ -174,8 +175,8 @@ public class JobList extends AbstractFilteringList<JobStatus, JobList> {
}
/** Returns the subset of jobs where the run of the indicated type was on the given version */
- public JobList on(ApplicationVersion version) {
- return matching(run -> run.versions().targetApplication().equals(version));
+ public JobList on(RevisionId revision) {
+ return matching(run -> run.versions().targetRevision().equals(revision));
}
/** Returns the subset of jobs where the run of the indicated type was on the given version */
@@ -196,7 +197,7 @@ public class JobList extends AbstractFilteringList<JobStatus, JobList> {
if (job.isSuccess()) return false;
if (job.lastSuccess().isEmpty()) return true; // An application which never succeeded is surely bad.
if ( ! job.firstFailing().get().versions().targetPlatform().equals(job.lastSuccess().get().versions().targetPlatform())) return false; // Version change may be to blame.
- return ! job.firstFailing().get().versions().targetApplication().equals(job.lastSuccess().get().versions().targetApplication()); // Return whether there is an application change.
+ return ! job.firstFailing().get().versions().targetRevision().equals(job.lastSuccess().get().versions().targetRevision()); // Return whether there is an application change.
}
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/RevisionHistory.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/RevisionHistory.java
index cfab02ea35f..5bdc980f11a 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/RevisionHistory.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/RevisionHistory.java
@@ -1,5 +1,6 @@
package com.yahoo.vespa.hosted.controller.deployment;
+import ai.vespa.validation.Validation;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId;
@@ -16,6 +17,7 @@ import java.util.Optional;
import java.util.OptionalLong;
import java.util.TreeMap;
+import static ai.vespa.validation.Validation.require;
import static java.util.Collections.emptyNavigableMap;
import static java.util.stream.Collectors.toList;
@@ -77,39 +79,35 @@ public class RevisionHistory {
return new RevisionHistory(production, development);
}
- /** Returns a copy of this with the production revision added or updated. */
+ /** Returns a copy of this with the revision added or updated. */
public RevisionHistory with(ApplicationVersion revision) {
- if ( ! production.isEmpty() && revision.bundleHash().flatMap(hash -> production.lastEntry().getValue().bundleHash().map(hash::equals)).orElse(false))
- revision = revision.skipped();
+ if (revision.id().isProduction()) {
+ if ( ! production.isEmpty() && revision.bundleHash().flatMap(hash -> production.lastEntry().getValue().bundleHash().map(hash::equals)).orElse(false))
+ revision = revision.skipped();
- NavigableMap<RevisionId, ApplicationVersion> production = new TreeMap<>(this.production);
- production.put(revision.id(), revision);
- return new RevisionHistory(production, development);
- }
-
- /** Returns a copy of this with the new development revision added, and the previous version without a package. */
- public RevisionHistory with(ApplicationVersion revision, JobId job) {
- NavigableMap<JobId, NavigableMap<RevisionId, ApplicationVersion>> development = new TreeMap<>(this.development);
- NavigableMap<RevisionId, ApplicationVersion> revisions = development.compute(job, (__, old) -> new TreeMap<>(old != null ? old : emptyNavigableMap()));
- if ( ! revisions.isEmpty()) revisions.compute(revisions.lastKey(), (__, last) -> last.withoutPackage());
- revisions.put(revision.id(), revision);
- return new RevisionHistory(production, development);
+ NavigableMap<RevisionId, ApplicationVersion> production = new TreeMap<>(this.production);
+ production.put(revision.id(), revision);
+ return new RevisionHistory(production, development);
+ }
+ else {
+ NavigableMap<JobId, NavigableMap<RevisionId, ApplicationVersion>> development = new TreeMap<>(this.development);
+ NavigableMap<RevisionId, ApplicationVersion> revisions = development.compute(revision.id().job(), (__, old) -> new TreeMap<>(old != null ? old : emptyNavigableMap()));
+ if ( ! revisions.isEmpty()) revisions.compute(revisions.lastKey(), (__, last) -> last.withoutPackage());
+ revisions.put(revision.id(), revision);
+ return new RevisionHistory(production, development);
+ }
}
// Fallback for when an application version isn't known for the given key.
- private static ApplicationVersion revisionOf(RevisionId id, boolean production) {
- return new ApplicationVersion(Optional.empty(), OptionalLong.of(id.number()), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), ! production, Optional.empty(), false, false, Optional.empty(), 0);
+ private static ApplicationVersion revisionOf(RevisionId id) {
+ return new ApplicationVersion(id, Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), false, false, Optional.empty(), 0);
}
/** Returns the production {@link ApplicationVersion} with this revision ID. */
public ApplicationVersion get(RevisionId id) {
- return production.getOrDefault(id, revisionOf(id, true));
- }
-
- /** Returns the development {@link ApplicationVersion} for the give job, with this revision ID. */
- public ApplicationVersion get(RevisionId id, JobId job) {
- return development.getOrDefault(job, emptyNavigableMap())
- .getOrDefault(id, revisionOf(id, false));
+ return id.isProduction() ? production.getOrDefault(id, revisionOf(id))
+ : development.getOrDefault(id.job(), emptyNavigableMap())
+ .getOrDefault(id, revisionOf(id));
}
/** Returns the last submitted production build. */
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/Versions.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/Versions.java
index 5299c59b774..f4c4b8bebd4 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/Versions.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/Versions.java
@@ -5,6 +5,7 @@ import com.yahoo.component.Version;
import com.yahoo.text.Text;
import com.yahoo.vespa.hosted.controller.Application;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId;
import com.yahoo.vespa.hosted.controller.application.Change;
import com.yahoo.vespa.hosted.controller.application.Deployment;
@@ -22,24 +23,24 @@ import static java.util.Objects.requireNonNull;
public class Versions {
private final Version targetPlatform;
- private final ApplicationVersion targetApplication;
+ private final RevisionId targetRevision;
private final Optional<Version> sourcePlatform;
- private final Optional<ApplicationVersion> sourceApplication;
+ private final Optional<RevisionId> sourceRevision;
- public Versions(Version targetPlatform, ApplicationVersion targetApplication, Optional<Version> sourcePlatform,
- Optional<ApplicationVersion> sourceApplication) {
- if (sourcePlatform.isPresent() ^ sourceApplication.isPresent())
+ public Versions(Version targetPlatform, RevisionId targetRevision, Optional<Version> sourcePlatform,
+ Optional<RevisionId> sourceRevision) {
+ if (sourcePlatform.isPresent() ^ sourceRevision.isPresent())
throw new IllegalArgumentException("Sources must both be present or absent.");
this.targetPlatform = requireNonNull(targetPlatform);
- this.targetApplication = requireNonNull(targetApplication);
+ this.targetRevision = requireNonNull(targetRevision);
this.sourcePlatform = requireNonNull(sourcePlatform);
- this.sourceApplication = requireNonNull(sourceApplication);
+ this.sourceRevision = requireNonNull(sourceRevision);
}
/** A copy of this, without source versions. */
public Versions withoutSources() {
- return new Versions(targetPlatform, targetApplication, Optional.empty(), Optional.empty());
+ return new Versions(targetPlatform, targetRevision, Optional.empty(), Optional.empty());
}
/** Target platform version for this */
@@ -47,9 +48,9 @@ public class Versions {
return targetPlatform;
}
- /** Target application version for this */
- public ApplicationVersion targetApplication() {
- return targetApplication;
+ /** Target revision for this */
+ public RevisionId targetRevision() {
+ return targetRevision;
}
/** Source platform version for this */
@@ -58,27 +59,27 @@ public class Versions {
}
/** Source application version for this */
- public Optional<ApplicationVersion> sourceApplication() {
- return sourceApplication;
+ public Optional<RevisionId> sourceRevision() {
+ return sourceRevision;
}
/** Returns whether source versions are present and match those of the given job other versions. */
public boolean sourcesMatchIfPresent(Versions versions) {
return (sourcePlatform.map(targetPlatform::equals).orElse(true) ||
sourcePlatform.equals(versions.sourcePlatform())) &&
- (sourceApplication.map(targetApplication::equals).orElse(true) ||
- sourceApplication.equals(versions.sourceApplication()));
+ (sourceRevision.map(targetRevision::equals).orElse(true) ||
+ sourceRevision.equals(versions.sourceRevision()));
}
public boolean targetsMatch(Versions versions) {
return targetPlatform.equals(versions.targetPlatform()) &&
- targetApplication.equals(versions.targetApplication());
+ targetRevision.equals(versions.targetRevision());
}
/** Returns wheter this change could result in the given target versions. */
public boolean targetsMatch(Change change) {
return change.platform().map(targetPlatform::equals).orElse(true)
- && change.application().map(targetApplication::equals).orElse(true);
+ && change.revision().map(targetRevision::equals).orElse(true);
}
@Override
@@ -87,43 +88,43 @@ public class Versions {
if ( ! (o instanceof Versions)) return false;
Versions versions = (Versions) o;
return Objects.equals(targetPlatform, versions.targetPlatform) &&
- Objects.equals(targetApplication, versions.targetApplication) &&
+ Objects.equals(targetRevision, versions.targetRevision) &&
Objects.equals(sourcePlatform, versions.sourcePlatform) &&
- Objects.equals(sourceApplication, versions.sourceApplication);
+ Objects.equals(sourceRevision, versions.sourceRevision);
}
@Override
public int hashCode() {
- return Objects.hash(targetPlatform, targetApplication, sourcePlatform, sourceApplication);
+ return Objects.hash(targetPlatform, targetRevision, sourcePlatform, sourceRevision);
}
@Override
public String toString() {
- return Text.format("platform %s%s, application %s%s",
- sourcePlatform.filter(source -> !source.equals(targetPlatform))
+ return Text.format("platform %s%s, revision %s%s",
+ sourcePlatform.filter(source -> ! source.equals(targetPlatform))
.map(source -> source + " -> ").orElse(""),
targetPlatform,
- sourceApplication.filter(source -> !source.equals(targetApplication))
- .map(source -> source.stringId() + " -> ").orElse(""),
- targetApplication.stringId());
+ sourceRevision.filter(source -> ! source.equals(targetRevision))
+ .map(source -> source + " -> ").orElse(""),
+ targetRevision);
}
/** Create versions using given change and application */
public static Versions from(Change change, Application application, Optional<Version> existingPlatform,
- Optional<ApplicationVersion> existingApplication, Version defaultPlatformVersion) {
+ Optional<RevisionId> existingRevision, Version defaultPlatformVersion) {
return new Versions(targetPlatform(application, change, existingPlatform, defaultPlatformVersion),
- targetApplication(application, change, existingApplication),
+ targetRevision(application, change, existingRevision),
existingPlatform,
- existingApplication);
+ existingRevision);
}
/** Create versions using given change and application */
public static Versions from(Change change, Application application, Optional<Deployment> deployment,
Version defaultPlatformVersion) {
return new Versions(targetPlatform(application, change, deployment.map(Deployment::version), defaultPlatformVersion),
- targetApplication(application, change, deployment.map(Deployment::applicationVersion)),
+ targetRevision(application, change, deployment.map(Deployment::revision)),
deployment.map(Deployment::version),
- deployment.map(Deployment::applicationVersion));
+ deployment.map(Deployment::revision));
}
private static Version targetPlatform(Application application, Change change, Optional<Version> existing,
@@ -135,16 +136,16 @@ public class Versions {
.orElseGet(() -> application.oldestDeployedPlatform().orElse(defaultVersion));
}
- private static ApplicationVersion targetApplication(Application application, Change change,
- Optional<ApplicationVersion> existing) {
- return change.application()
+ private static RevisionId targetRevision(Application application, Change change,
+ Optional<RevisionId> existing) {
+ return change.revision()
.or(() -> existing)
- .orElseGet(() -> defaultApplicationVersion(application));
+ .orElseGet(() -> defaultRevision(application));
}
- private static ApplicationVersion defaultApplicationVersion(Application application) {
- return application.oldestDeployedApplication()
- .or(() -> application.revisions().last())
+ private static RevisionId defaultRevision(Application application) {
+ return application.oldestDeployedRevision()
+ .or(() -> application.revisions().last().map(ApplicationVersion::id))
.orElseThrow(() -> new IllegalStateException("no known prod revisions, but asked for one, for " + application));
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentUpgrader.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentUpgrader.java
index 7392b4c6e38..144c27b9e5e 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentUpgrader.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentUpgrader.java
@@ -51,8 +51,8 @@ public class DeploymentUpgrader extends ControllerMaintainer {
if ( ! deployment.zone().environment().isManuallyDeployed()) continue;
Run last = controller().jobController().last(job).get();
- Versions target = new Versions(targetPlatform, last.versions().targetApplication(), Optional.of(last.versions().targetPlatform()), Optional.of(last.versions().targetApplication()));
- if (last.versions().targetApplication().compileVersion()
+ Versions target = new Versions(targetPlatform, last.versions().targetRevision(), Optional.of(last.versions().targetPlatform()), Optional.of(last.versions().targetRevision()));
+ if (application.revisions().get(last.versions().targetRevision()).compileVersion()
.map(version -> controller().applications().versionCompatibility(instance.id()).refuse(version, target.targetPlatform()))
.orElse(false)) continue;
if ( ! deployment.version().isBefore(target.targetPlatform())) continue;
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 68965ba8ef9..a2483e41a64 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
@@ -4,9 +4,11 @@ package com.yahoo.vespa.hosted.controller.persistence;
import com.yahoo.component.Version;
import com.yahoo.config.application.api.DeploymentSpec;
import com.yahoo.config.application.api.ValidationOverrides;
+import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.InstanceName;
import com.yahoo.config.provision.RegionName;
+import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.security.KeyUtils;
import com.yahoo.slime.ArrayTraverser;
@@ -20,6 +22,7 @@ import com.yahoo.vespa.hosted.controller.Instance;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId;
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;
@@ -51,6 +54,7 @@ import java.util.Optional;
import java.util.OptionalInt;
import java.util.OptionalLong;
import java.util.Set;
+import java.util.function.Function;
/**
* Serializes {@link Application}s to/from slime.
@@ -154,6 +158,12 @@ public class ApplicationSerializer {
private static final String deploymentCostField = "cost";
+ private final SystemName system;
+
+ public ApplicationSerializer(SystemName system) {
+ this.system = system;
+ }
+
// ------------------ Serialization
public Slime toSlime(Application application) {
@@ -171,7 +181,6 @@ public class ApplicationSerializer {
root.setDouble(queryQualityField, application.metrics().queryServiceQuality());
root.setDouble(writeQualityField, application.metrics().writeServiceQuality());
deployKeysToSlime(application.deployKeys(), root.setArray(pemDeployKeysField));
- revisionsToSlime(application.revisions().withPackage(), root.setArray(versionsField));
revisionsToSlime(application.revisions(), root.setArray(prodVersionsField), root.setArray(devVersionsField));
instancesToSlime(application, root.setArray(instancesField));
return slime;
@@ -181,11 +190,11 @@ public class ApplicationSerializer {
for (Instance instance : application.instances().values()) {
Cursor instanceObject = array.addObject();
instanceObject.setString(instanceNameField, instance.name().value());
- deploymentsToSlime(instance.deployments().values(), instanceObject.setArray(deploymentsField));
+ deploymentsToSlime(instance.deployments().values(), application, instanceObject.setArray(deploymentsField));
toSlime(instance.jobPauses(), instanceObject.setObject(deploymentJobsField));
assignedRotationsToSlime(instance.rotations(), instanceObject);
toSlime(instance.rotationStatus(), instanceObject.setArray(rotationStatusField));
- toSlime(instance.change(), instanceObject, deployingField);
+ toSlime(instance.change(), application, instanceObject, deployingField);
}
}
@@ -193,16 +202,16 @@ public class ApplicationSerializer {
deployKeys.forEach(key -> array.addString(KeyUtils.toPem(key)));
}
- private void deploymentsToSlime(Collection<Deployment> deployments, Cursor array) {
+ private void deploymentsToSlime(Collection<Deployment> deployments, Application application, Cursor array) {
for (Deployment deployment : deployments)
- deploymentToSlime(deployment, array.addObject());
+ deploymentToSlime(deployment, application.revisions()::get, array.addObject());
}
- private void deploymentToSlime(Deployment deployment, Cursor object) {
+ private void deploymentToSlime(Deployment deployment, Function<RevisionId, ApplicationVersion> compatibility, Cursor object) {
zoneIdToSlime(deployment.zone(), object.setObject(zoneField));
object.setString(versionField, deployment.version().toString());
object.setLong(deployTimeField, deployment.at().toEpochMilli());
- toSlime(deployment.applicationVersion(), object.setObject(applicationPackageRevisionField));
+ toSlime(compatibility.apply(deployment.revision()), object.setObject(applicationPackageRevisionField));
deploymentMetricsToSlime(deployment.metrics(), object);
deployment.activity().lastQueried().ifPresent(instant -> object.setLong(lastQueriedField, instant.toEpochMilli()));
deployment.activity().lastWritten().ifPresent(instant -> object.setLong(lastWrittenField, instant.toEpochMilli()));
@@ -276,14 +285,14 @@ public class ApplicationSerializer {
});
}
- private void toSlime(Change deploying, Cursor parentObject, String fieldName) {
+ private void toSlime(Change deploying, Application application, Cursor parentObject, String fieldName) {
if (deploying.isEmpty()) return;
Cursor object = parentObject.setObject(fieldName);
if (deploying.platform().isPresent())
object.setString(versionField, deploying.platform().get().toString());
- if (deploying.application().isPresent())
- toSlime(deploying.application().get(), object);
+ if (deploying.revision().isPresent())
+ toSlime(application.revisions().get(deploying.revision().get()), object);
if (deploying.isPinned())
object.setBool(pinnedField, true);
}
@@ -338,21 +347,20 @@ public class ApplicationSerializer {
Set<PublicKey> deployKeys = deployKeysFromSlime(root.field(pemDeployKeysField));
List<Instance> instances = instancesFromSlime(id, root.field(instancesField));
OptionalLong projectId = SlimeUtils.optionalLong(root.field(projectIdField));
- RevisionHistory revisions = revisionsFromSlime(root.field(versionsField), root.field(prodVersionsField), root.field(devVersionsField), id);
+ RevisionHistory revisions = revisionsFromSlime(root.field(prodVersionsField), root.field(devVersionsField), id);
return new Application(id, createdAt, deploymentSpec, validationOverrides,
deploymentIssueId, ownershipIssueId, owner, majorVersion, metrics,
deployKeys, projectId, revisions, instances);
}
- // TODO jonmv: read only from prodVersionsArray, once data is migrated.
- private RevisionHistory revisionsFromSlime(Inspector versionsArray, Inspector prodVersionsArray, Inspector devVersionsArray, TenantAndApplicationId id) {
- // Once last controller updates storage after upgrade, these should be in sync.
- List<ApplicationVersion> revisions = prodVersionsArray.valid() ? revisionsFromSlime(prodVersionsArray)
- : revisionsFromSlime(versionsArray);
+ private RevisionHistory revisionsFromSlime(Inspector prodVersionsArray, Inspector devVersionsArray, TenantAndApplicationId id) {
+ List<ApplicationVersion> revisions = revisionsFromSlime(prodVersionsArray, null);
Map<JobId, List<ApplicationVersion>> devRevisions = new HashMap<>();
- devVersionsArray.traverse((ArrayTraverser) (__, devRevisionsObject) ->
- devRevisions.put(jobIdFromSlime(id, devRevisionsObject), revisionsFromSlime(devRevisionsObject.field(versionsField))));
+ devVersionsArray.traverse((ArrayTraverser) (__, devRevisionsObject) -> {
+ JobId job = jobIdFromSlime(id, devRevisionsObject);
+ devRevisions.put(jobIdFromSlime(id, devRevisionsObject), revisionsFromSlime(devRevisionsObject.field(versionsField), job));
+ });
return RevisionHistory.ofRevisions(revisions, devRevisions);
}
@@ -362,9 +370,9 @@ public class ApplicationSerializer {
JobType.fromJobName(idObject.field(jobTypeField).asString()));
}
- private List<ApplicationVersion> revisionsFromSlime(Inspector versionsArray) {
+ private List<ApplicationVersion> revisionsFromSlime(Inspector versionsArray, JobId job) {
List<ApplicationVersion> revisions = new ArrayList<>();
- versionsArray.traverse((ArrayTraverser) (__, revisionObject) -> revisions.add(applicationVersionFromSlime(revisionObject)));
+ versionsArray.traverse((ArrayTraverser) (__, revisionObject) -> revisions.add(applicationVersionFromSlime(revisionObject, job)));
return revisions;
}
@@ -372,7 +380,7 @@ public class ApplicationSerializer {
List<Instance> instances = new ArrayList<>();
field.traverse((ArrayTraverser) (name, object) -> {
InstanceName instanceName = InstanceName.from(object.field(instanceNameField).asString());
- List<Deployment> deployments = deploymentsFromSlime(object.field(deploymentsField));
+ List<Deployment> deployments = deploymentsFromSlime(object.field(deploymentsField), id.instance(instanceName));
Map<JobType, Instant> jobPauses = jobPausesFromSlime(object.field(deploymentJobsField));
List<AssignedRotation> assignedRotations = assignedRotationsFromSlime(object);
RotationStatus rotationStatus = rotationStatusFromSlime(object);
@@ -393,15 +401,16 @@ public class ApplicationSerializer {
return keys;
}
- private List<Deployment> deploymentsFromSlime(Inspector array) {
+ private List<Deployment> deploymentsFromSlime(Inspector array, ApplicationId id) {
List<Deployment> deployments = new ArrayList<>();
- array.traverse((ArrayTraverser) (int i, Inspector item) -> deployments.add(deploymentFromSlime(item)));
+ array.traverse((ArrayTraverser) (int i, Inspector item) -> deployments.add(deploymentFromSlime(item, id)));
return deployments;
}
- private Deployment deploymentFromSlime(Inspector deploymentObject) {
- return new Deployment(zoneIdFromSlime(deploymentObject.field(zoneField)),
- applicationVersionFromSlime(deploymentObject.field(applicationPackageRevisionField)),
+ private Deployment deploymentFromSlime(Inspector deploymentObject, ApplicationId id) {
+ ZoneId zone = zoneIdFromSlime(deploymentObject.field(zoneField));
+ return new Deployment(zone,
+ revisionFromSlime(deploymentObject.field(applicationPackageRevisionField), new JobId(id, JobType.from(system, zone).get())),
Version.fromString(deploymentObject.field(versionField).asString()),
SlimeUtils.instant(deploymentObject.field(deployTimeField)),
deploymentMetricsFromSlime(deploymentObject.field(deploymentMetricsField)),
@@ -458,27 +467,30 @@ public class ApplicationSerializer {
return ZoneId.from(object.field(environmentField).asString(), object.field(regionField).asString());
}
- private ApplicationVersion applicationVersionFromSlime(Inspector object) {
- if ( ! object.valid()) return ApplicationVersion.unknown;
- OptionalLong applicationBuildNumber = SlimeUtils.optionalLong(object.field(applicationBuildNumberField));
- if (applicationBuildNumber.isEmpty())
- return ApplicationVersion.unknown;
+ private RevisionId revisionFromSlime(Inspector object, JobId job) {
+ long build = object.field(applicationBuildNumberField).asLong();
+ boolean production = object.field(deployedDirectlyField).valid() // TODO jonmv: remove after migration
+ && build > 0
+ && ! object.field(deployedDirectlyField).asBool();
+ return production ? RevisionId.forProduction(build) : RevisionId.forDevelopment(build, job);
+ }
+ private ApplicationVersion applicationVersionFromSlime(Inspector object, JobId job) {
+ RevisionId id = revisionFromSlime(object, job);
Optional<SourceRevision> sourceRevision = sourceRevisionFromSlime(object.field(sourceRevisionField));
Optional<String> authorEmail = SlimeUtils.optionalString(object.field(authorEmailField));
Optional<Version> compileVersion = SlimeUtils.optionalString(object.field(compileVersionField)).map(Version::fromString);
Optional<Instant> buildTime = SlimeUtils.optionalInstant(object.field(buildTimeField));
Optional<String> sourceUrl = SlimeUtils.optionalString(object.field(sourceUrlField));
Optional<String> commit = SlimeUtils.optionalString(object.field(commitField));
- boolean deployedDirectly = object.field(deployedDirectlyField).asBool();
- boolean hasPackage = ! object.field(hasPackageField).valid() || object.field(hasPackageField).asBool(); // TODO jonmv: remove default
+ boolean hasPackage = object.field(hasPackageField).asBool();
boolean shouldSkip = object.field(shouldSkipField).asBool();
Optional<String> description = SlimeUtils.optionalString(object.field(descriptionField));
int risk = (int) object.field(riskField).asLong();
Optional<String> bundleHash = SlimeUtils.optionalString(object.field(bundleHashField));
- return new ApplicationVersion(sourceRevision, applicationBuildNumber, authorEmail, compileVersion, buildTime, sourceUrl,
- commit, deployedDirectly, bundleHash, hasPackage, shouldSkip, description, risk);
+ return new ApplicationVersion(id, sourceRevision, authorEmail, compileVersion, buildTime, sourceUrl,
+ commit, bundleHash, hasPackage, shouldSkip, description, risk);
}
private Optional<SourceRevision> sourceRevisionFromSlime(Inspector object) {
@@ -504,7 +516,7 @@ public class ApplicationSerializer {
if (versionFieldValue.valid())
change = Change.of(Version.fromString(versionFieldValue.asString()));
if (object.field(applicationBuildNumberField).valid())
- change = change.with(applicationVersionFromSlime(object));
+ change = change.with(revisionFromSlime(object, null));
if (object.field(pinnedField).asBool())
change = change.withPin();
return change;
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java
index e5327cb5362..0bfdd53eeab 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java
@@ -7,6 +7,7 @@ import com.yahoo.component.Version;
import com.yahoo.concurrent.UncheckedTimeoutException;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.HostName;
+import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.TenantName;
import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.path.Path;
@@ -20,11 +21,13 @@ import com.yahoo.vespa.flags.Flags;
import com.yahoo.vespa.flags.StringFlag;
import com.yahoo.vespa.hosted.controller.Application;
import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
+import com.yahoo.vespa.hosted.controller.api.integration.ServiceRegistry;
import com.yahoo.vespa.hosted.controller.api.integration.archive.ArchiveBucket;
import com.yahoo.vespa.hosted.controller.api.integration.certificates.EndpointCertificateMetadata;
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.vcmr.VespaChangeRequest;
+import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneRegistry;
import com.yahoo.vespa.hosted.controller.application.TenantAndApplicationId;
import com.yahoo.vespa.hosted.controller.auditlog.AuditLog;
import com.yahoo.vespa.hosted.controller.deployment.RetriggerEntry;
@@ -103,7 +106,6 @@ public class CuratorDb {
private final ControllerVersionSerializer controllerVersionSerializer = new ControllerVersionSerializer();
private final ConfidenceOverrideSerializer confidenceOverrideSerializer = new ConfidenceOverrideSerializer();
private final TenantSerializer tenantSerializer = new TenantSerializer();
- private final ApplicationSerializer applicationSerializer = new ApplicationSerializer();
private final RunSerializer runSerializer = new RunSerializer();
private final OsVersionSerializer osVersionSerializer = new OsVersionSerializer();
private final OsVersionTargetSerializer osVersionTargetSerializer = new OsVersionTargetSerializer(osVersionSerializer);
@@ -112,6 +114,7 @@ public class CuratorDb {
private final ZoneRoutingPolicySerializer zoneRoutingPolicySerializer = new ZoneRoutingPolicySerializer(routingPolicySerializer);
private final AuditLogSerializer auditLogSerializer = new AuditLogSerializer();
private final NameServiceQueueSerializer nameServiceQueueSerializer = new NameServiceQueueSerializer();
+ private final ApplicationSerializer applicationSerializer;
private final Curator curator;
private final Duration tryLockTimeout;
@@ -125,14 +128,15 @@ public class CuratorDb {
private final Map<Path, Pair<Integer, NavigableMap<RunId, Run>>> cachedHistoricRuns = new ConcurrentHashMap<>();
@Inject
- public CuratorDb(Curator curator, FlagSource flagSource) {
- this(curator, defaultTryLockTimeout, flagSource);
+ public CuratorDb(Curator curator, FlagSource flagSource, ServiceRegistry services) {
+ this(curator, defaultTryLockTimeout, flagSource, services.zoneRegistry().system());
}
- CuratorDb(Curator curator, Duration tryLockTimeout, FlagSource flagSource) {
+ CuratorDb(Curator curator, Duration tryLockTimeout, FlagSource flagSource, SystemName system) {
this.curator = curator;
this.tryLockTimeout = tryLockTimeout;
this.lockScheme = Flags.CONTROLLER_LOCK_SCHEME.bindTo(flagSource);
+ this.applicationSerializer = new ApplicationSerializer(system);
}
/** Returns all hostnames configured to be part of this ZooKeeper cluster */
@@ -383,7 +387,7 @@ public class CuratorDb {
}
public Optional<Tenant> readTenant(TenantName name) {
- return readSlime(tenantPath(name)).map(bytes -> tenantSerializer.tenantFrom(bytes));
+ return readSlime(tenantPath(name)).map(tenantSerializer::tenantFrom);
}
public List<Tenant> readTenants() {
@@ -415,7 +419,7 @@ public class CuratorDb {
.map(stat -> cachedApplications.compute(path, (__, old) ->
old != null && old.getFirst() == stat.getVersion()
? old
- : new Pair<>(stat.getVersion(), read(path, applicationSerializer::fromSlime).get())).getSecond());
+ : new Pair<>(stat.getVersion(), read(path, bytes -> applicationSerializer.fromSlime(bytes)).get())).getSecond());
}
public List<Application> readApplications(boolean canFail) {
@@ -458,13 +462,13 @@ public class CuratorDb {
// -------------- Job Runs ------------------------------------------------
- public void writeLastRun(Run run) {
- curator.set(lastRunPath(run.id().application(), run.id().type()), asJson(runSerializer.toSlime(run)));
+ public void writeLastRun(Run run, Application application) {
+ curator.set(lastRunPath(run.id().application(), run.id().type()), asJson(runSerializer.toSlime(run, application)));
}
- public void writeHistoricRuns(ApplicationId id, JobType type, Iterable<Run> runs) {
+ public void writeHistoricRuns(ApplicationId id, JobType type, Iterable<Run> runs, Application application) {
Path path = runsPath(id, type);
- curator.set(path, asJson(runSerializer.toSlime(runs)));
+ curator.set(path, asJson(runSerializer.toSlime(runs, application)));
}
public Optional<Run> readLastRun(ApplicationId id, JobType type) {
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/MockCuratorDb.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/MockCuratorDb.java
index 65c9859ad72..d7391c69bf6 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/MockCuratorDb.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/MockCuratorDb.java
@@ -2,6 +2,8 @@
package com.yahoo.vespa.hosted.controller.persistence;
import com.google.inject.Inject;
+import com.yahoo.cloud.config.ConfigserverConfig;
+import com.yahoo.config.provision.SystemName;
import com.yahoo.vespa.curator.mock.MockCurator;
import com.yahoo.vespa.flags.InMemoryFlagSource;
@@ -18,21 +20,21 @@ public class MockCuratorDb extends CuratorDb {
private final MockCurator curator;
@Inject
- public MockCuratorDb() {
- this("test-controller:2222");
+ public MockCuratorDb(ConfigserverConfig config) {
+ this("test-controller:2222", SystemName.from(config.system()));
}
- public MockCuratorDb(String zooKeeperEnsembleConnectionSpec) {
- this(new MockCurator() {
- @Override
- public String zooKeeperEnsembleConnectionSpec() {
- return zooKeeperEnsembleConnectionSpec;
- }
- });
+ public MockCuratorDb(SystemName system) {
+ this("test-controller:2222", system);
}
- public MockCuratorDb(MockCurator curator) {
- super(curator, Duration.ofMillis(100), new InMemoryFlagSource());
+ public MockCuratorDb(String zooKeeperEnsembleConnectionSpec, SystemName system) {
+ this(new MockCurator() { @Override public String zooKeeperEnsembleConnectionSpec() { return zooKeeperEnsembleConnectionSpec; } },
+ system);
+ }
+
+ public MockCuratorDb(MockCurator curator, SystemName system) {
+ super(curator, Duration.ofMillis(100), new InMemoryFlagSource(), system);
this.curator = curator;
}
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 afe45bf6a1b..ea932fd19c8 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
@@ -10,8 +10,10 @@ import com.yahoo.slime.Inspector;
import com.yahoo.slime.ObjectTraverser;
import com.yahoo.slime.Slime;
import com.yahoo.slime.SlimeUtils;
+import com.yahoo.vespa.hosted.controller.Application;
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.RevisionId;
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.deployment.ConvergenceSummary;
@@ -30,6 +32,7 @@ import java.util.NavigableMap;
import java.util.Optional;
import java.util.OptionalLong;
import java.util.TreeMap;
+import java.util.function.Function;
import static com.yahoo.vespa.hosted.controller.deployment.RunStatus.aborted;
import static com.yahoo.vespa.hosted.controller.deployment.RunStatus.deploymentFailed;
@@ -74,7 +77,6 @@ class RunSerializer {
// - REMOVING FIELDS: Stop reading the field first. Stop writing it on a later version.
// - CHANGING THE FORMAT OF A FIELD: Don't do it bro.
- // TODO: Remove "steps" when there are no traces of it in the controllers
private static final String stepsField = "steps";
private static final String stepDetailsField = "stepDetails";
private static final String startTimeField = "startTime";
@@ -134,11 +136,12 @@ class RunSerializer {
steps.put(typedStep, new StepInfo(typedStep, stepStatusOf(status.asString()), startTime));
});
- return new Run(new RunId(ApplicationId.fromSerializedForm(runObject.field(applicationField).asString()),
+ RunId id = new RunId(ApplicationId.fromSerializedForm(runObject.field(applicationField).asString()),
JobType.fromJobName(runObject.field(jobTypeField).asString()),
- runObject.field(numberField).asLong()),
+ runObject.field(numberField).asLong());
+ return new Run(id,
steps,
- versionsFromSlime(runObject.field(versionsField)),
+ versionsFromSlime(runObject.field(versionsField), id),
runObject.field(isRedeploymentField).asBool(),
SlimeUtils.instant(runObject.field(startField)),
SlimeUtils.optionalInstant(runObject.field(endField)),
@@ -155,38 +158,26 @@ class RunSerializer {
SlimeUtils.optionalString(runObject.field(reasonField)));
}
- private Versions versionsFromSlime(Inspector versionsObject) {
+ private Versions versionsFromSlime(Inspector versionsObject, RunId id) {
Version targetPlatformVersion = Version.fromString(versionsObject.field(platformVersionField).asString());
- ApplicationVersion targetApplicationVersion = applicationVersionFrom(versionsObject);
+ RevisionId targetRevision = revisionFrom(versionsObject, id);
Optional<Version> sourcePlatformVersion = versionsObject.field(sourceField).valid()
? Optional.of(Version.fromString(versionsObject.field(sourceField).field(platformVersionField).asString()))
: Optional.empty();
- Optional<ApplicationVersion> sourceApplicationVersion = versionsObject.field(sourceField).valid()
- ? Optional.of(applicationVersionFrom(versionsObject.field(sourceField)))
+ Optional<RevisionId> sourceRevision = versionsObject.field(sourceField).valid()
+ ? Optional.of(revisionFrom(versionsObject.field(sourceField), id))
: Optional.empty();
- return new Versions(targetPlatformVersion, targetApplicationVersion, sourcePlatformVersion, sourceApplicationVersion);
+ return new Versions(targetPlatformVersion, targetRevision, sourcePlatformVersion, sourceRevision);
}
- private ApplicationVersion applicationVersionFrom(Inspector versionObject) {
- if ( ! versionObject.field(buildField).valid())
- return ApplicationVersion.unknown;
-
+ private RevisionId revisionFrom(Inspector versionObject, RunId id) {
long buildNumber = versionObject.field(buildField).asLong();
- Optional<SourceRevision> source = Optional.of(new SourceRevision(versionObject.field(repositoryField).asString(),
- versionObject.field(branchField).asString(),
- versionObject.field(commitField).asString()))
- .filter(revision -> ! revision.commit().isBlank() && ! revision.repository().isBlank() && ! revision.branch().isBlank());
- Optional<String> authorEmail = SlimeUtils.optionalString(versionObject.field(authorEmailField));
- Optional<Version> compileVersion = SlimeUtils.optionalString(versionObject.field(compileVersionField)).map(Version::fromString);
- Optional<Instant> buildTime = SlimeUtils.optionalInstant(versionObject.field(buildTimeField));
- Optional<String> sourceUrl = SlimeUtils.optionalString(versionObject.field(sourceUrlField));
- Optional<String> commit = SlimeUtils.optionalString(versionObject.field(commitField));
- boolean deployedDirectly = versionObject.field(deployedDirectlyField).asBool();
- Optional<String> bundleHash = SlimeUtils.optionalString(versionObject.field(bundleHashField));
-
- return new ApplicationVersion(source, OptionalLong.of(buildNumber), authorEmail, compileVersion, buildTime, sourceUrl, commit, deployedDirectly, bundleHash, false, false, Optional.empty(), 0);
+ boolean production = versionObject.field(deployedDirectlyField).valid() // TODO jonmv: remove after migration
+ && buildNumber > 0
+ && ! versionObject.field(deployedDirectlyField).asBool();
+ return production ? RevisionId.forProduction(buildNumber) : RevisionId.forDevelopment(buildNumber, id.job());
}
// Don't change this — introduce a separate array instead.
@@ -211,20 +202,24 @@ class RunSerializer {
summaryArray.entry(12).asLong()));
}
- Slime toSlime(Iterable<Run> runs) {
+ Slime toSlime(Iterable<Run> runs, Application application) {
Slime slime = new Slime();
Cursor runArray = slime.setArray();
- runs.forEach(run -> toSlime(run, runArray.addObject()));
+ runs.forEach(run -> toSlime(run, application.revisions()::get, runArray.addObject()));
return slime;
}
- Slime toSlime(Run run) {
+ Slime toSlime(Run run, Application application) {
+ return toSlime(run, application.revisions()::get);
+ }
+
+ Slime toSlime(Run run, Function<RevisionId, ApplicationVersion> compatilibity) {
Slime slime = new Slime();
- toSlime(run, slime.setObject());
+ toSlime(run, compatilibity, slime.setObject());
return slime;
}
- private void toSlime(Run run, Cursor runObject) {
+ private void toSlime(Run run, Function<RevisionId, ApplicationVersion> compatibility, Cursor runObject) {
runObject.setString(applicationField, run.id().application().serializedForm());
runObject.setString(jobTypeField, run.id().type().jobName());
runObject.setBool(isRedeploymentField, run.isRedeployment());
@@ -249,10 +244,10 @@ class RunSerializer {
stepDetailsObject.setObject(valueOf(step)).setLong(startTimeField, valueOf(startTime))));
Cursor versionsObject = runObject.setObject(versionsField);
- toSlime(run.versions().targetPlatform(), run.versions().targetApplication(), versionsObject);
+ toSlime(run.versions().targetPlatform(), compatibility.apply(run.versions().targetRevision()), versionsObject);
run.versions().sourcePlatform().ifPresent(sourcePlatformVersion -> {
toSlime(sourcePlatformVersion,
- run.versions().sourceApplication()
+ run.versions().sourceRevision().map(compatibility)
.orElseThrow(() -> new IllegalArgumentException("Source versions must be both present or absent.")),
versionsObject.setObject(sourceField));
});
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 620e4101c36..e635fc20053 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
@@ -5,6 +5,7 @@ import ai.vespa.hosted.api.Signatures;
import ai.vespa.http.DomainName;
import ai.vespa.http.HttpURL;
import ai.vespa.http.HttpURL.Query;
+import ai.vespa.validation.Validation;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Joiner;
@@ -259,7 +260,7 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/deploying")) return deploying(path.get("tenant"), path.get("application"), path.get("instance"), request);
if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/deploying/pin")) return deploying(path.get("tenant"), path.get("application"), path.get("instance"), request);
if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/job")) return JobControllerApiHandlerHelper.jobTypeResponse(controller, appIdFromPath(path), request.getUri());
- if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/job/{jobtype}")) return JobControllerApiHandlerHelper.runResponse(controller.jobController().runs(appIdFromPath(path), jobTypeFromPath(path)).descendingMap(), Optional.ofNullable(request.getProperty("limit")), request.getUri());
+ if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/job/{jobtype}")) return JobControllerApiHandlerHelper.runResponse(controller.applications().requireApplication(TenantAndApplicationId.from(path.get("tenant"), path.get("application"))), controller.jobController().runs(appIdFromPath(path), jobTypeFromPath(path)).descendingMap(), Optional.ofNullable(request.getProperty("limit")), request.getUri()); // (((\(✘෴✘)/)))
if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/job/{jobtype}/package")) return devApplicationPackage(appIdFromPath(path), jobTypeFromPath(path));
if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/job/{jobtype}/diff/{number}")) return devApplicationPackageDiff(runIdFromPath(path));
if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/job/{jobtype}/test-config")) return testConfig(appIdFromPath(path), jobTypeFromPath(path));
@@ -804,8 +805,8 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
throw new IllegalArgumentException("Only manually deployed zones have dev packages");
ZoneId zone = type.zone(controller.system());
- ApplicationVersion version = controller.jobController().last(id, type).get().versions().targetApplication();
- byte[] applicationPackage = controller.applications().applicationStore().get(new DeploymentId(id, zone), version);
+ RevisionId revision = controller.jobController().last(id, type).get().versions().targetRevision();
+ byte[] applicationPackage = controller.applications().applicationStore().get(new DeploymentId(id, zone), revision);
return new ZipResponse(id.toFullString() + "." + zone.value() + ".zip", applicationPackage);
}
@@ -817,30 +818,27 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
}
private HttpResponse applicationPackage(String tenantName, String applicationName, HttpRequest request) {
- var tenantAndApplication = TenantAndApplicationId.from(tenantName, applicationName);
- List<ApplicationVersion> versions = controller.applications().requireApplication(tenantAndApplication).revisions().withPackage();
- if (versions.isEmpty())
- throw new NotExistsException("No application package has been submitted for '" + tenantAndApplication + "'");
-
- ApplicationVersion version = Optional.ofNullable(request.getProperty("build"))
- .map(build -> {
- try {
- return Long.parseLong(build);
- } catch (NumberFormatException e) {
- throw new IllegalArgumentException("Invalid build number", e);
- }
- })
- .map(build -> versions.stream()
- .filter(ver -> ver.buildNumber().orElse(-1) == build)
- .findFirst()
- .orElseThrow(() -> new NotExistsException("No application package found for '" + tenantAndApplication + "' with build number " + build)))
- .orElseGet(() -> versions.get(versions.size() - 1));
-
+ TenantAndApplicationId tenantAndApplication = TenantAndApplicationId.from(tenantName, applicationName);
+ long build;
+ String parameter = request.getProperty("build");
+ if (parameter != null)
+ try {
+ build = Validation.requireAtLeast(Long.parseLong(request.getProperty("build")), "build number", 1L);
+ }
+ catch (NumberFormatException e) {
+ throw new IllegalArgumentException("invalid value for request parameter 'build'", e);
+ }
+ else {
+ build = controller.applications().requireApplication(tenantAndApplication).revisions().last()
+ .map(version -> version.id().number())
+ .orElseThrow(() -> new NotExistsException("no application package has been submitted for " + tenantAndApplication));
+ }
+ RevisionId revision = RevisionId.forProduction(build);
boolean tests = request.getBooleanProperty("tests");
byte[] applicationPackage = tests ?
- controller.applications().applicationStore().getTester(tenantAndApplication.tenant(), tenantAndApplication.application(), version) :
- controller.applications().applicationStore().get(new DeploymentId(tenantAndApplication.defaultInstance(), ZoneId.defaultId()), version);
- String filename = tenantAndApplication + (tests ? "-tests" : "-build") + version.buildNumber().getAsLong() + ".zip";
+ controller.applications().applicationStore().getTester(tenantAndApplication.tenant(), tenantAndApplication.application(), revision) :
+ controller.applications().applicationStore().get(new DeploymentId(tenantAndApplication.defaultInstance(), ZoneId.defaultId()), revision);
+ String filename = tenantAndApplication + (tests ? "-tests" : "-build") + revision.number() + ".zip";
return new ZipResponse(filename, applicationPackage);
}
@@ -1326,11 +1324,11 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
application.instances().values().stream().findFirst().ifPresent(instance -> {
// Currently deploying change
if ( ! instance.change().isEmpty())
- toSlime(object.setObject("deploying"), instance.change());
+ toSlime(object.setObject("deploying"), instance.change(), application);
// Outstanding change
if ( ! status.outstandingChange(instance.name()).isEmpty())
- toSlime(object.setObject("outstandingChange"), status.outstandingChange(instance.name()));
+ toSlime(object.setObject("outstandingChange"), status.outstandingChange(instance.name()), application);
});
application.majorVersion().ifPresent(majorVersion -> object.setLong("majorVersion", majorVersion));
@@ -1370,11 +1368,11 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
.sortedJobs(status.instanceJobs(instance.name()).values());
if ( ! instance.change().isEmpty())
- toSlime(object.setObject("deploying"), instance.change());
+ toSlime(object.setObject("deploying"), instance.change(), status.application());
// Outstanding change
if ( ! status.outstandingChange(instance.name()).isEmpty())
- toSlime(object.setObject("outstandingChange"), status.outstandingChange(instance.name()));
+ toSlime(object.setObject("outstandingChange"), status.outstandingChange(instance.name()), status.application());
// Change blockers
Cursor changeBlockers = object.setArray("changeBlockers");
@@ -1455,11 +1453,11 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
.sortedJobs(status.instanceJobs(instance.name()).values());
if ( ! instance.change().isEmpty())
- toSlime(object.setObject("deploying"), instance.change());
+ toSlime(object.setObject("deploying"), instance.change(), application);
// Outstanding change
if ( ! status.outstandingChange(instance.name()).isEmpty())
- toSlime(object.setObject("outstandingChange"), status.outstandingChange(instance.name()));
+ toSlime(object.setObject("outstandingChange"), status.outstandingChange(instance.name()), application);
// Change blockers
Cursor changeBlockers = object.setArray("changeBlockers");
@@ -1574,11 +1572,9 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
return new SlimeJsonResponse(slime);
}
- private void toSlime(Cursor object, Change change) {
+ private void toSlime(Cursor object, Change change, Application application) {
change.platform().ifPresent(version -> object.setString("version", version.toString()));
- change.application()
- .filter(version -> !version.isUnknown())
- .ifPresent(version -> JobControllerApiHandlerHelper.toSlime(object.setObject("revision"), version));
+ change.revision().ifPresent(revision -> JobControllerApiHandlerHelper.toSlime(object.setObject("revision"), application.revisions().get(revision)));
}
private void toSlime(Endpoint endpoint, Cursor object) {
@@ -1623,7 +1619,8 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
response.setString("nodes", withPathAndQuery("/zone/v2/" + deploymentId.zoneId().environment() + "/" + deploymentId.zoneId().region() + "/nodes/v2/node/", "recursive=true&application=" + deploymentId.applicationId().tenant() + "." + deploymentId.applicationId().application() + "." + deploymentId.applicationId().instance(), request.getUri()).toString());
response.setString("yamasUrl", monitoringSystemUri(deploymentId).toString());
response.setString("version", deployment.version().toFullString());
- response.setString("revision", deployment.applicationVersion().stringId());
+ response.setString("revision", application.revisions().get(deployment.revision()).stringId()); // TODO jonmv or freva: ƪ(`▿▿▿▿´ƪ)
+ response.setLong("build", deployment.revision().number());
Instant lastDeploymentStart = lastDeploymentStart(deploymentId.applicationId(), deployment);
response.setLong("deployTimeEpochMs", lastDeploymentStart.toEpochMilli());
controller.zoneRegistry().getDeploymentTimeToLive(deploymentId.zoneId())
@@ -1642,8 +1639,7 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
.map(type -> new JobId(instance.id(), type))
.map(status.jobSteps()::get)
.ifPresent(stepStatus -> {
- JobControllerApiHandlerHelper.toSlime(
- response.setObject("applicationVersion"), deployment.applicationVersion());
+ JobControllerApiHandlerHelper.toSlime(response.setObject("applicationVersion"), application.revisions().get(deployment.revision()));
if ( ! status.jobsToRun().containsKey(stepStatus.job().get()))
response.setString("status", "complete");
else if (stepStatus.readyAt(instance.change()).map(controller.clock().instant()::isBefore).orElse(true))
@@ -1770,7 +1766,7 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
Cursor root = slime.setObject();
if ( ! instance.change().isEmpty()) {
instance.change().platform().ifPresent(version -> root.setString("platform", version.toString()));
- instance.change().application().ifPresent(applicationVersion -> root.setString("application", applicationVersion.stringId()));
+ instance.change().revision().ifPresent(revision -> root.setString("application", revision.toString()));
root.setBool("pinned", instance.change().isPinned());
}
return new SlimeJsonResponse(slime);
@@ -1915,18 +1911,19 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
StringBuilder response = new StringBuilder();
controller.applications().lockApplicationOrThrow(TenantAndApplicationId.from(id), application -> {
- ApplicationVersion version = build == -1 ? application.get().revisions().last().get()
- : getApplicationVersion(application.get(), build);
- Change change = Change.of(version);
+ RevisionId revision = build == -1 ? application.get().revisions().last().get().id()
+ : getRevision(application.get(), build);
+ Change change = Change.of(revision);
controller.applications().deploymentTrigger().forceChange(id, change);
response.append("Triggered ").append(change).append(" for ").append(id);
});
return new MessageResponse(response.toString());
}
- private ApplicationVersion getApplicationVersion(Application application, Long build) {
+ private RevisionId getRevision(Application application, long build) {
return application.revisions().withPackage().stream()
- .filter(version -> version.buildNumber().stream().anyMatch(build::equals))
+ .map(ApplicationVersion::id)
+ .filter(version -> version.number() == build)
.findFirst()
.filter(version -> controller.applications().applicationStore().hasBuild(application.id().tenant(),
application.id().application(),
@@ -2546,14 +2543,16 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
}
}
+ /*
private void toSlime(Run run, Cursor object) {
object.setLong("id", run.id().number());
object.setString("version", run.versions().targetPlatform().toFullString());
- if ( ! run.versions().targetApplication().isUnknown())
- JobControllerApiHandlerHelper.toSlime(object.setObject("revision"), run.versions().targetApplication());
+ if ( ! run.versions().targetRevision().isUnknown())
+ JobControllerApiHandlerHelper.toSlime(object.setObject("revision"), run.versions().targetRevision());
object.setString("reason", "unknown reason");
object.setLong("at", run.end().orElse(run.start()).toEpochMilli());
}
+ */
private Slime toSlime(InputStream jsonStream) {
try {
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 51bd29f9838..cf3642144b1 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
@@ -20,6 +20,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.LogEntry;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId;
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.application.Change;
@@ -86,19 +87,19 @@ class JobControllerApiHandlerHelper {
Cursor jobObject = jobsArray.addObject();
jobObject.setString("jobName", job.type().jobName());
- toSlime(jobObject.setArray("runs"), runs, 10, baseUriForJobs);
+ toSlime(jobObject.setArray("runs"), runs, controller.applications().requireApplication(TenantAndApplicationId.from(id)), 10, baseUriForJobs);
});
return new SlimeJsonResponse(slime);
}
/** Returns a response with the runs for the given job type. */
- static HttpResponse runResponse(Map<RunId, Run> runs, Optional<String> limitStr, URI baseUriForJobType) {
+ static HttpResponse runResponse(Application application, Map<RunId, Run> runs, Optional<String> limitStr, URI baseUriForJobType) {
Slime slime = new Slime();
Cursor cursor = slime.setObject();
int limit = limitStr.map(Integer::parseInt).orElse(Integer.MAX_VALUE);
- toSlime(cursor.setArray("runs"), runs.values(), limit, baseUriForJobType);
+ toSlime(cursor.setArray("runs"), runs.values(), application, limit, baseUriForJobType);
return new SlimeJsonResponse(slime);
}
@@ -200,7 +201,7 @@ class JobControllerApiHandlerHelper {
ApplicationVersion version = jobController.submit(TenantAndApplicationId.from(tenant, application), sourceRevision, authorEmail,
sourceUrl, projectId, applicationPackage, testPackage, description, risk);
- return new MessageResponse(version.toString());
+ return new MessageResponse("application " + version);
}
/** Aborts any job of the given type. */
@@ -270,8 +271,8 @@ class JobControllerApiHandlerHelper {
stepStatus.coolingDownUntil(change).ifPresent(until -> stepObject.setLong("coolingDownUntil", until.toEpochMilli()));
stepStatus.blockedUntil(Change.of(controller.systemVersion(versionStatus))) // Dummy version — just anything with a platform.
.ifPresent(until -> stepObject.setLong("platformBlockedUntil", until.toEpochMilli()));
- application.revisions().last().map(Change::of).flatMap(stepStatus::blockedUntil) // Dummy version — just anything with an application.
- .ifPresent(until -> stepObject.setLong("applicationBlockedUntil", until.toEpochMilli()));
+ stepStatus.blockedUntil(Change.of(RevisionId.forProduction(1))) // Dummy version — just anything with an application.
+ .ifPresent(until -> stepObject.setLong("applicationBlockedUntil", until.toEpochMilli()));
if (stepStatus.type() == DeploymentStatus.StepType.delay)
stepStatus.completedAt(change).ifPresent(completed -> stepObject.setLong("completedAt", completed.toEpochMilli()));
@@ -280,7 +281,7 @@ class JobControllerApiHandlerHelper {
Cursor deployingObject = stepObject.setObject("deploying");
if ( ! change.isEmpty()) {
change.platform().ifPresent(version -> deployingObject.setString("platform", version.toFullString()));
- change.application().ifPresent(version -> toSlime(deployingObject.setObject("application"), version));
+ change.revision().ifPresent(revision -> toSlime(deployingObject.setObject("application"), application.revisions().get(revision)));
}
Cursor latestVersionsObject = stepObject.setObject("latestVersions");
@@ -315,20 +316,20 @@ class JobControllerApiHandlerHelper {
Cursor latestApplicationObject = latestVersionsObject.setObject("application");
toSlime(latestApplicationObject.setObject("application"), latestApplication);
latestApplicationObject.setLong("at", latestApplication.buildTime().orElse(Instant.EPOCH).toEpochMilli());
- latestApplicationObject.setBool("upgrade", change.application().map(latestApplication::compareTo).orElse(1) > 0 && deployments.isEmpty()
- || deployments.stream().anyMatch(deployment -> deployment.applicationVersion().compareTo(latestApplication) < 0));
+ latestApplicationObject.setBool("upgrade", change.revision().map(latestApplication.id()::compareTo).orElse(1) > 0 && deployments.isEmpty()
+ || deployments.stream().anyMatch(deployment -> deployment.revision().compareTo(latestApplication.id()) < 0));
Cursor availableArray = latestApplicationObject.setArray("available");
for (ApplicationVersion available : availableApplications) {
- if ( deployments.stream().anyMatch(deployment -> deployment.applicationVersion().compareTo(available) > 0)
- || deployments.stream().noneMatch(deployment -> deployment.applicationVersion().compareTo(available) < 0) && ! deployments.isEmpty()
- || status.hasCompleted(stepStatus.instance(), Change.of(available))
- || change.application().map(available::compareTo).orElse(1) <= 0)
+ if ( deployments.stream().anyMatch(deployment -> deployment.revision().compareTo(available.id()) > 0)
+ || deployments.stream().noneMatch(deployment -> deployment.revision().compareTo(available.id()) < 0) && ! deployments.isEmpty()
+ || status.hasCompleted(stepStatus.instance(), Change.of(available.id()))
+ || change.revision().map(available.id()::compareTo).orElse(1) <= 0)
break;
toSlime(availableArray.addObject().setObject("application"), available);
}
- change.application().ifPresent(version -> toSlime(availableArray.addObject().setObject("application"), version));
+ change.revision().ifPresent(revision -> toSlime(availableArray.addObject().setObject("application"), application.revisions().get(revision)));
toSlime(latestApplicationObject.setArray("blockers"), blockers.stream().filter(ChangeBlocker::blocksRevisions));
}
}
@@ -345,7 +346,7 @@ class JobControllerApiHandlerHelper {
if (job.type().isProduction() && job.type().isDeployment()) {
status.deploymentFor(job).ifPresent(deployment -> {
stepObject.setString("currentPlatform", deployment.version().toFullString());
- toSlime(stepObject.setObject("currentApplication"), deployment.applicationVersion());
+ toSlime(stepObject.setObject("currentApplication"), application.revisions().get(deployment.revision()));
});
}
@@ -361,10 +362,10 @@ class JobControllerApiHandlerHelper {
continue; // Run will be contained in the "runs" array.
Cursor runObject = toRunArray.addObject();
- toSlime(runObject.setObject("versions"), versions.versions());
+ toSlime(runObject.setObject("versions"), versions.versions(), application);
}
- toSlime(stepObject.setArray("runs"), jobStatus.runs().descendingMap().values(), 10, baseUriForJob);
+ toSlime(stepObject.setArray("runs"), jobStatus.runs().descendingMap().values(), application, 10, baseUriForJob);
});
}
@@ -388,11 +389,11 @@ class JobControllerApiHandlerHelper {
version.commit().ifPresent(commit -> versionObject.setString("commit", commit));
}
- private static void toSlime(Cursor versionsObject, Versions versions) {
+ private static void toSlime(Cursor versionsObject, Versions versions, Application application) {
versionsObject.setString("targetPlatform", versions.targetPlatform().toFullString());
- toSlime(versionsObject.setObject("targetApplication"), versions.targetApplication());
+ toSlime(versionsObject.setObject("targetApplication"), application.revisions().get(versions.targetRevision()));
versions.sourcePlatform().ifPresent(platform -> versionsObject.setString("sourcePlatform", platform.toFullString()));
- versions.sourceApplication().ifPresent(application -> toSlime(versionsObject.setObject("sourceApplication"), application));
+ versions.sourceRevision().ifPresent(revision -> toSlime(versionsObject.setObject("sourceApplication"), application.revisions().get(revision)));
}
private static void toSlime(Cursor blockersArray, Stream<ChangeBlocker> blockers) {
@@ -428,7 +429,7 @@ class JobControllerApiHandlerHelper {
return candidates;
}
- private static void toSlime(Cursor runsArray, Collection<Run> runs, int limit, URI baseUriForJob) {
+ private static void toSlime(Cursor runsArray, Collection<Run> runs, Application application, int limit, URI baseUriForJob) {
runs.stream().limit(limit).forEach(run -> {
Cursor runObject = runsArray.addObject();
runObject.setLong("id", run.id().number());
@@ -436,7 +437,7 @@ class JobControllerApiHandlerHelper {
runObject.setLong("start", run.start().toEpochMilli());
run.end().ifPresent(end -> runObject.setLong("end", end.toEpochMilli()));
runObject.setString("status", run.status().name());
- toSlime(runObject.setObject("versions"), run.versions());
+ toSlime(runObject.setObject("versions"), run.versions(), application);
Cursor runStepsArray = runObject.setArray("steps");
run.steps().forEach((step, info) -> {
Cursor runStepObject = runStepsArray.addObject();
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 816a7370bcd..687820d15cc 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
@@ -23,6 +23,8 @@ import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
import com.yahoo.vespa.hosted.controller.api.integration.certificates.EndpointCertificateMetadata;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.ContainerEndpoint;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobId;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId;
import com.yahoo.vespa.hosted.controller.api.integration.dns.LatencyAliasTarget;
import com.yahoo.vespa.hosted.controller.api.integration.dns.Record;
import com.yahoo.vespa.hosted.controller.api.integration.dns.RecordData;
@@ -59,6 +61,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.yahoo.config.provision.SystemName.main;
+import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.devUsEast1;
import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.productionUsEast3;
import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.productionUsWest1;
import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.stagingTest;
@@ -92,13 +95,13 @@ public class ControllerTest {
var context = tester.newDeploymentContext();
context.submit(applicationPackage);
assertEquals("Application version is known from completion of initial job",
- ApplicationVersion.from(DeploymentContext.defaultSourceRevision, 1, "a@b", new Version("6.1"), Instant.ofEpochSecond(1)),
- context.instance().change().application().get());
+ ApplicationVersion.from(RevisionId.forProduction(1), DeploymentContext.defaultSourceRevision, "a@b", new Version("6.1"), Instant.ofEpochSecond(1)),
+ context.application().revisions().get(context.instance().change().revision().get()));
context.runJob(systemTest);
context.runJob(stagingTest);
- ApplicationVersion applicationVersion = context.instance().change().application().get();
- assertFalse("Application version has been set during deployment", applicationVersion.isUnknown());
+ RevisionId applicationVersion = context.instance().change().revision().get();
+ assertTrue("Application version has been set during deployment", applicationVersion.isProduction());
tester.triggerJobs();
// Causes first deployment job to be triggered
@@ -735,7 +738,7 @@ public class ControllerTest {
context.runJob(zone, new ApplicationPackageBuilder().compileVersion(version1).build());
assertEquals(version2, context.deployment(zone).version());
- assertEquals(Optional.of(version1), context.deployment(zone).applicationVersion().compileVersion());
+ assertEquals(Optional.of(version1), context.application().revisions().get(context.deployment(zone).revision()).compileVersion());
try {
context.runJob(zone, new ApplicationPackageBuilder().compileVersion(version1).majorVersion(8).build());
@@ -764,11 +767,11 @@ public class ControllerTest {
context.runJob(zone, new ApplicationPackageBuilder().compileVersion(version3).majorVersion(8).build());
assertEquals(version3, context.deployment(zone).version());
- assertEquals(Optional.of(version3), context.deployment(zone).applicationVersion().compileVersion());
+ assertEquals(Optional.of(version3), context.application().revisions().get(context.deployment(zone).revision()).compileVersion());
context.runJob(zone, new ApplicationPackageBuilder().compileVersion(version3).build());
assertEquals(version3, context.deployment(zone).version());
- assertEquals(Optional.of(version3), context.deployment(zone).applicationVersion().compileVersion());
+ assertEquals(Optional.of(version3), context.application().revisions().get(context.deployment(zone).revision()).compileVersion());
}
@Test
@@ -1040,7 +1043,7 @@ public class ControllerTest {
@Test
public void testReadableApplications() {
- var db = new MockCuratorDb();
+ var db = new MockCuratorDb(tester.controller().system());
var tester = new DeploymentTester(new ControllerTester(db));
// Create and deploy two applications
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java
index b4bf4a6c135..a2eefd47b56 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java
@@ -74,6 +74,7 @@ import java.util.logging.Handler;
import java.util.logging.Logger;
import java.util.stream.Collectors;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -109,11 +110,11 @@ public final class ControllerTester {
}
public ControllerTester(ServiceRegistryMock serviceRegistryMock) {
- this(new AthenzDbMock(), new MockCuratorDb(), defaultRotationsConfig(), serviceRegistryMock);
+ this(new AthenzDbMock(), new MockCuratorDb(serviceRegistryMock.zoneRegistry().system()), defaultRotationsConfig(), serviceRegistryMock);
}
public ControllerTester(RotationsConfig rotationsConfig, SystemName system) {
- this(new AthenzDbMock(), new MockCuratorDb(), rotationsConfig, new ServiceRegistryMock(system));
+ this(new AthenzDbMock(), new MockCuratorDb(system), rotationsConfig, new ServiceRegistryMock(system));
}
public ControllerTester(MockCuratorDb curatorDb) {
@@ -121,11 +122,11 @@ public final class ControllerTester {
}
public ControllerTester() {
- this(defaultRotationsConfig(), new MockCuratorDb());
+ this(defaultRotationsConfig(), new MockCuratorDb(new ServiceRegistryMock().zoneRegistry().system()));
}
public ControllerTester(SystemName system) {
- this(new AthenzDbMock(), new MockCuratorDb(), defaultRotationsConfig(), new ServiceRegistryMock(system));
+ this(new AthenzDbMock(), new MockCuratorDb(system), defaultRotationsConfig(), new ServiceRegistryMock(system));
}
private ControllerTester(AthenzDbMock athenzDb, boolean inContainer, CuratorDb curator,
@@ -215,9 +216,9 @@ public final class ControllerTester {
}
/** Set the zones and system for this and bootstrap infrastructure nodes */
- public ControllerTester setZones(List<ZoneId> zones, SystemName system) {
- zoneRegistry().setZones(zones.stream().map(ZoneApiMock::from).collect(Collectors.toList()))
- .setSystemName(system);
+ public ControllerTester setZones(List<ZoneId> zones) {
+ ZoneApiMock.Builder builder = ZoneApiMock.newBuilder().withSystem(zoneRegistry().system());
+ zoneRegistry().setZones(zones.stream().map(zone -> builder.with(zone).build()).collect(Collectors.toList()));
configServer().bootstrap(zones, SystemApplication.notController());
return this;
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/DeploymentQuotaCalculatorTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/DeploymentQuotaCalculatorTest.java
index 9739ee219b8..96b0e3137cb 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/DeploymentQuotaCalculatorTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/DeploymentQuotaCalculatorTest.java
@@ -13,6 +13,7 @@ import com.yahoo.vespa.hosted.controller.Application;
import com.yahoo.vespa.hosted.controller.Instance;
import com.yahoo.vespa.hosted.controller.api.integration.billing.Quota;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId;
import com.yahoo.vespa.hosted.controller.api.integration.noderepository.ApplicationData;
import com.yahoo.vespa.hosted.controller.deployment.RevisionHistory;
import com.yahoo.vespa.hosted.controller.metric.ApplicationMetrics;
@@ -62,9 +63,8 @@ public class DeploymentQuotaCalculatorTest {
var existing_dev_deployment = new Application(TenantAndApplicationId.from(ApplicationId.defaultId()), Instant.EPOCH, DeploymentSpec.empty, ValidationOverrides.empty, Optional.empty(),
Optional.empty(), Optional.empty(), OptionalInt.empty(), new ApplicationMetrics(1, 1), Set.of(), OptionalLong.empty(), RevisionHistory.empty(),
- List.of(new Instance(ApplicationId.defaultId()).withNewDeployment(
- ZoneId.from(Environment.dev, RegionName.defaultName()), ApplicationVersion.unknown, Version.emptyVersion, Instant.EPOCH, Map.of(),
- QuotaUsage.create(0.53d))));
+ List.of(new Instance(ApplicationId.defaultId()).withNewDeployment(ZoneId.from(Environment.dev, RegionName.defaultName()),
+ RevisionId.forProduction(1), Version.emptyVersion, Instant.EPOCH, Map.of(), QuotaUsage.create(0.53d))));
Quota calculated = DeploymentQuotaCalculator.calculate(Quota.unlimited().withBudget(2), List.of(existing_dev_deployment), ApplicationId.defaultId(), ZoneId.defaultId(),
DeploymentSpec.fromXml(
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentContext.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentContext.java
index 7191ec92440..899e567d7cc 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentContext.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentContext.java
@@ -24,6 +24,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.configserver.NodeFilter
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId;
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;
@@ -107,7 +108,7 @@ public class DeploymentContext {
private final JobRunner runner;
private final DeploymentTester tester;
- private ApplicationVersion lastSubmission = null;
+ private RevisionId lastSubmission = null;
private boolean deferDnsUpdates = false;
public DeploymentContext(ApplicationId instanceId, DeploymentTester tester) {
@@ -172,7 +173,7 @@ public class DeploymentContext {
assertTrue("Application package submitted", application.revisions().last().isPresent());
assertFalse("Submission is not already deployed", application.instances().values().stream()
.anyMatch(instance -> instance.deployments().values().stream()
- .anyMatch(deployment -> deployment.applicationVersion().equals(lastSubmission))));
+ .anyMatch(deployment -> deployment.revision().equals(lastSubmission))));
completeRollout(application.deploymentSpec().instances().size() > 1);
for (var instance : application().instances().values()) {
assertFalse(instance.change().hasTargets());
@@ -187,7 +188,7 @@ public class DeploymentContext {
.anyMatch(instance -> instance.deployments().values().stream()
.anyMatch(deployment -> deployment.version().equals(version))));
assertEquals(version, instance().change().platform().get());
- assertFalse(instance().change().application().isPresent());
+ assertFalse(instance().change().revision().isPresent());
completeRollout();
@@ -288,7 +289,7 @@ public class DeploymentContext {
.projectId()
.orElse(1000); // These are really set through submission, so just pick one if it hasn't been set.
var testerpackage = new byte[]{ (byte) (salt >> 56), (byte) (salt >> 48), (byte) (salt >> 40), (byte) (salt >> 32), (byte) (salt >> 24), (byte) (salt >> 16), (byte) (salt >> 8), (byte) salt };
- lastSubmission = jobs.submit(applicationId, sourceRevision, Optional.of("a@b"), Optional.empty(), projectId, applicationPackage, testerpackage, Optional.empty(), risk);
+ lastSubmission = jobs.submit(applicationId, sourceRevision, Optional.of("a@b"), Optional.empty(), projectId, applicationPackage, testerpackage, Optional.empty(), risk).id();
return this;
}
@@ -349,7 +350,7 @@ public class DeploymentContext {
}
/** Returns the last submitted application version */
- public Optional<ApplicationVersion> lastSubmission() {
+ public Optional<RevisionId> lastSubmission() {
return Optional.ofNullable(lastSubmission);
}
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 d90f7c5fd64..04ee21117a9 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
@@ -7,13 +7,15 @@ import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.zone.RoutingMethod;
import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.vespa.flags.PermanentFlags;
+import com.yahoo.vespa.hosted.controller.ControllerTester;
import com.yahoo.vespa.hosted.controller.Instance;
-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.RevisionId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId;
import com.yahoo.vespa.hosted.controller.application.Change;
import com.yahoo.vespa.hosted.controller.application.Deployment;
import com.yahoo.vespa.hosted.controller.application.pkg.ApplicationPackage;
+import com.yahoo.vespa.hosted.controller.integration.ZoneRegistryMock;
import com.yahoo.vespa.hosted.controller.versions.VespaVersion;
import org.junit.Assert;
import org.junit.Test;
@@ -29,6 +31,7 @@ import java.util.OptionalLong;
import java.util.stream.Collectors;
import static ai.vespa.validation.Validation.require;
+import static com.yahoo.config.provision.SystemName.cd;
import static com.yahoo.config.provision.SystemName.main;
import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.productionApNortheast1;
import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.productionApNortheast2;
@@ -121,28 +124,28 @@ public class DeploymentTriggerTest {
.build();
app.submit(applicationPackage).runJob(systemTest).runJob(stagingTest).runJob(productionUsEast3);
- Optional<ApplicationVersion> v0 = app.lastSubmission();
+ Optional<RevisionId> v0 = app.lastSubmission();
app.submit(applicationPackage);
- Optional<ApplicationVersion> v1 = app.lastSubmission();
- assertEquals(v0, app.instance().change().application());
+ Optional<RevisionId> v1 = app.lastSubmission();
+ assertEquals(v0, app.instance().change().revision());
// Eager tests still run before new revision rolls out.
app.runJob(systemTest).runJob(stagingTest);
// v0 rolls out completely.
app.runJob(testUsEast3);
- assertEquals(Optional.empty(), app.instance().change().application());
+ assertEquals(Optional.empty(), app.instance().change().revision());
// v1 starts rolling when v0 is done.
tester.outstandingChangeDeployer().run();
- assertEquals(v1, app.instance().change().application());
+ assertEquals(v1, app.instance().change().revision());
// v1 fails, so v2 starts immediately.
app.runJob(productionUsEast3).failDeployment(testUsEast3);
app.submit(applicationPackage);
- Optional<ApplicationVersion> v2 = app.lastSubmission();
- assertEquals(v2, app.instance().change().application());
+ Optional<RevisionId> v2 = app.lastSubmission();
+ assertEquals(v2, app.instance().change().revision());
}
@Test
@@ -223,7 +226,7 @@ public class DeploymentTriggerTest {
DeploymentContext app = tester.newDeploymentContext().submit(firstPackage, 5417, 0);
var version = app.lastSubmission();
- assertEquals(version, app.instance().change().application());
+ assertEquals(version, app.instance().change().revision());
app.runJob(systemTest)
.runJob(stagingTest)
.runJob(productionUsEast3);
@@ -241,7 +244,7 @@ public class DeploymentTriggerTest {
app.submit(secondPackage, 5417, 0);
app.triggerJobs();
assertEquals(List.of(), tester.jobs().active());
- assertEquals(version, app.instance().change().application());
+ assertEquals(version, app.instance().change().revision());
tester.clock().advance(Duration.ofHours(1));
app.runJob(testUsEast3);
@@ -263,45 +266,45 @@ public class DeploymentTriggerTest {
.build();
DeploymentContext app = tester.newDeploymentContext()
.submit(appPackage);
- Optional<ApplicationVersion> revision1 = app.lastSubmission();
+ Optional<RevisionId> revision1 = app.lastSubmission();
app.submit(appPackage);
- Optional<ApplicationVersion> revision2 = app.lastSubmission();
+ Optional<RevisionId> revision2 = app.lastSubmission();
app.submit(appPackage);
- Optional<ApplicationVersion> revision3 = app.lastSubmission();
+ Optional<RevisionId> revision3 = app.lastSubmission();
app.submit(appPackage);
- Optional<ApplicationVersion> revision4 = app.lastSubmission();
+ Optional<RevisionId> revision4 = app.lastSubmission();
app.submit(appPackage);
- Optional<ApplicationVersion> revision5 = app.lastSubmission();
+ Optional<RevisionId> revision5 = app.lastSubmission();
// 5 revisions submitted; the first is rolling out, and the others are queued.
tester.outstandingChangeDeployer().run();
- assertEquals(revision1, app.instance().change().application());
- assertEquals(revision2, app.deploymentStatus().outstandingChange(InstanceName.defaultName()).application());
+ assertEquals(revision1, app.instance().change().revision());
+ assertEquals(revision2, app.deploymentStatus().outstandingChange(InstanceName.defaultName()).revision());
// The second revision is set as the target by user interaction.
tester.deploymentTrigger().forceChange(app.instanceId(), Change.of(revision2.get()));
tester.outstandingChangeDeployer().run();
- assertEquals(revision2, app.instance().change().application());
- assertEquals(revision3, app.deploymentStatus().outstandingChange(InstanceName.defaultName()).application());
+ assertEquals(revision2, app.instance().change().revision());
+ assertEquals(revision3, app.deploymentStatus().outstandingChange(InstanceName.defaultName()).revision());
// The second revision deploys completely, and the third starts rolling out.
app.runJob(systemTest).runJob(stagingTest)
.runJob(productionUsEast3);
tester.outstandingChangeDeployer().run();
tester.outstandingChangeDeployer().run();
- assertEquals(revision3, app.instance().change().application());
- assertEquals(revision4, app.deploymentStatus().outstandingChange(InstanceName.defaultName()).application());
+ assertEquals(revision3, app.instance().change().revision());
+ assertEquals(revision4, app.deploymentStatus().outstandingChange(InstanceName.defaultName()).revision());
// The third revision fails, and the fourth is chosen to replace it.
app.triggerJobs().timeOutConvergence(systemTest);
tester.outstandingChangeDeployer().run();
tester.outstandingChangeDeployer().run();
- assertEquals(revision4, app.instance().change().application());
- assertEquals(revision5, app.deploymentStatus().outstandingChange(InstanceName.defaultName()).application());
+ assertEquals(revision4, app.instance().change().revision());
+ assertEquals(revision5, app.deploymentStatus().outstandingChange(InstanceName.defaultName()).revision());
// Tests for outstanding change are relevant when current revision completes.
app.runJob(systemTest).runJob(systemTest)
@@ -309,7 +312,7 @@ public class DeploymentTriggerTest {
.runJob(productionUsEast3);
tester.outstandingChangeDeployer().run();
tester.outstandingChangeDeployer().run();
- assertEquals(revision5, app.instance().change().application());
+ assertEquals(revision5, app.instance().change().revision());
assertEquals(Change.empty(), app.deploymentStatus().outstandingChange(InstanceName.defaultName()));
app.runJob(productionUsEast3);
}
@@ -504,8 +507,8 @@ public class DeploymentTriggerTest {
tester.clock().advance(Duration.ofHours(1));
app.submit(applicationPackage);
app.runJob(productionUsWest1);
- assertEquals(1, app.instanceJobs().get(productionUsWest1).lastSuccess().get().versions().targetApplication().buildNumber().getAsLong());
- assertEquals(2, app.deploymentStatus().outstandingChange(app.instance().name()).application().get().buildNumber().getAsLong());
+ assertEquals(1, app.instanceJobs().get(productionUsWest1).lastSuccess().get().versions().targetRevision().number());
+ assertEquals(2, app.deploymentStatus().outstandingChange(app.instance().name()).revision().get().number());
tester.triggerJobs();
// Platform upgrade keeps rolling, since it began before block window, and tests for the new revision have also started.
@@ -585,8 +588,8 @@ public class DeploymentTriggerTest {
.runJob(stagingTest)
.timeOutUpgrade(productionUsCentral1);
- ApplicationVersion appVersion1 = app.lastSubmission().get();
- assertEquals(appVersion1, app.deployment(ZoneId.from("prod.us-central-1")).applicationVersion());
+ RevisionId appVersion1 = app.lastSubmission().get();
+ assertEquals(appVersion1, app.deployment(ZoneId.from("prod.us-central-1")).revision());
// Verify the application change is not removed when platform change is cancelled.
tester.deploymentTrigger().cancelChange(app.instanceId(), PLATFORM);
@@ -608,12 +611,12 @@ public class DeploymentTriggerTest {
// Finally, the two production jobs complete, in order.
app.runJob(productionUsCentral1).runJob(productionEuWest1);
- assertEquals(appVersion1, app.deployment(ZoneId.from("prod.us-central-1")).applicationVersion());
+ assertEquals(appVersion1, app.deployment(ZoneId.from("prod.us-central-1")).revision());
}
- ApplicationVersion latestDeployed(Instance instance) {
+ RevisionId latestDeployed(Instance instance) {
return instance.productionDeployments().values().stream()
- .map(Deployment::applicationVersion)
+ .map(Deployment::revision)
.reduce((o, n) -> require(o.equals(n), n, "all versions should be equal, but got " + o + " and " + n))
.orElseThrow(() -> new AssertionError("no versions deployed"));
}
@@ -621,11 +624,11 @@ public class DeploymentTriggerTest {
@Test
public void downgradingApplicationVersionWorks() {
var app = tester.newDeploymentContext().submit().deploy();
- ApplicationVersion appVersion0 = app.lastSubmission().get();
+ RevisionId appVersion0 = app.lastSubmission().get();
assertEquals(appVersion0, latestDeployed(app.instance()));
app.submit().deploy();
- ApplicationVersion appVersion1 = app.lastSubmission().get();
+ RevisionId appVersion1 = app.lastSubmission().get();
assertEquals(appVersion1, latestDeployed(app.instance()));
// Downgrading application version.
@@ -636,7 +639,7 @@ public class DeploymentTriggerTest {
.runJob(productionUsEast3)
.runJob(productionUsWest1);
assertEquals(Change.empty(), app.instance().change());
- assertEquals(appVersion0, app.instance().deployments().get(productionUsEast3.zone(tester.controller().system())).applicationVersion());
+ assertEquals(appVersion0, app.instance().deployments().get(productionUsEast3.zone(tester.controller().system())).revision());
assertEquals(appVersion0, latestDeployed(app.instance()));
}
@@ -645,11 +648,11 @@ public class DeploymentTriggerTest {
var app = tester.newDeploymentContext().submit();
app.deploy();
- ApplicationVersion appVersion0 = app.lastSubmission().get();
+ RevisionId appVersion0 = app.lastSubmission().get();
assertEquals(appVersion0, latestDeployed(app.instance()));
app.submit().deploy();
- ApplicationVersion appVersion1 = app.lastSubmission().get();
+ RevisionId appVersion1 = app.lastSubmission().get();
assertEquals(appVersion1, latestDeployed(app.instance()));
// Triggering a roll-out of an already deployed application is a no-op.
@@ -705,9 +708,9 @@ public class DeploymentTriggerTest {
assertEquals(triggered, app1.instanceJobs().get(productionUsCentral1).lastTriggered().get().start());
// Roll out a new application version, which gives a dual change -- this should trigger us-central-1, but only as long as it hasn't yet deployed there.
- ApplicationVersion revision1 = app1.lastSubmission().get();
+ RevisionId revision1 = app1.lastSubmission().get();
app1.submit(applicationPackage);
- ApplicationVersion revision2 = app1.lastSubmission().get();
+ RevisionId revision2 = app1.lastSubmission().get();
app1.runJob(systemTest) // Tests for new revision on version2
.runJob(stagingTest)
.runJob(systemTest) // Tests for new revision on version1
@@ -716,13 +719,13 @@ public class DeploymentTriggerTest {
tester.triggerJobs();
app1.assertRunning(productionUsCentral1);
assertEquals(version2, app1.instance().deployments().get(productionUsCentral1.zone(main)).version());
- assertEquals(revision1, app1.deployment(productionUsCentral1.zone(main)).applicationVersion());
+ assertEquals(revision1, app1.deployment(productionUsCentral1.zone(main)).revision());
assertTrue(triggered.isBefore(app1.instanceJobs().get(productionUsCentral1).lastTriggered().get().start()));
// Change has a higher application version than what is deployed -- deployment should trigger.
app1.timeOutUpgrade(productionUsCentral1);
assertEquals(version2, app1.deployment(productionUsCentral1.zone(main)).version());
- assertEquals(revision2, app1.deployment(productionUsCentral1.zone(main)).applicationVersion());
+ assertEquals(revision2, app1.deployment(productionUsCentral1.zone(main)).revision());
// Change is again strictly dominated, and us-central-1 is skipped, even though it is still failing.
tester.clock().advance(Duration.ofHours(3)); // Enough time for retry
@@ -781,8 +784,8 @@ public class DeploymentTriggerTest {
app.failDeployment(productionEuWest1).failDeployment(productionUsEast3)
.runJob(productionEuWest1).runJob(productionUsEast3);
assertFalse(app.instance().change().hasTargets());
- assertEquals(2, app.instanceJobs().get(productionEuWest1).lastSuccess().get().versions().targetApplication().buildNumber().getAsLong());
- assertEquals(2, app.instanceJobs().get(productionUsEast3).lastSuccess().get().versions().targetApplication().buildNumber().getAsLong());
+ assertEquals(2, app.instanceJobs().get(productionEuWest1).lastSuccess().get().versions().targetRevision().number());
+ assertEquals(2, app.instanceJobs().get(productionUsEast3).lastSuccess().get().versions().targetRevision().number());
}
@Test
@@ -949,9 +952,9 @@ public class DeploymentTriggerTest {
app3.abortJob(stagingTest);
assertEquals(0, tester.jobs().active().size());
- assertTrue(app1.instance().change().application().isPresent());
- assertFalse(app2.instance().change().application().isPresent());
- assertFalse(app3.instance().change().application().isPresent());
+ assertTrue(app1.instance().change().revision().isPresent());
+ assertFalse(app2.instance().change().revision().isPresent());
+ assertFalse(app3.instance().change().revision().isPresent());
tester.readyJobsTrigger().maintain();
app1.assertRunning(stagingTest);
@@ -1016,12 +1019,12 @@ public class DeploymentTriggerTest {
// Package is submitted, and change propagated to the two first instances.
i1.submit(applicationPackage);
- Optional<ApplicationVersion> v0 = i1.lastSubmission();
+ Optional<RevisionId> v0 = i1.lastSubmission();
tester.outstandingChangeDeployer().run();
- assertEquals(v0, i1.instance().change().application());
- assertEquals(v0, i2.instance().change().application());
- assertEquals(Optional.empty(), i3.instance().change().application());
- assertEquals(Optional.empty(), i4.instance().change().application());
+ assertEquals(v0, i1.instance().change().revision());
+ assertEquals(v0, i2.instance().change().revision());
+ assertEquals(Optional.empty(), i3.instance().change().revision());
+ assertEquals(Optional.empty(), i4.instance().change().revision());
// Tests run in i4, as they're declared there, and i1 and i2 get to work
i4.runJob(systemTest).runJob(stagingTest);
@@ -1032,57 +1035,57 @@ public class DeploymentTriggerTest {
tester.outstandingChangeDeployer().run();
assertEquals(v0, Optional.of(latestDeployed(i1.instance())));
assertEquals(v0, Optional.of(latestDeployed(i2.instance())));
- assertEquals(Optional.empty(), i1.instance().change().application());
- assertEquals(Optional.empty(), i2.instance().change().application());
- assertEquals(Optional.empty(), i3.instance().change().application());
- assertEquals(Optional.empty(), i4.instance().change().application());
+ assertEquals(Optional.empty(), i1.instance().change().revision());
+ assertEquals(Optional.empty(), i2.instance().change().revision());
+ assertEquals(Optional.empty(), i3.instance().change().revision());
+ assertEquals(Optional.empty(), i4.instance().change().revision());
// When the delay is done, i3 gets the change.
tester.clock().advance(Duration.ofHours(6));
tester.outstandingChangeDeployer().run();
- assertEquals(Optional.empty(), i1.instance().change().application());
- assertEquals(Optional.empty(), i2.instance().change().application());
- assertEquals(v0, i3.instance().change().application());
- assertEquals(Optional.empty(), i4.instance().change().application());
+ assertEquals(Optional.empty(), i1.instance().change().revision());
+ assertEquals(Optional.empty(), i2.instance().change().revision());
+ assertEquals(v0, i3.instance().change().revision());
+ assertEquals(Optional.empty(), i4.instance().change().revision());
// v0 begins roll-out in i3, and v1 is submitted and rolls out in i1 and i2 some time later
i3.runJob(productionUsEast3); // v0
tester.clock().advance(Duration.ofHours(12));
i1.submit(applicationPackage);
- Optional<ApplicationVersion> v1 = i1.lastSubmission();
+ Optional<RevisionId> v1 = i1.lastSubmission();
i4.runJob(systemTest).runJob(stagingTest);
i1.runJob(productionUsEast3); // v1
i2.runJob(productionUsEast3); // v1
assertEquals(v1, Optional.of(latestDeployed(i1.instance())));
assertEquals(v1, Optional.of(latestDeployed(i2.instance())));
- assertEquals(Optional.empty(), i1.instance().change().application());
- assertEquals(Optional.empty(), i2.instance().change().application());
- assertEquals(v0, i3.instance().change().application());
- assertEquals(Optional.empty(), i4.instance().change().application());
+ assertEquals(Optional.empty(), i1.instance().change().revision());
+ assertEquals(Optional.empty(), i2.instance().change().revision());
+ assertEquals(v0, i3.instance().change().revision());
+ assertEquals(Optional.empty(), i4.instance().change().revision());
// After some time, v2 also starts rolling out to i1 and i2, but does not complete in i2
tester.clock().advance(Duration.ofHours(3));
i1.submit(applicationPackage);
- Optional<ApplicationVersion> v2 = i1.lastSubmission();
+ Optional<RevisionId> v2 = i1.lastSubmission();
i4.runJob(systemTest).runJob(stagingTest);
i1.runJob(productionUsEast3); // v2
tester.clock().advance(Duration.ofHours(3));
// v1 is all done in i1 and i2, but does not yet roll out in i3; v2 is not completely rolled out there yet.
tester.outstandingChangeDeployer().run();
- assertEquals(v0, i3.instance().change().application());
+ assertEquals(v0, i3.instance().change().revision());
// i3 completes v0, which rolls out to i4; v1 is ready for i3, but v2 is not.
i3.runJob(testUsEast3);
- assertEquals(Optional.empty(), i3.instance().change().application());
+ assertEquals(Optional.empty(), i3.instance().change().revision());
tester.outstandingChangeDeployer().run();
assertEquals(v2, Optional.of(latestDeployed(i1.instance())));
assertEquals(v1, Optional.of(latestDeployed(i2.instance())));
assertEquals(v0, Optional.of(latestDeployed(i3.instance())));
- assertEquals(Optional.empty(), i1.instance().change().application());
- assertEquals(v2, i2.instance().change().application());
- assertEquals(v1, i3.instance().change().application());
- assertEquals(v0, i4.instance().change().application());
+ assertEquals(Optional.empty(), i1.instance().change().revision());
+ assertEquals(v2, i2.instance().change().revision());
+ assertEquals(v1, i3.instance().change().revision());
+ assertEquals(v0, i4.instance().change().revision());
}
@Test
@@ -1105,7 +1108,7 @@ public class DeploymentTriggerTest {
DeploymentContext alpha = tester.newDeploymentContext("t", "a", "alpha");
DeploymentContext beta = tester.newDeploymentContext("t", "a", "beta");
alpha.submit(applicationPackage).deploy();
- Optional<ApplicationVersion> revision1 = alpha.lastSubmission();
+ Optional<RevisionId> revision1 = alpha.lastSubmission();
Version version1 = new Version("7.1");
tester.controllerTester().upgradeSystem(version1);
@@ -1128,7 +1131,7 @@ public class DeploymentTriggerTest {
beta.assertNotRunning(testUsEast3);
alpha.submit(applicationPackage);
- Optional<ApplicationVersion> revision2 = alpha.lastSubmission();
+ Optional<RevisionId> revision2 = alpha.lastSubmission();
assertEquals(Change.of(revision2.get()), alpha.instance().change());
assertEquals(Change.of(version1), beta.instance().change());
@@ -1380,7 +1383,7 @@ public class DeploymentTriggerTest {
// Upgrade instance 1; upgrade rolls out first, with revision following.
// The new platform won't roll out to the conservative instance until the normal one is upgraded.
app1.submit(applicationPackage);
- assertEquals(Change.of(version).with(app1.application().revisions().last().get()), app1.instance().change());
+ assertEquals(Change.of(version).with(app1.application().revisions().last().get().id()), app1.instance().change());
// Upgrade platform.
app2.runJob(systemTest);
app1.runJob(stagingTest)
@@ -1443,7 +1446,7 @@ public class DeploymentTriggerTest {
tester.triggerJobs();
assertEquals(1, tester.jobs().active().size());
assertEquals(Change.empty(), app1.instance().change());
- assertEquals(Change.of(version).with(app1.application().revisions().last().get()), app2.instance().change());
+ assertEquals(Change.of(version).with(app1.application().revisions().last().get().id()), app2.instance().change());
app2.runJob(productionEuWest1)
.runJob(testEuWest1);
@@ -1680,7 +1683,7 @@ public class DeploymentTriggerTest {
alpha.runJob(systemTest).runJob(stagingTest)
.runJob(productionUsEast3).runJob(testUsEast3);
- assertEquals(Optional.empty(), alpha.instance().change().application());
+ assertEquals(Optional.empty(), alpha.instance().change().revision());
// revision3 is submitted when revision2 is half-way.
tester.outstandingChangeDeployer().run();
@@ -1688,20 +1691,20 @@ public class DeploymentTriggerTest {
alpha.submit(appPackage, 2); // Will only roll out to gamma together with the next revision.
var revision3 = alpha.lastSubmission();
beta.runJob(testUsEast3);
- assertEquals(Optional.empty(), beta.instance().change().application());
+ assertEquals(Optional.empty(), beta.instance().change().revision());
// revision3 is the target for alpha, beta is done, revision2 is the target for gamma.
tester.outstandingChangeDeployer().run();
- assertEquals(revision3, alpha.instance().change().application());
- assertEquals(Optional.empty(), beta.instance().change().application());
- assertEquals(revision2, gamma.instance().change().application());
+ assertEquals(revision3, alpha.instance().change().revision());
+ assertEquals(Optional.empty(), beta.instance().change().revision());
+ assertEquals(revision2, gamma.instance().change().revision());
// revision3 rolls to beta, then a couple of new revisions are submitted to alpha, and the latter is the new target.
alpha.runJob(systemTest).runJob(stagingTest)
.runJob(productionUsEast3).runJob(testUsEast3);
tester.outstandingChangeDeployer().run();
- assertEquals(Optional.empty(), alpha.instance().change().application());
- assertEquals(revision3, beta.instance().change().application());
+ assertEquals(Optional.empty(), alpha.instance().change().revision());
+ assertEquals(revision3, beta.instance().change().revision());
// revision5 supersedes revision4
alpha.submit(appPackage, 3);
@@ -1713,8 +1716,8 @@ public class DeploymentTriggerTest {
alpha.runJob(systemTest).runJob(stagingTest)
.runJob(productionUsEast3).runJob(testUsEast3);
tester.outstandingChangeDeployer().run();
- assertEquals(Optional.empty(), alpha.instance().change().application());
- assertEquals(revision3, beta.instance().change().application());
+ assertEquals(Optional.empty(), alpha.instance().change().revision());
+ assertEquals(revision3, beta.instance().change().revision());
// revision6 rolls through alpha, and becomes the next target for beta, which also completes revision3.
alpha.submit(appPackage, 6);
@@ -1724,37 +1727,37 @@ public class DeploymentTriggerTest {
.runJob(testUsEast3);
beta.runJob(productionUsEast3).runJob(testUsEast3);
tester.outstandingChangeDeployer().run();
- assertEquals(Optional.empty(), alpha.instance().change().application());
- assertEquals(revision6, beta.instance().change().application());
+ assertEquals(Optional.empty(), alpha.instance().change().revision());
+ assertEquals(revision6, beta.instance().change().revision());
// revision 2 fails in gamma, but this does not bring on revision 3
gamma.failDeployment(productionUsEast3);
tester.outstandingChangeDeployer().run();
- assertEquals(revision2, gamma.instance().change().application());
+ assertEquals(revision2, gamma.instance().change().revision());
// revision 2 completes in gamma
gamma.runJob(productionUsEast3)
.runJob(testUsEast3);
tester.outstandingChangeDeployer().run();
- assertEquals(Optional.empty(), alpha.instance().change().application());
- assertEquals(Optional.empty(), gamma.instance().change().application()); // no other revisions after 3 are ready, so gamma waits
+ assertEquals(Optional.empty(), alpha.instance().change().revision());
+ assertEquals(Optional.empty(), gamma.instance().change().revision()); // no other revisions after 3 are ready, so gamma waits
// revision6 rolls through beta, and revision3 is the next target for gamma with "when-clear" change-revision, now that 6 is blocking 4 and 5
alpha.jobAborted(stagingTest).runJob(stagingTest);
beta.runJob(productionUsEast3).runJob(testUsEast3);
- assertEquals(Optional.empty(), beta.instance().change().application());
+ assertEquals(Optional.empty(), beta.instance().change().revision());
tester.outstandingChangeDeployer().run();
- assertEquals(Optional.empty(), alpha.instance().change().application());
- assertEquals(Optional.empty(), beta.instance().change().application());
- assertEquals(revision3, gamma.instance().change().application()); // revision4 never became ready, but 5 did, so 4 is skipped, and 3 rolls out alone instead.
+ assertEquals(Optional.empty(), alpha.instance().change().revision());
+ assertEquals(Optional.empty(), beta.instance().change().revision());
+ assertEquals(revision3, gamma.instance().change().revision()); // revision4 never became ready, but 5 did, so 4 is skipped, and 3 rolls out alone instead.
// revision 6 is next, once 3 is done
// revision 3 completes
gamma.runJob(productionUsEast3)
.runJob(testUsEast3);
tester.outstandingChangeDeployer().run();
- assertEquals(revision6, gamma.instance().change().application());
+ assertEquals(revision6, gamma.instance().change().revision());
// revision 7 becomes ready for gamma, but must wait for the idle time of 8 hours before being deployed
alpha.submit(appPackage, 1);
@@ -1762,11 +1765,11 @@ public class DeploymentTriggerTest {
alpha.deploy();
tester.outstandingChangeDeployer();
assertEquals(Change.empty(), gamma.instance().change());
- assertEquals(revision6.get(), gamma.deployment(ZoneId.from("prod.us-east-3")).applicationVersion());
+ assertEquals(revision6.get(), gamma.deployment(ZoneId.from("prod.us-east-3")).revision());
tester.clock().advance(Duration.ofHours(8));
tester.outstandingChangeDeployer().run();
- assertEquals(revision7, gamma.instance().change().application());
+ assertEquals(revision7, gamma.instance().change().revision());
// revision 8 is has too low risk to roll out on its own, but will start rolling immediately when revision 9 is submitted
gamma.deploy();
@@ -1775,11 +1778,11 @@ public class DeploymentTriggerTest {
alpha.deploy();
tester.outstandingChangeDeployer();
assertEquals(Change.empty(), gamma.instance().change());
- assertEquals(revision7.get(), gamma.deployment(ZoneId.from("prod.us-east-3")).applicationVersion());
+ assertEquals(revision7.get(), gamma.deployment(ZoneId.from("prod.us-east-3")).revision());
alpha.submit(appPackage, 5);
tester.outstandingChangeDeployer().run();
- assertEquals(revision8, gamma.instance().change().application());
+ assertEquals(revision8, gamma.instance().change().revision());
}
@Test
@@ -1941,15 +1944,17 @@ public class DeploymentTriggerTest {
ApplicationPackage cdPackage = new ApplicationPackageBuilder().region("cd-us-east-1")
.region("cd-aws-us-east-1a")
.build();
- var zones = List.of(ZoneId.from("test.cd-us-west-1"),
- ZoneId.from("staging.cd-us-west-1"),
- ZoneId.from("prod.cd-us-east-1"),
- ZoneId.from("prod.cd-aws-us-east-1a"));
- tester.controllerTester()
- .setZones(zones, SystemName.cd)
- .setRoutingMethod(zones, RoutingMethod.sharedLayer4);
- tester.controllerTester().upgradeSystem(Version.fromString("6.1"));
- tester.controllerTester().computeVersionStatus();
+ List<ZoneId> zones = List.of(ZoneId.from("test.cd-us-west-1"),
+ ZoneId.from("staging.cd-us-west-1"),
+ ZoneId.from("prod.cd-us-east-1"),
+ ZoneId.from("prod.cd-aws-us-east-1a"));
+ ControllerTester wrapped = new ControllerTester(cd);
+ wrapped.setZones(zones)
+ .setRoutingMethod(zones, RoutingMethod.sharedLayer4);
+ wrapped.upgradeSystem(Version.fromString("6.1"));
+ wrapped.computeVersionStatus();
+
+ DeploymentTester tester = new DeploymentTester(wrapped);
var app = tester.newDeploymentContext();
app.runJob(productionCdUsEast1, cdPackage);
@@ -2039,12 +2044,12 @@ public class DeploymentTriggerTest {
// Start upgrade, then receive new submission.
Version version1 = new Version("7.8.9");
- ApplicationVersion build1 = app.lastSubmission().get();
+ RevisionId build1 = app.lastSubmission().get();
tester.controllerTester().upgradeSystem(version1);
tester.upgrader().maintain();
app.runJob(stagingTest);
app.submit();
- ApplicationVersion build2 = app.lastSubmission().get();
+ RevisionId build2 = app.lastSubmission().get();
assertNotEquals(build1, build2);
// App now free to start system tests eagerly, for new submission. These should run assuming upgrade succeeds.
@@ -2053,16 +2058,16 @@ public class DeploymentTriggerTest {
assertEquals(version1,
app.instanceJobs().get(stagingTest).lastCompleted().get().versions().targetPlatform());
assertEquals(build1,
- app.instanceJobs().get(stagingTest).lastCompleted().get().versions().targetApplication());
+ app.instanceJobs().get(stagingTest).lastCompleted().get().versions().targetRevision());
assertEquals(version1,
app.instanceJobs().get(stagingTest).lastTriggered().get().versions().sourcePlatform().get());
assertEquals(build1,
- app.instanceJobs().get(stagingTest).lastTriggered().get().versions().sourceApplication().get());
+ app.instanceJobs().get(stagingTest).lastTriggered().get().versions().sourceRevision().get());
assertEquals(version1,
app.instanceJobs().get(stagingTest).lastTriggered().get().versions().targetPlatform());
assertEquals(build2,
- app.instanceJobs().get(stagingTest).lastTriggered().get().versions().targetApplication());
+ app.instanceJobs().get(stagingTest).lastTriggered().get().versions().targetRevision());
// App completes upgrade, and outstanding change is triggered. This should let relevant, running jobs finish.
app.runJob(systemTest)
@@ -2151,7 +2156,7 @@ public class DeploymentTriggerTest {
.build());
app.deploy();
assertEquals(version2, tester.jobs().last(app.instanceId(), productionUsEast3).get().versions().targetPlatform());
- assertEquals(version2, tester.jobs().last(app.instanceId(), productionUsEast3).get().versions().targetApplication().compileVersion().get());
+ assertEquals(version2, app.application().revisions().get(tester.jobs().last(app.instanceId(), productionUsEast3).get().versions().targetRevision()).compileVersion().get());
}
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java
index 4e538acb8f2..98cbf33fb2b 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java
@@ -12,6 +12,7 @@ import com.yahoo.config.provision.zone.RoutingMethod;
import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.slime.Inspector;
import com.yahoo.slime.SlimeUtils;
+import com.yahoo.vespa.hosted.controller.ControllerTester;
import com.yahoo.vespa.hosted.controller.api.application.v4.model.configserverbindings.ConfigChangeActions;
import com.yahoo.vespa.hosted.controller.api.application.v4.model.configserverbindings.RestartAction;
import com.yahoo.vespa.hosted.controller.api.application.v4.model.configserverbindings.ServiceInfo;
@@ -480,15 +481,16 @@ public class InternalStepRunnerTest {
@Test
public void realDeploymentRequiresForTesterCert() {
- tester.controllerTester().zoneRegistry().setSystemName(SystemName.Public);
- var zones = List.of(ZoneApiMock.fromId("test.aws-us-east-1c"),
- ZoneApiMock.fromId("staging.aws-us-east-1c"),
- ZoneApiMock.fromId("prod.aws-us-east-1c"));
- tester.controllerTester().zoneRegistry()
- .setZones(zones)
- .setRoutingMethod(zones, RoutingMethod.exclusive);
+ List<ZoneApiMock> zones = List.of(ZoneApiMock.fromId("test.aws-us-east-1c"),
+ ZoneApiMock.fromId("staging.aws-us-east-1c"),
+ ZoneApiMock.fromId("prod.aws-us-east-1c"));
+ ControllerTester wrapped = new ControllerTester(SystemName.Public);
+ wrapped.zoneRegistry()
+ .setZones(zones)
+ .setRoutingMethod(zones, RoutingMethod.exclusive);
+ tester = new DeploymentTester(wrapped);
tester.configServer().bootstrap(tester.controllerTester().zoneRegistry().zones().all().ids(), SystemApplication.values());
- ZoneId testZone = JobType.systemTest.zone(tester.controller().system());
+ app = tester.newDeploymentContext();
RunId id = app.newRun(JobType.systemTest);
tester.configServer().throwOnPrepare(instanceId -> {
if (instanceId.instance().isTester())
@@ -517,14 +519,16 @@ public class InternalStepRunnerTest {
@Test
public void certificateTimeoutAbortsJob() {
- tester.controllerTester().zoneRegistry().setSystemName(SystemName.Public);
- var zones = List.of(ZoneApiMock.fromId("test.aws-us-east-1c"),
- ZoneApiMock.fromId("staging.aws-us-east-1c"),
- ZoneApiMock.fromId("prod.aws-us-east-1c"));
- tester.controllerTester().zoneRegistry()
- .setZones(zones)
- .setRoutingMethod(zones, RoutingMethod.exclusive);
+ List<ZoneApiMock> zones = List.of(ZoneApiMock.fromId("test.aws-us-east-1c"),
+ ZoneApiMock.fromId("staging.aws-us-east-1c"),
+ ZoneApiMock.fromId("prod.aws-us-east-1c"));
+ ControllerTester wrapped = new ControllerTester(SystemName.Public);
+ wrapped.zoneRegistry()
+ .setZones(zones)
+ .setRoutingMethod(zones, RoutingMethod.exclusive);
+ tester = new DeploymentTester(wrapped);
tester.configServer().bootstrap(tester.controllerTester().zoneRegistry().zones().all().ids(), SystemApplication.values());
+ app = tester.newDeploymentContext();
RunId id = app.startSystemTestTests();
List<X509Certificate> trusted = new ArrayList<>(DeploymentContext.publicApplicationPackage().trustedCertificates());
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ApplicationStoreMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ApplicationStoreMock.java
index 3dbe307fa5a..8ed38761c95 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ApplicationStoreMock.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ApplicationStoreMock.java
@@ -5,9 +5,10 @@ import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.ApplicationName;
import com.yahoo.config.provision.InstanceName;
import com.yahoo.config.provision.TenantName;
+import com.yahoo.vespa.hosted.controller.NotExistsException;
import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationStore;
-import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.TesterId;
import com.yahoo.vespa.hosted.controller.application.TenantAndApplicationId;
@@ -29,7 +30,7 @@ public class ApplicationStoreMock implements ApplicationStore {
private static final byte[] tombstone = new byte[0];
- private final Map<ApplicationId, Map<ApplicationVersion, byte[]>> store = new ConcurrentHashMap<>();
+ private final Map<ApplicationId, Map<RevisionId, byte[]>> store = new ConcurrentHashMap<>();
private final Map<DeploymentId, byte[]> devStore = new ConcurrentHashMap<>();
private final Map<ApplicationId, Map<Long, byte[]>> diffs = new ConcurrentHashMap<>();
private final Map<DeploymentId, Map<Long, byte[]>> devDiffs = new ConcurrentHashMap<>();
@@ -45,15 +46,14 @@ public class ApplicationStoreMock implements ApplicationStore {
}
@Override
- public byte[] get(DeploymentId deploymentId, ApplicationVersion applicationVersion) {
- if (applicationVersion.isDeployedDirectly())
+ public byte[] get(DeploymentId deploymentId, RevisionId revisionId) {
+ if ( ! revisionId.isProduction())
return requireNonNull(devStore.get(deploymentId));
TenantAndApplicationId tenantAndApplicationId = TenantAndApplicationId.from(deploymentId.applicationId());
- byte[] bytes = store.get(appId(tenantAndApplicationId.tenant(), tenantAndApplicationId.application())).get(applicationVersion);
+ byte[] bytes = store.get(appId(tenantAndApplicationId.tenant(), tenantAndApplicationId.application())).get(revisionId);
if (bytes == null)
- throw new IllegalArgumentException("No application package found for " + tenantAndApplicationId +
- " with version " + applicationVersion.stringId());
+ throw new NotExistsException("No " + revisionId + " found for " + tenantAndApplicationId);
return bytes;
}
@@ -71,21 +71,20 @@ public class ApplicationStoreMock implements ApplicationStore {
@Override
public Optional<byte[]> find(TenantName tenant, ApplicationName application, long buildNumber) {
return store.getOrDefault(appId(tenant, application), Map.of()).entrySet().stream()
- .filter(kv -> kv.getKey().buildNumber().orElse(Long.MIN_VALUE) == buildNumber)
+ .filter(kv -> kv.getKey().number() == buildNumber)
.map(Map.Entry::getValue)
.findFirst();
}
@Override
- public void put(TenantName tenant, ApplicationName application, ApplicationVersion applicationVersion, byte[] bytes, byte[] tests, byte[] diff) {
- store.computeIfAbsent(appId(tenant, application), __ -> new ConcurrentHashMap<>()).put(applicationVersion, bytes);
- store.computeIfAbsent(testerId(tenant, application), key -> new ConcurrentHashMap<>()) .put(applicationVersion, tests);
- applicationVersion.buildNumber().ifPresent(buildNumber ->
- diffs.computeIfAbsent(appId(tenant, application), __ -> new ConcurrentHashMap<>()).put(buildNumber, diff));
+ public void put(TenantName tenant, ApplicationName application, RevisionId revision, byte[] bytes, byte[] tests, byte[] diff) {
+ store.computeIfAbsent(appId(tenant, application), __ -> new ConcurrentHashMap<>()).put(revision, bytes);
+ store.computeIfAbsent(testerId(tenant, application), key -> new ConcurrentHashMap<>()) .put(revision, tests);
+ diffs.computeIfAbsent(appId(tenant, application), __ -> new ConcurrentHashMap<>()).put(revision.number(), diff);
}
@Override
- public void prune(TenantName tenant, ApplicationName application, ApplicationVersion oldestToRetain) {
+ public void prune(TenantName tenant, ApplicationName application, RevisionId oldestToRetain) {
store.getOrDefault(appId(tenant, application), Map.of()).keySet().removeIf(version -> version.compareTo(oldestToRetain) < 0);
store.getOrDefault(testerId(tenant, application), Map.of()).keySet().removeIf(version -> version.compareTo(oldestToRetain) < 0);
}
@@ -97,8 +96,8 @@ public class ApplicationStoreMock implements ApplicationStore {
}
@Override
- public byte[] getTester(TenantName tenant, ApplicationName application, ApplicationVersion applicationVersion) {
- return requireNonNull(store.get(testerId(tenant, application)).get(applicationVersion));
+ public byte[] getTester(TenantName tenant, ApplicationName application, RevisionId revision) {
+ return requireNonNull(store.get(testerId(tenant, application)).get(revision));
}
@@ -114,10 +113,9 @@ public class ApplicationStoreMock implements ApplicationStore {
}
@Override
- public void putDev(DeploymentId deploymentId, ApplicationVersion applicationVersion, byte[] applicationPackage, byte[] diff) {
+ public void putDev(DeploymentId deploymentId, RevisionId revision, byte[] applicationPackage, byte[] diff) {
devStore.put(deploymentId, applicationPackage);
- applicationVersion.buildNumber().ifPresent(buildNumber ->
- devDiffs.computeIfAbsent(deploymentId, __ -> new ConcurrentHashMap<>()).put(buildNumber, diff));
+ devDiffs.computeIfAbsent(deploymentId, __ -> new ConcurrentHashMap<>()).put(revision.number(), diff);
}
@Override
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ZoneRegistryMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ZoneRegistryMock.java
index a4c30cca29e..1f4218af1b6 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ZoneRegistryMock.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ZoneRegistryMock.java
@@ -41,9 +41,11 @@ public class ZoneRegistryMock extends AbstractComponent implements ZoneRegistry
private final Map<CloudName, UpgradePolicy> osUpgradePolicies = new HashMap<>();
private final Map<ZoneApi, List<RoutingMethod>> zoneRoutingMethods = new HashMap<>();
private final Set<ZoneApi> reprovisionToUpgradeOs = new HashSet<>();
+ private final SystemName system; // Don't even think about making it non-final! ƪ(`▿▿▿▿´ƪ)
+
+
private List<? extends ZoneApi> zones;
- private SystemName system;
private UpgradePolicy upgradePolicy = null;
/**
@@ -95,11 +97,6 @@ public class ZoneRegistryMock extends AbstractComponent implements ZoneRegistry
return setZones(List.of(zone));
}
- public ZoneRegistryMock setSystemName(SystemName system) {
- this.system = system;
- return this;
- }
-
public ZoneRegistryMock setUpgradePolicy(UpgradePolicy upgradePolicy) {
this.upgradePolicy = upgradePolicy;
return this;
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 d50c69196c6..8b155644fb4 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
@@ -6,6 +6,7 @@ import com.yahoo.config.provision.ApplicationId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId;
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.application.TenantAndApplicationId;
@@ -77,10 +78,7 @@ 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",
- "bada55"),
- 321),
+ RevisionId.forProduction(321),
Optional.empty(),
Optional.empty());
@@ -95,7 +93,7 @@ public class JobRunnerTest {
TenantAndApplicationId appId = tester.createApplication("tenant", "real", "default").id();
ApplicationId id = appId.defaultInstance();
byte[] testPackageBytes = new byte[0];
- jobs.submit(appId, versions.targetApplication().source(), Optional.empty(), Optional.empty(), 2, applicationPackage, testPackageBytes, Optional.empty(), 0);
+ jobs.submit(appId, Optional.empty(), Optional.empty(), Optional.empty(), 2, applicationPackage, testPackageBytes, Optional.empty(), 0);
start(jobs, id, systemTest);
try {
@@ -127,7 +125,7 @@ public class JobRunnerTest {
TenantAndApplicationId appId = tester.createApplication("tenant", "real", "default").id();
ApplicationId id = appId.defaultInstance();
byte[] testPackageBytes = new byte[0];
- jobs.submit(appId, versions.targetApplication().source(), Optional.empty(), Optional.empty(), 2, applicationPackage, testPackageBytes, Optional.empty(), 0);
+ jobs.submit(appId, Optional.empty(), Optional.empty(), Optional.empty(), 2, applicationPackage, testPackageBytes, Optional.empty(), 0);
Supplier<Run> run = () -> jobs.last(id, systemTest).get();
start(jobs, id, systemTest);
@@ -235,7 +233,7 @@ public class JobRunnerTest {
TenantAndApplicationId appId = tester.createApplication("tenant", "real", "default").id();
ApplicationId id = appId.defaultInstance();
byte[] testPackageBytes = new byte[0];
- jobs.submit(appId, versions.targetApplication().source(), Optional.empty(), Optional.empty(), 2, applicationPackage, testPackageBytes, Optional.empty(), 0);
+ jobs.submit(appId, Optional.empty(), Optional.empty(), Optional.empty(), 2, applicationPackage, testPackageBytes, Optional.empty(), 0);
RunId runId = new RunId(id, systemTest, 1);
start(jobs, id, systemTest);
@@ -273,7 +271,7 @@ public class JobRunnerTest {
ApplicationId instanceId = appId.defaultInstance();
JobId jobId = new JobId(instanceId, systemTest);
byte[] testPackageBytes = new byte[0];
- jobs.submit(appId, versions.targetApplication().source(), Optional.empty(), Optional.empty(), 2, applicationPackage, testPackageBytes, Optional.empty(), 0);
+ jobs.submit(appId, Optional.empty(), Optional.empty(), Optional.empty(), 2, applicationPackage, testPackageBytes, Optional.empty(), 0);
assertFalse(jobs.lastSuccess(jobId).isPresent());
for (int i = 0; i < jobs.historyLength(); i++) {
@@ -369,7 +367,7 @@ public class JobRunnerTest {
TenantAndApplicationId appId = tester.createApplication("tenant", "real", "default").id();
ApplicationId id = appId.defaultInstance();
byte[] testPackageBytes = new byte[0];
- jobs.submit(appId, versions.targetApplication().source(), Optional.empty(), Optional.empty(), 2, applicationPackage, testPackageBytes, Optional.empty(), 0);
+ jobs.submit(appId, Optional.empty(), Optional.empty(), Optional.empty(), 2, applicationPackage, testPackageBytes, Optional.empty(), 0);
start(jobs, id, systemTest);
tester.clock().advance(JobRunner.jobTimeout.plus(Duration.ofSeconds(1)));
@@ -387,7 +385,7 @@ public class JobRunnerTest {
TenantAndApplicationId appId = tester.createApplication("tenant", "real", "default").id();
ApplicationId id = appId.defaultInstance();
byte[] testPackageBytes = new byte[0];
- jobs.submit(appId, versions.targetApplication().source(), Optional.empty(), Optional.empty(), 2, applicationPackage, testPackageBytes, Optional.empty(), 0);
+ jobs.submit(appId, Optional.empty(), Optional.empty(), Optional.empty(), 2, applicationPackage, testPackageBytes, Optional.empty(), 0);
for (Step step : JobProfile.of(systemTest).steps())
outcomes.put(step, running);
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporterTest.java
index 455e802e87b..658fbccd660 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporterTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporterTest.java
@@ -259,7 +259,7 @@ public class MetricsReporterTest {
var context = tester.newDeploymentContext()
.submit(applicationPackage)
.deploy();
- assertEquals(1000, context.lastSubmission().get().buildTime().get().toEpochMilli());
+ assertEquals(1000, context.application().revisions().get(context.lastSubmission().get()).buildTime().get().toEpochMilli());
MetricsReporter reporter = createReporter(tester.controller());
reporter.maintain();
@@ -483,7 +483,6 @@ public class MetricsReporterTest {
@Test
public void tenant_counter() {
var tester = new ControllerTester(SystemName.Public);
- tester.zoneRegistry().setSystemName(SystemName.Public);
tester.createTenant("foo", Tenant.Type.cloud);
tester.createTenant("bar", Tenant.Type.cloud);
tester.createTenant("fix", Tenant.Type.cloud);
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 0a0b94bd6c9..e989486c595 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
@@ -3,6 +3,7 @@ package com.yahoo.vespa.hosted.controller.maintenance;
import com.yahoo.component.Version;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId;
import com.yahoo.vespa.hosted.controller.application.Change;
import com.yahoo.vespa.hosted.controller.application.pkg.ApplicationPackage;
import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder;
@@ -36,12 +37,12 @@ public class OutstandingChangeDeployerTest {
assertFalse(app.deploymentStatus().outstandingChange(app.instance().name()).hasTargets());
app.submit(applicationPackage);
- Optional<ApplicationVersion> revision = app.lastSubmission();
+ Optional<RevisionId> revision = app.lastSubmission();
assertFalse(app.deploymentStatus().outstandingChange(app.instance().name()).hasTargets());
assertEquals(Change.of(version).with(revision.get()), app.instance().change());
app.submit(applicationPackage);
- Optional<ApplicationVersion> outstanding = app.lastSubmission();
+ Optional<RevisionId> outstanding = app.lastSubmission();
assertTrue(app.deploymentStatus().outstandingChange(app.instance().name()).hasTargets());
assertEquals(Change.of(version).with(revision.get()), app.instance().change());
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java
index 3fb57402b35..ef4bfdb568e 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java
@@ -5,6 +5,7 @@ import com.yahoo.component.Version;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.test.ManualClock;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId;
import com.yahoo.vespa.hosted.controller.application.Change;
import com.yahoo.vespa.hosted.controller.application.Deployment;
@@ -792,12 +793,12 @@ public class UpgraderTest {
// New application change
app.submit(applicationPackage("default"));
- String applicationVersion = app.lastSubmission().get().stringId();
+ RevisionId revision = app.lastSubmission().get();
// Application change recorded together with ongoing upgrade
assertTrue("Change contains both upgrade and application change",
app.instance().change().platform().get().equals(version) &&
- app.instance().change().application().get().stringId().equals(applicationVersion));
+ app.instance().change().revision().get().equals(revision));
// Deployment completes
app.runJob(systemTest).runJob(stagingTest)
@@ -807,7 +808,7 @@ public class UpgraderTest {
for (Deployment deployment : app.instance().deployments().values()) {
assertEquals(version, deployment.version());
- assertEquals(applicationVersion, deployment.applicationVersion().stringId());
+ assertEquals(revision, deployment.revision());
}
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/notification/NotificationsDbTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/notification/NotificationsDbTest.java
index d0dbb23ad1b..28be68cf850 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/notification/NotificationsDbTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/notification/NotificationsDbTest.java
@@ -4,6 +4,7 @@ package com.yahoo.vespa.hosted.controller.notification;
import com.google.common.collect.ImmutableBiMap;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.ClusterSpec;
+import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.TenantName;
import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.path.Path;
@@ -66,7 +67,7 @@ public class NotificationsDbTest {
notification(1501, Type.deployment, Level.warning, NotificationSource.from(new RunId(ApplicationId.from(tenant.value(), "app1", "instance1"), JobType.devUsEast1, 4)), "run id msg"));
private final ManualClock clock = new ManualClock(Instant.ofEpochSecond(12345));
- private final MockCuratorDb curatorDb = new MockCuratorDb();
+ private final MockCuratorDb curatorDb = new MockCuratorDb(SystemName.Public);
private final MockMailer mailer = new MockMailer();
private final NotificationsDb notificationsDb = new NotificationsDb(clock, curatorDb, new Notifier(curatorDb, mailer));
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 742bbaec918..1fc99b0da1c 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
@@ -5,6 +5,7 @@ import com.yahoo.component.Version;
import com.yahoo.config.application.api.DeploymentSpec;
import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.security.KeyUtils;
import com.yahoo.slime.SlimeUtils;
@@ -13,6 +14,7 @@ import com.yahoo.vespa.hosted.controller.Instance;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId;
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;
@@ -53,7 +55,7 @@ import static org.junit.Assert.assertEquals;
public class ApplicationSerializerTest {
- private static final ApplicationSerializer APPLICATION_SERIALIZER = new ApplicationSerializer();
+ private static final ApplicationSerializer APPLICATION_SERIALIZER = new ApplicationSerializer(SystemName.main);
private static final Path testData = Paths.get("src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/");
private static final ZoneId zone1 = ZoneId.from("prod", "us-west-1");
private static final ZoneId zone2 = ZoneId.from("prod", "us-east-3");
@@ -83,21 +85,31 @@ public class ApplicationSerializerTest {
OptionalLong projectId = OptionalLong.of(123L);
+ ApplicationId id1 = ApplicationId.from("t1", "a1", "i1");
+ ApplicationId id3 = ApplicationId.from("t1", "a1", "i3");
List<Deployment> deployments = new ArrayList<>();
- ApplicationVersion applicationVersion1 = new ApplicationVersion(Optional.of(new SourceRevision("git@github:org/repo.git", "branch1", "commit1")),
- OptionalLong.of(31), Optional.of("william@shakespeare"),
- Optional.of(Version.fromString("1.2.3")), Optional.of(Instant.ofEpochMilli(666)),
- Optional.empty(), Optional.of("best commit"), true, Optional.of("hash1"),
- true, false, Optional.of("~(˘▾˘)~"), 3);
+ ApplicationVersion applicationVersion1 = new ApplicationVersion(RevisionId.forProduction(31),
+ Optional.of(new SourceRevision("git@github:org/repo.git", "branch1", "commit1")),
+ Optional.of("william@shakespeare"),
+ Optional.of(Version.fromString("1.2.3")),
+ Optional.of(Instant.ofEpochMilli(666)),
+ Optional.empty(),
+ Optional.of("best commit"),
+ Optional.of("hash1"),
+ true,
+ false,
+ Optional.of("~(˘▾˘)~"),
+ 3);
assertEquals("https://github/org/repo/tree/commit1", applicationVersion1.sourceUrl().get());
- ApplicationVersion applicationVersion2 = ApplicationVersion
- .from(new SourceRevision("repo1", "branch1", "commit1"), 32, "a@b",
- Version.fromString("6.3.1"), Instant.ofEpochMilli(496));
+ ApplicationVersion applicationVersion2 = ApplicationVersion.from(RevisionId.forDevelopment(31, new JobId(id1, JobType.productionUsEast3)),
+ new SourceRevision("repo1", "branch1", "commit1"), "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),
+ deployments.add(new Deployment(zone1, applicationVersion1.id(), Version.fromString("1.2.3"), Instant.ofEpochMilli(3),
DeploymentMetrics.none, DeploymentActivity.none, QuotaUsage.none, OptionalDouble.empty()));
- deployments.add(new Deployment(zone2, applicationVersion2, Version.fromString("1.2.3"), Instant.ofEpochMilli(5),
+ deployments.add(new Deployment(zone2, applicationVersion2.id(), Version.fromString("1.2.3"), Instant.ofEpochMilli(5),
new DeploymentMetrics(2, 3, 4, 5, 6,
Optional.of(Instant.now().truncatedTo(ChronoUnit.MILLIS)),
Map.of(DeploymentMetrics.Warning.all, 3)),
@@ -112,10 +124,8 @@ public class ApplicationSerializerTest {
ZoneId.from("prod", "us-east-3"), RotationState.out),
Instant.ofEpochMilli(42))));
- ApplicationId id1 = ApplicationId.from("t1", "a1", "i1");
- ApplicationId id3 = ApplicationId.from("t1", "a1", "i3");
RevisionHistory revisions = RevisionHistory.ofRevisions(List.of(applicationVersion1),
- Map.of(new JobId(id3, JobType.devUsEast1), List.of(applicationVersion2)));
+ Map.of(new JobId(id1, JobType.productionUsEast3), List.of(applicationVersion2)));
List<Instance> instances = List.of(new Instance(id1,
deployments,
Map.of(JobType.systemTest, Instant.ofEpochMilli(333)),
@@ -140,7 +150,8 @@ public class ApplicationSerializerTest {
new ApplicationMetrics(0.5, 0.9),
Set.of(publicKey, otherPublicKey),
projectId,
- revisions, instances
+ revisions,
+ instances
);
Application serialized = APPLICATION_SERIALIZER.fromSlime(SlimeUtils.toJsonBytes(APPLICATION_SERIALIZER.toSlime(original)));
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/BufferedLogStoreTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/BufferedLogStoreTest.java
index a9baeb9589d..e13c598f2a9 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/BufferedLogStoreTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/BufferedLogStoreTest.java
@@ -2,6 +2,7 @@
package com.yahoo.vespa.hosted.controller.persistence;
import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.SystemName;
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.deployment.JobType;
@@ -28,7 +29,7 @@ public class BufferedLogStoreTest {
public void chunkingAndFlush() {
int chunkSize = 1 << 10;
int maxChunks = 1 << 5;
- CuratorDb buffer = new MockCuratorDb();
+ CuratorDb buffer = new MockCuratorDb(SystemName.main);
RunDataStore store = new MockRunDataStore();
BufferedLogStore logs = new BufferedLogStore(chunkSize, chunkSize * maxChunks, buffer, store);
RunId id = new RunId(ApplicationId.from("tenant", "application", "instance"),
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 5f7d280a230..f5922fd74aa 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
@@ -8,6 +8,7 @@ import com.yahoo.security.X509CertificateUtils;
import com.yahoo.slime.SlimeUtils;
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.RevisionId;
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.deployment.ConvergenceSummary;
@@ -19,11 +20,14 @@ import com.yahoo.vespa.hosted.controller.deployment.StepInfo;
import org.junit.Test;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.util.Collections;
+import java.util.List;
+import java.util.Map;
import java.util.Optional;
import java.util.OptionalLong;
@@ -46,6 +50,7 @@ import static com.yahoo.vespa.hosted.controller.deployment.Step.installTester;
import static com.yahoo.vespa.hosted.controller.deployment.Step.report;
import static com.yahoo.vespa.hosted.controller.deployment.Step.startStagingSetup;
import static com.yahoo.vespa.hosted.controller.deployment.Step.startTests;
+import static java.nio.charset.StandardCharsets.UTF_8;
import static java.time.temporal.ChronoUnit.MILLIS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -83,22 +88,27 @@ public class RunSerializerTest {
assertEquals(running, run.status());
assertEquals(3, run.lastTestLogEntry());
assertEquals(new Version(1, 2, 3), run.versions().targetPlatform());
- ApplicationVersion applicationVersion = new ApplicationVersion(Optional.of(new SourceRevision("git@github.com:user/repo.git",
- "master",
- "f00bad")), OptionalLong.of(123), Optional.of("a@b"), Optional.of(Version.fromString("6.3.1")), Optional.of(Instant.ofEpochMilli(100)), Optional.empty(), Optional.empty(), true, Optional.empty(), true, false, Optional.empty(), 0);
- assertEquals(applicationVersion, run.versions().targetApplication());
- assertEquals(applicationVersion.authorEmail(), run.versions().targetApplication().authorEmail());
- assertEquals(applicationVersion.buildTime(), run.versions().targetApplication().buildTime());
- assertEquals(applicationVersion.compileVersion(), run.versions().targetApplication().compileVersion());
- assertEquals("f00bad", run.versions().targetApplication().commit().get());
- assertEquals("https://github.com/user/repo/tree/f00bad", run.versions().targetApplication().sourceUrl().get());
+ RevisionId revision1 = RevisionId.forDevelopment(123, id.job());
+ RevisionId revision2 = RevisionId.forProduction(122);
+ ApplicationVersion applicationVersion1 = new ApplicationVersion(revision1,
+ Optional.of(new SourceRevision("git@github.com:user/repo.git", "master", "f00bad")),
+ Optional.of("a@b"),
+ Optional.of(Version.fromString("6.3.1")),
+ Optional.of(Instant.ofEpochMilli(100)),
+ Optional.empty(),
+ Optional.empty(),
+ Optional.empty(),
+ true,
+ false,
+ Optional.empty(),
+ 0);
+ ApplicationVersion applicationVersion2 = ApplicationVersion.from(revision2, new SourceRevision("git@github.com:user/repo.git",
+ "master",
+ "badb17"));
+ assertEquals(revision1, run.versions().targetRevision());
assertEquals("because", run.reason().get());
assertEquals(new Version(1, 2, 2), run.versions().sourcePlatform().get());
- assertEquals(ApplicationVersion.from(new SourceRevision("git@github.com:user/repo.git",
- "master",
- "badb17"),
- 122),
- run.versions().sourceApplication().get());
+ assertEquals(revision2, run.versions().sourceRevision().get());
assertEquals(Optional.of(new ConvergenceSummary(1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233)),
run.convergenceSummary());
assertEquals(X509CertificateUtils.fromPem("-----BEGIN CERTIFICATE-----\n" +
@@ -128,6 +138,8 @@ public class RunSerializerTest {
.build(),
run.steps());
+ Map<RevisionId, ApplicationVersion> revisions = Map.of(revision1, applicationVersion1, revision2, applicationVersion2);
+
run = run.with(1L << 50)
.with(Instant.now().truncatedTo(MILLIS))
.noNodesDownSince(Instant.now().truncatedTo(MILLIS))
@@ -136,7 +148,8 @@ public class RunSerializerTest {
assertEquals(aborted, run.status());
assertTrue(run.hasEnded());
- Run phoenix = serializer.runsFromSlime(serializer.toSlime(Collections.singleton(run))).get(id);
+ // Run phoenix = serializer.runsFromSlime(serializer.toSlime(List.of(run))); // TODO jonmv: use runs again, once compatability code is gone.
+ Run phoenix = serializer.runFromSlime(serializer.toSlime(run, revisions::get));
assertEquals(run.id(), phoenix.id());
assertEquals(run.start(), phoenix.start());
assertEquals(run.end(), phoenix.end());
@@ -149,8 +162,11 @@ public class RunSerializerTest {
assertEquals(run.isDryRun(), phoenix.isDryRun());
assertEquals(run.reason(), phoenix.reason());
+ assertEquals(new String(SlimeUtils.toJsonBytes(serializer.toSlime(run, revisions::get).get(), false), UTF_8),
+ new String(SlimeUtils.toJsonBytes(serializer.toSlime(phoenix, revisions::get).get(), false), UTF_8));
+
Run initial = Run.initial(id, run.versions(), run.isRedeployment(), run.start(), JobProfile.production, Optional.empty());
- assertEquals(initial, serializer.runFromSlime(serializer.toSlime(initial)));
+ assertEquals(initial, serializer.runFromSlime(serializer.toSlime(initial, revisions::get)));
}
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java
index 07f00e8c989..bed2bb97aeb 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java
@@ -38,7 +38,7 @@ import static org.junit.Assert.fail;
*/
public class ContainerTester {
- private static final boolean writeResponses = false;
+ private static final boolean writeResponses = true;
private final JDisc container;
private final String responseFilePath;
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java
index 6e81c4280c2..d0176ffd5be 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java
@@ -365,7 +365,7 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest {
request("/application/v4/tenant/scoober/application/unique/submit", POST)
.data(data)
.roles(Set.of(Role.developer(tenantName))),
- "{\"message\":\"Application package version: 1.0.1-commit1, source revision of repository 'repository1', branch 'master' with commit 'commit1', by a@b, built against 6.1 at 1970-01-01T00:00:01Z\"}");
+ "{\"message\":\"application build 1, source revision of repository 'repository1', branch 'master' with commit 'commit1', by a@b, built against 6.1 at 1970-01-01T00:00:01Z\"}");
assertTrue(tester.controller().applications().getApplication(TenantAndApplicationId.from(tenantName, application)).isPresent());
}
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 c8d88101304..8c639628fdf 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
@@ -329,7 +329,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/submit", POST)
.screwdriverIdentity(SCREWDRIVER_ID)
.data(createApplicationSubmissionData(applicationPackageInstance1, 123)),
- "{\"message\":\"Application package version: 1.0.1-commit1, source revision of repository 'repository1', branch 'master' with commit 'commit1', by a@b, built against 6.1 at 1970-01-01T00:00:01Z\"}");
+ "{\"message\":\"application build 1, source revision of repository 'repository1', branch 'master' with commit 'commit1', by a@b, built against 6.1 at 1970-01-01T00:00:01Z\"}");
app1.runJob(JobType.systemTest).runJob(JobType.stagingTest).runJob(JobType.productionUsCentral1);
@@ -358,7 +358,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
tester.assertResponse(request("/application/v4/tenant/tenant2/application/application2/submit", POST)
.screwdriverIdentity(SCREWDRIVER_ID)
.data(createApplicationSubmissionData(applicationPackage, 1000)),
- "{\"message\":\"Application package version: 1.0.1-commit1, source revision of repository 'repository1', branch 'master' with commit 'commit1', by a@b, built against 6.1 at 1970-01-01T00:00:01Z\"}");
+ "{\"message\":\"application build 1, source revision of repository 'repository1', branch 'master' with commit 'commit1', by a@b, built against 6.1 at 1970-01-01T00:00:01Z\"}");
deploymentTester.triggerJobs();
@@ -518,18 +518,18 @@ public class ApplicationApiTest extends ControllerContainerTest {
// POST a roll-out of the latest application
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1/deploying/application", POST)
.userIdentity(USER_ID),
- "{\"message\":\"Triggered application change to 1.0.1-commit1 for tenant1.application1.instance1\"}");
+ "{\"message\":\"Triggered revision change to build 1 for tenant1.application1.instance1\"}");
// POST a roll-out of a given revision
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1/deploying/application", POST)
.data("{ \"build\": 1 }")
.userIdentity(USER_ID),
- "{\"message\":\"Triggered application change to 1.0.1-commit1 for tenant1.application1.instance1\"}");
+ "{\"message\":\"Triggered revision change to build 1 for tenant1.application1.instance1\"}");
// DELETE (cancel) ongoing change
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1/deploying", DELETE)
.userIdentity(HOSTED_VESPA_OPERATOR),
- "{\"message\":\"Changed deployment from 'application change to 1.0.1-commit1' to 'no change' for tenant1.application1.instance1\"}");
+ "{\"message\":\"Changed deployment from 'revision change to build 1' to 'no change' for tenant1.application1.instance1\"}");
// DELETE (cancel) again is a no-op
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1/deploying", DELETE)
@@ -773,7 +773,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1/submit", POST)
.screwdriverIdentity(SCREWDRIVER_ID)
.data(createApplicationSubmissionData(packageWithService, 123)),
- "{\"message\":\"Application package version: 1.0.2-commit1, source revision of repository 'repository1', branch 'master' with commit 'commit1', by a@b, built against 6.1 at 1970-01-01T00:00:01Z\"}");
+ "{\"message\":\"application build 2, source revision of repository 'repository1', branch 'master' with commit 'commit1', by a@b, built against 6.1 at 1970-01-01T00:00:01Z\"}");
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/diff/2", GET).userIdentity(HOSTED_VESPA_OPERATOR),
(response) -> assertTrue(response.getBodyAsString(),
@@ -818,7 +818,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
.screwdriverIdentity(SCREWDRIVER_ID)
.header("X-Content-Hash", Base64.getEncoder().encodeToString(Signatures.sha256Digest(streamer::data)))
.data(streamer),
- "{\"message\":\"Application package version: 1.0.3-commit1, source revision of repository 'repository1', branch 'master' with commit 'commit1', by a@b, built against 6.1 at 1970-01-01T00:00:01Z\"}");
+ "{\"message\":\"application build 3, source revision of repository 'repository1', branch 'master' with commit 'commit1', by a@b, built against 6.1 at 1970-01-01T00:00:01Z\"}");
// Sixth attempt has a multi-instance deployment spec, and is accepted.
ApplicationPackage multiInstanceSpec = new ApplicationPackageBuilder()
@@ -831,7 +831,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1/submit", POST)
.screwdriverIdentity(SCREWDRIVER_ID)
.data(createApplicationSubmissionData(multiInstanceSpec, 123)),
- "{\"message\":\"Application package version: 1.0.4-commit1, source revision of repository 'repository1', branch 'master' with commit 'commit1', by a@b, built against 6.1 at 1970-01-01T00:00:01Z\"}");
+ "{\"message\":\"application build 4, source revision of repository 'repository1', branch 'master' with commit 'commit1', by a@b, built against 6.1 at 1970-01-01T00:00:01Z\"}");
// DELETE submitted build, to mark it as non-deployable
@@ -1196,7 +1196,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
// GET non-existent application package
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/package", GET).userIdentity(HOSTED_VESPA_OPERATOR),
- "{\"error-code\":\"NOT_FOUND\",\"message\":\"No application package has been submitted for 'tenant1.application1'\"}",
+ "{\"error-code\":\"NOT_FOUND\",\"message\":\"no application package has been submitted for tenant1.application1\"}",
404);
// GET non-existent application package of specific build
@@ -1204,11 +1204,11 @@ public class ApplicationApiTest extends ControllerContainerTest {
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/submit", POST)
.screwdriverIdentity(SCREWDRIVER_ID)
.data(createApplicationSubmissionData(applicationPackageInstance1, 1000)),
- "{\"message\":\"Application package version: 1.0.1-commit1, source revision of repository 'repository1', branch 'master' with commit 'commit1', by a@b, built against 6.1 at 1970-01-01T00:00:01Z\"}");
+ "{\"message\":\"application build 1, source revision of repository 'repository1', branch 'master' with commit 'commit1', by a@b, built against 6.1 at 1970-01-01T00:00:01Z\"}");
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/package", GET)
.properties(Map.of("build", "42"))
.userIdentity(HOSTED_VESPA_OPERATOR),
- "{\"error-code\":\"NOT_FOUND\",\"message\":\"No application package found for 'tenant1.application1' with build number 42\"}",
+ "{\"error-code\":\"NOT_FOUND\",\"message\":\"No build 42 found for tenant1.application1\"}",
404);
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/deployment", DELETE).userIdentity(USER_ID).oAuthCredentials(OKTA_CREDENTIALS),
"{\"message\":\"All deployments removed\"}");
@@ -1217,7 +1217,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/package", GET)
.properties(Map.of("build", "foobar"))
.userIdentity(HOSTED_VESPA_OPERATOR),
- "{\"error-code\":\"BAD_REQUEST\",\"message\":\"Invalid build number: For input string: \\\"foobar\\\"\"}",
+ "{\"error-code\":\"BAD_REQUEST\",\"message\":\"invalid value for request parameter 'build': For input string: \\\"foobar\\\"\"}",
400);
// POST (deploy) an application to legacy deploy path
@@ -1419,7 +1419,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/submit/", POST)
.data(createApplicationSubmissionData(applicationPackage, 123))
.screwdriverIdentity(screwdriverId),
- "{\"message\":\"Application package version: 1.0.1-commit1, source revision of repository 'repository1', branch 'master' with commit 'commit1', by a@b, built against 6.1 at 1970-01-01T00:00:01Z\"}");
+ "{\"message\":\"application build 1, source revision of repository 'repository1', branch 'master' with commit 'commit1', by a@b, built against 6.1 at 1970-01-01T00:00:01Z\"}");
}
@Test
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java
index b7dc3bcc499..ee91787a36e 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java
@@ -5,10 +5,9 @@ import com.yahoo.component.Version;
import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.container.jdisc.HttpResponse;
import com.yahoo.slime.SlimeUtils;
-import com.yahoo.test.json.JsonTestHelper;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServerException;
-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.RevisionId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.TestReport;
import com.yahoo.vespa.hosted.controller.application.pkg.ApplicationPackage;
import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder;
@@ -17,7 +16,6 @@ import org.junit.Test;
import java.io.ByteArrayOutputStream;
import java.net.URI;
-import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -67,14 +65,14 @@ public class JobControllerApiHandlerHelperTest {
// Revision 1 gets deployed everywhere.
app.submit(applicationPackage).deploy();
- ApplicationVersion revision1 = app.lastSubmission().get();
+ RevisionId revision1 = app.lastSubmission().get();
assertEquals(1000, tester.application().projectId().getAsLong());
// System test includes test report
assertResponse(JobControllerApiHandlerHelper.runDetailsResponse(tester.jobs(), tester.jobs().last(app.instanceId(), systemTest).get().id(), "0"), "system-test-log.json");
tester.clock().advance(Duration.ofMillis(1000));
// Revision 2 gets deployed everywhere except in us-east-3.
- ApplicationVersion revision2 = app.submit(applicationPackage).lastSubmission().get();
+ RevisionId revision2 = app.submit(applicationPackage).lastSubmission().get();
app.runJob(systemTest);
app.runJob(stagingTest);
app.runJob(productionUsCentral1);
@@ -91,9 +89,9 @@ public class JobControllerApiHandlerHelperTest {
tester.clock().advance(Duration.ofHours(4).plusSeconds(1));
tester.runner().run();
assertEquals(installationFailed, tester.jobs().last(app.instanceId(), productionUsWest1).get().status());
- assertEquals(revision2, app.deployment(productionUsCentral1.zone(tester.controller().system())).applicationVersion());
- assertEquals(revision1, app.deployment(productionUsEast3.zone(tester.controller().system())).applicationVersion());
- assertEquals(revision2, app.deployment(productionUsWest1.zone(tester.controller().system())).applicationVersion());
+ assertEquals(revision2, app.deployment(productionUsCentral1.zone(tester.controller().system())).revision());
+ assertEquals(revision1, app.deployment(productionUsEast3.zone(tester.controller().system())).revision());
+ assertEquals(revision2, app.deployment(productionUsWest1.zone(tester.controller().system())).revision());
tester.clock().advance(Duration.ofMillis(1000));
@@ -133,14 +131,14 @@ public class JobControllerApiHandlerHelperTest {
// Only us-east-3 is verified, on revision1.
// staging-test has 5 runs: one success without sources on revision1, one success from revision1 to revision2,
// one success from revision2 to revision3 and two failures from revision1 to revision3.
- assertResponse(JobControllerApiHandlerHelper.runResponse(tester.jobs().runs(app.instanceId(), stagingTest), Optional.empty(), URI.create("https://some.url:43/root")), "staging-runs.json");
+ assertResponse(JobControllerApiHandlerHelper.runResponse(app.application(), tester.jobs().runs(app.instanceId(), stagingTest), Optional.empty(), URI.create("https://some.url:43/root")), "staging-runs.json");
assertResponse(JobControllerApiHandlerHelper.runDetailsResponse(tester.jobs(), tester.jobs().last(app.instanceId(), stagingTest).get().id(), "0"), "staging-test-log.json");
assertResponse(JobControllerApiHandlerHelper.runDetailsResponse(tester.jobs(), tester.jobs().last(app.instanceId(), productionUsEast3).get().id(), "0"), "us-east-3-log-without-first.json");
assertResponse(JobControllerApiHandlerHelper.jobTypeResponse(tester.controller(), app.instanceId(), URI.create("https://some.url:43/root/")), "overview.json");
var userApp = tester.newDeploymentContext(app.instanceId().tenant().value(), app.instanceId().application().value(), "user");
userApp.runJob(devAwsUsEast2a, applicationPackage);
- assertResponse(JobControllerApiHandlerHelper.runResponse(tester.jobs().runs(userApp.instanceId(), devAwsUsEast2a), Optional.empty(), URI.create("https://some.url:43/root")), "dev-aws-us-east-2a-runs.json");
+ assertResponse(JobControllerApiHandlerHelper.runResponse(app.application(), tester.jobs().runs(userApp.instanceId(), devAwsUsEast2a), Optional.empty(), URI.create("https://some.url:43/root")), "dev-aws-us-east-2a-runs.json");
assertResponse(JobControllerApiHandlerHelper.jobTypeResponse(tester.controller(), userApp.instanceId(), URI.create("https://some.url:43/root/")), "overview-user-instance.json");
assertResponse(JobControllerApiHandlerHelper.overviewResponse(tester.controller(), app.application().id(), URI.create("https://some.url:43/root/")), "deployment-overview-2.json");
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-cloud.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-cloud.json
index 7b8ddf3b90d..80e04d58614 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-cloud.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-cloud.json
@@ -19,6 +19,7 @@
"yamasUrl": "http://monitoring-system.test/?environment=prod&region=aws-us-east-1c&application=scoober.albums",
"version": "7.164.0",
"revision": "1.0.1-commit1",
+ "build": 1,
"deployTimeEpochMs": 1600000000000,
"screwdriverId": "1000",
"applicationVersion": {
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-with-routing-policy.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-with-routing-policy.json
index 86571f3bf9a..7244cf1493a 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-with-routing-policy.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-with-routing-policy.json
@@ -19,6 +19,7 @@
"yamasUrl": "http://monitoring-system.test/?environment=prod&region=us-west-1&application=tenant1.application1.instance1",
"version": "6.1.0",
"revision": "1.0.1-commit1",
+ "build": 1,
"deployTimeEpochMs": 1600000000000,
"screwdriverId": "1000",
"applicationVersion": {
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-without-shared-endpoints.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-without-shared-endpoints.json
index 86571f3bf9a..7244cf1493a 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-without-shared-endpoints.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-without-shared-endpoints.json
@@ -19,6 +19,7 @@
"yamasUrl": "http://monitoring-system.test/?environment=prod&region=us-west-1&application=tenant1.application1.instance1",
"version": "6.1.0",
"revision": "1.0.1-commit1",
+ "build": 1,
"deployTimeEpochMs": 1600000000000,
"screwdriverId": "1000",
"applicationVersion": {
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment.json
index 6965b246176..1448b79385b 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment.json
@@ -35,6 +35,7 @@
"yamasUrl": "http://monitoring-system.test/?environment=prod&region=us-central-1&application=tenant1.application1.instance1",
"version": "6.1.0",
"revision": "1.0.1-commit1",
+ "build": 1,
"deployTimeEpochMs": 1600000000000,
"screwdriverId": "123",
"endpointStatus": [
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-east-1-log-first-part.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-east-1-log-first-part.json
index bfaa4d5c813..2e9618c890d 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-east-1-log-first-part.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-east-1-log-first-part.json
@@ -6,7 +6,7 @@
{
"at": 0,
"type": "info",
- "message": "Deploying platform version 6.1 and application version 1.0.1 ..."
+ "message": "Deploying platform version 6.1 and application dev build 1 for devUsEast1 of default ..."
},
{
"at": 0,
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/instance1-recursive.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/instance1-recursive.json
index bb8b9ba9a02..4bd328f605f 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/instance1-recursive.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/instance1-recursive.json
@@ -62,6 +62,7 @@
"yamasUrl": "http://monitoring-system.test/?environment=dev&region=us-east-1&application=tenant1.application1.instance1",
"version": "6.1.0",
"revision": "1.0.1",
+ "build": 1,
"deployTimeEpochMs": 1600000000000,
"screwdriverId": "123",
"status": "complete",
@@ -121,6 +122,7 @@
"yamasUrl": "http://monitoring-system.test/?environment=prod&region=us-central-1&application=tenant1.application1.instance1",
"version": "6.1.0",
"revision": "1.0.1-commit1",
+ "build": 1,
"deployTimeEpochMs": 1600000000000,
"screwdriverId": "123",
"endpointStatus": [
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-root.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-root.json
index 495958cab53..bfbeda9233d 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-root.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-root.json
@@ -69,6 +69,7 @@
"yamasUrl": "http://monitoring-system.test/?environment=dev&region=us-east-1&application=tenant1.application1.instance1",
"version": "6.1.0",
"revision": "1.0.1",
+ "build": 1,
"deployTimeEpochMs": 1600000000000,
"screwdriverId": "123",
"status": "complete",
@@ -128,6 +129,7 @@
"yamasUrl": "http://monitoring-system.test/?environment=prod&region=us-central-1&application=tenant1.application1.instance1",
"version": "6.1.0",
"revision": "1.0.1-commit1",
+ "build": 1,
"deployTimeEpochMs": 1600000000000,
"screwdriverId": "123",
"endpointStatus": [
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/staging-test-log.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/staging-test-log.json
index 7c1f7223e9e..ba65b962a73 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/staging-test-log.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/staging-test-log.json
@@ -80,7 +80,7 @@
{
"at": 14503000,
"type": "info",
- "message": "Deploying platform version 6.1 and application version 1.0.1-commit1 ..."
+ "message": "Deploying platform version 6.1 and application build 1 ..."
},
{
"at": 14503000,
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/system-test-details.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/system-test-details.json
index 83a09e8a3f3..3b505bc11fd 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/system-test-details.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/system-test-details.json
@@ -100,7 +100,7 @@
{
"at": 1600000000000,
"type": "info",
- "message": "Deploying platform version 6.1 and application version 1.0.1-commit1 ..."
+ "message": "Deploying platform version 6.1 and application build 1 ..."
},
{
"at": 1600000000000,
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/system-test-log.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/system-test-log.json
index bfb5d8e6cbc..e31058d349b 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/system-test-log.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/system-test-log.json
@@ -95,7 +95,7 @@
{
"at": 0,
"type": "info",
- "message": "Deploying platform version 6.1 and application version 1.0.1-commit1 ..."
+ "message": "Deploying platform version 6.1 and application build 1 ..."
},
{
"at": 0,
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant1-recursive.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant1-recursive.json
index 7503cb68337..054aaec0fcd 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant1-recursive.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant1-recursive.json
@@ -68,6 +68,7 @@
"yamasUrl": "http://monitoring-system.test/?environment=dev&region=us-east-1&application=tenant1.application1.instance1",
"version": "6.1.0",
"revision": "1.0.1",
+ "build": 1,
"deployTimeEpochMs": 1600000000000,
"screwdriverId": "123",
"status": "complete",
@@ -127,6 +128,7 @@
"yamasUrl": "http://monitoring-system.test/?environment=prod&region=us-central-1&application=tenant1.application1.instance1",
"version": "6.1.0",
"revision": "1.0.1-commit1",
+ "build": 1,
"deployTimeEpochMs": 1600000000000,
"screwdriverId": "123",
"endpointStatus": [
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilterTest.java
index eab3a37a9c3..be3a50c38b0 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilterTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilterTest.java
@@ -66,8 +66,7 @@ public class ControllerAuthorizationFilterTest {
@Test
public void unprivilegedInPublic() {
- ControllerTester tester = new ControllerTester();
- tester.zoneRegistry().setSystemName(SystemName.Public);
+ ControllerTester tester = new ControllerTester(SystemName.Public);
SecurityContext securityContext = new SecurityContext(() -> "user", Set.of(Role.everyone()));
ControllerAuthorizationFilter filter = createFilter(tester);
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/os/OsApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/os/OsApiTest.java
index cf4deb7b4bf..5c210616cb1 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/os/OsApiTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/os/OsApiTest.java
@@ -47,13 +47,17 @@ public class OsApiTest extends ControllerContainerTest {
private ContainerTester tester;
private List<OsUpgrader> osUpgraders;
+ @Override
+ protected SystemName system() {
+ return SystemName.cd;
+ }
+
@Before
public void before() {
tester = new ContainerTester(container, responses);
tester.serviceRegistry().clock().setInstant(Instant.ofEpochMilli(1234));
addUserToHostedOperatorRole(operator);
- zoneRegistryMock().setSystemName(SystemName.cd)
- .setZones(zone1, zone2, zone3)
+ zoneRegistryMock().setZones(zone1, zone2, zone3)
.reprovisionToUpgradeOsIn(zone3)
.setOsUpgradePolicy(cloud1, UpgradePolicy.builder().upgrade(zone1).upgrade(zone2).build())
.setOsUpgradePolicy(cloud2, UpgradePolicy.builder().upgrade(zone3).build());
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/RoutingPoliciesTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/RoutingPoliciesTest.java
index 83b6f05c0b0..fca3dde8f7d 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/RoutingPoliciesTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/RoutingPoliciesTest.java
@@ -322,7 +322,7 @@ public class RoutingPoliciesTest {
@Test
public void zone_routing_policies_without_dns_update() {
- var tester = new RoutingPoliciesTester(new DeploymentTester(), SystemName.main, false);
+ var tester = new RoutingPoliciesTester(new DeploymentTester(), false);
var context = tester.newDeploymentContext("tenant1", "app1", "default");
tester.provisionLoadBalancers(1, context.instanceId(), true, zone1, zone2);
context.submit(applicationPackage).deferLoadBalancerProvisioningIn(Environment.prod).deploy();
@@ -892,23 +892,21 @@ public class RoutingPoliciesTest {
}
public RoutingPoliciesTester(SystemName system) {
- this(new DeploymentTester(system.isPublic()
- ? new ControllerTester(new RotationsConfig.Builder().build(), system)
- : new ControllerTester()),
- system,
+ this(new DeploymentTester(system.isPublic() ? new ControllerTester(new RotationsConfig.Builder().build(), system)
+ : new ControllerTester(system)),
true);
}
- public RoutingPoliciesTester(DeploymentTester tester, SystemName system, boolean exclusiveRouting) {
+ public RoutingPoliciesTester(DeploymentTester tester, boolean exclusiveRouting) {
this.tester = tester;
List<ZoneId> zones;
- if (system.isPublic()) {
+ if (tester.controller().system().isPublic()) {
zones = publicZones();
} else {
zones = new ArrayList<>(tester.controllerTester().zoneRegistry().zones().all().ids()); // Default zones
zones.add(zone4); // Missing from default ZoneRegistryMock zones
}
- tester.controllerTester().setZones(zones, system);
+ tester.controllerTester().setZones(zones);
if (exclusiveRouting) {
tester.controllerTester().setRoutingMethod(zones, RoutingMethod.exclusive);
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/rotation/RotationRepositoryTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/rotation/RotationRepositoryTest.java
index d7847da2404..02154470de2 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/rotation/RotationRepositoryTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/rotation/RotationRepositoryTest.java
@@ -149,10 +149,10 @@ public class RotationRepositoryTest {
ZoneApiMock.fromId("staging.cd-us-west-1"),
ZoneApiMock.fromId("prod.cd-us-east-1"),
ZoneApiMock.fromId("prod.cd-us-west-1"));
+ DeploymentTester tester = new DeploymentTester(new ControllerTester(rotationsConfig, SystemName.cd));
tester.controllerTester().zoneRegistry()
.setZones(zones)
- .setRoutingMethod(zones, RoutingMethod.sharedLayer4)
- .setSystemName(SystemName.cd);
+ .setRoutingMethod(zones, RoutingMethod.sharedLayer4);
tester.configServer().bootstrap(tester.controllerTester().zoneRegistry().zones().all().ids(), SystemApplication.notController());
var application2 = tester.newDeploymentContext("tenant2", "app2", "default");
application2.submit(applicationPackage).deploy();
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java
index 9902f9bd07d..297410112d5 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java
@@ -5,6 +5,7 @@ import com.yahoo.component.Version;
import com.yahoo.component.Vtag;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.HostName;
+import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.zone.ZoneApi;
import com.yahoo.vespa.hosted.controller.Controller;
import com.yahoo.vespa.hosted.controller.ControllerTester;
@@ -89,7 +90,8 @@ public class VersionStatusTest {
HostName controller3 = HostName.of("controller-3");
MockCuratorDb db = new MockCuratorDb(Stream.of(controller1, controller2, controller3)
.map(hostName -> hostName.value() + ":2222")
- .collect(Collectors.joining(",")));
+ .collect(Collectors.joining(",")),
+ SystemName.main);
ControllerTester tester = new ControllerTester(db);
writeControllerVersion(controller1, Version.fromString("6.2"), db);
@@ -498,7 +500,8 @@ public class VersionStatusTest {
HostName controller3 = HostName.of("controller-3");
MockCuratorDb db = new MockCuratorDb(Stream.of(controller1, controller2, controller3)
.map(hostName -> hostName.value() + ":2222")
- .collect(Collectors.joining(",")));
+ .collect(Collectors.joining(",")),
+ SystemName.main);
DeploymentTester tester = new DeploymentTester(new ControllerTester(db));
// Commit details are set for initial version