summaryrefslogtreecommitdiffstats
path: root/controller-server
diff options
context:
space:
mode:
authorMorten Tokle <morten.tokle@gmail.com>2018-01-31 14:33:38 +0100
committerGitHub <noreply@github.com>2018-01-31 14:33:38 +0100
commit793423e64ee415f1803a0c730f9b245397dd6a0d (patch)
tree7a14f5baa95a2a0c4375a33dfa7c859387117de5 /controller-server
parent2c25a02adbe644b3f50dc44252c6b61974d0c8d6 (diff)
Revert "Application version migration"
Diffstat (limited to 'controller-server')
-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.java75
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedApplication.java24
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationVersion.java61
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/DeploymentJobs.java13
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/JobList.java2
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/JobStatus.java22
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java25
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializer.java33
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java7
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ArtifactRepositoryMock.java38
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java216
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java8
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java26
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/complete-application.json514
16 files changed, 226 insertions, 857 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Application.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Application.java
index f26502e4630..d5ce613b98d 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,9 +7,9 @@ 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.Environment;
+import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.api.integration.MetricsService.ApplicationMetrics;
import com.yahoo.vespa.hosted.controller.api.integration.organization.IssueId;
-import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.application.ApplicationRotation;
import com.yahoo.vespa.hosted.controller.application.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.application.Change;
@@ -149,16 +149,6 @@ public class Application {
.min(Comparator.naturalOrder());
}
- /**
- * Returns the oldest application version this has deployed in a permanent zone (not test or staging),
- * or empty version if it is not deployed anywhere
- */
- public Optional<ApplicationVersion> oldestDeployedApplicationVersion() {
- return productionDeployments().values().stream()
- .map(Deployment::applicationVersion)
- .min(Comparator.naturalOrder());
- }
-
/** Returns the version a new deployment to this zone should use for this application */
public Version deployVersionIn(ZoneId zone, Controller controller) {
return change.platform().orElse(versionIn(zone, controller));
@@ -167,18 +157,19 @@ public class Application {
/** Returns the current version this application has, or if none; should use, in the given zone */
public Version versionIn(ZoneId zone, Controller controller) {
return Optional.ofNullable(deployments().get(zone)).map(Deployment::version) // Already deployed in this zone: Use that version
- .orElse(oldestDeployedVersion().orElse(controller.systemVersion()));
+ .orElse(oldestDeployedVersion().orElse(controller.systemVersion()));
}
/** Returns the application version a deployment to this zone should use, or empty if we don't know */
public Optional<ApplicationVersion> deployApplicationVersionIn(ZoneId zone) {
if (change().application().isPresent()) {
ApplicationVersion version = change().application().get();
- if (version.isUnknown())
+ if (version == ApplicationVersion.unknown)
return Optional.empty();
else
return Optional.of(version);
}
+
return applicationVersionIn(zone);
}
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 407f5b65e81..83c3d6a5d11 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
@@ -297,51 +297,41 @@ public class ApplicationController {
version = application.deployVersionIn(zone, controller);
}
- // Determine application package to use
- ApplicationVersion applicationVersion;
- ApplicationPackage applicationPackage;
- Optional<DeploymentJobs.JobType> job = DeploymentJobs.JobType.from(controller.system(), zone);
+ Optional<DeploymentJobs.JobType> jobType = DeploymentJobs.JobType.from(controller.system(), zone);
+ if (!jobType.isPresent() && !applicationPackageFromDeployer.isPresent()) {
+ throw new IllegalArgumentException("Unable to determine job type from zone '" + zone +
+ "' and no application package was given");
+ }
- // TODO: Simplify after new application version is always available
- if (canDownloadReportedApplicationVersion(application) && !canDeployDirectlyTo(zone, options)) {
- if (!job.isPresent()) {
- throw new IllegalArgumentException("Cannot determine job for zone " + zone);
- }
- applicationVersion = application.deployApplicationVersion(job.get(), controller,
- options.deployCurrentVersion)
- .orElseThrow(() -> new IllegalArgumentException("Cannot determine application version for " + applicationId));
- if (canDownloadArtifact(applicationVersion)) {
- applicationPackage = new ApplicationPackage(
- artifactRepository.getApplicationPackage(applicationId, applicationVersion.id())
- );
- } else {
- applicationPackage = applicationPackageFromDeployer.orElseThrow(
- () -> new IllegalArgumentException("Application package with version " +
- applicationVersion.id() + " cannot be downloaded, and " +
- "no package was given by deployer"));
- }
- } else { // ..otherwise we use the package sent by the deployer and deduce version from the package
- // TODO: Only allow this for environments that are allowed to deploy directly
- applicationPackage = applicationPackageFromDeployer.orElseThrow(
- () -> new IllegalArgumentException("Application package must be given as new application " +
- "version is not known for " + applicationId)
+ // Determine which application package to use
+ ApplicationPackage applicationPackage;
+ ApplicationVersion applicationVersion;
+ if (applicationPackageFromDeployer.isPresent()) {
+ applicationVersion = toApplicationPackageRevision(applicationPackageFromDeployer.get(),
+ options.screwdriverBuildJob);
+ applicationPackage = applicationPackageFromDeployer.get();
+ } else {
+ applicationVersion = application.deployApplicationVersion(jobType.get(), controller)
+ .orElseThrow(() -> new IllegalArgumentException("Cannot determine application version to use in " + zone));
+ applicationPackage = new ApplicationPackage(artifactRepository.getApplicationPackage(
+ applicationId, applicationVersion.id())
);
- applicationVersion = toApplicationPackageRevision(applicationPackage, options.screwdriverBuildJob);
}
+
validate(applicationPackage.deploymentSpec());
- // TODO: Remove after introducing new application version
- if (!options.deployCurrentVersion && !canDownloadReportedApplicationVersion(application)) {
+ // TODO: Remove after introducing new application version number
+ if ( ! options.deployCurrentVersion && applicationPackageFromDeployer.isPresent()) {
if (application.change().application().isPresent()) {
- application = application.withChange(application.change().with(applicationVersion));
+ application = application.withDeploying(application.change().with(applicationVersion));
}
- if (!canDeployDirectlyTo(zone, options) && job.isPresent()) {
+ if (!canDeployDirectlyTo(zone, options) && jobType.isPresent()) {
// Update with (potentially) missing information about what we triggered:
// * When someone else triggered the job, we need to store a stand-in triggering event.
// * When this is the system test job, we need to record the new application version,
// for future use.
- JobStatus.JobRun triggering = getOrCreateTriggering(application, version, job.get());
- application = application.withJobTriggering(job.get(),
+ JobStatus.JobRun triggering = getOrCreateTriggering(application, version, jobType.get());
+ application = application.withJobTriggering(jobType.get(),
application.change(),
triggering.at(),
version,
@@ -426,8 +416,7 @@ public class ApplicationController {
Log logEntry = new Log();
logEntry.level = "WARNING";
logEntry.time = clock.instant().toEpochMilli();
- logEntry.message = "Ignoring deployment of " + require(applicationId) + " to " + zone +
- " as a deployment is not currently expected";
+ logEntry.message = "Ignoring deployment of " + get(applicationId) + " to " + zone + " as a deployment is not currently expected";
PrepareResponse prepareResponse = new PrepareResponse();
prepareResponse.log = Collections.singletonList(logEntry);
prepareResponse.configChangeActions = new ConfigChangeActions(Collections.emptyList(), Collections.emptyList());
@@ -709,20 +698,6 @@ public class ApplicationController {
zone.environment().isManuallyDeployed();
}
- /** Returns whether artifact for given version number is available in artifact repository */
- private static boolean canDownloadArtifact(ApplicationVersion applicationVersion) {
- return applicationVersion.buildNumber().isPresent() && applicationVersion.source().isPresent();
- }
-
- /** Returns whether component has reported a version number that is availabe in artifact repository */
- private static boolean canDownloadReportedApplicationVersion(Application application) {
- return Optional.ofNullable(application.deploymentJobs().jobStatus().get(DeploymentJobs.JobType.component))
- .flatMap(JobStatus::lastSuccess)
- .map(JobStatus.JobRun::applicationVersion)
- .filter(ApplicationController::canDownloadArtifact)
- .isPresent();
- }
-
/** Verify that each of the production zones listed in the deployment spec exist in this system. */
private void validate(DeploymentSpec deploymentSpec) {
deploymentSpec.zones().stream()
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedApplication.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedApplication.java
index 4b6213733a0..e744df0da68 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedApplication.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedApplication.java
@@ -60,11 +60,8 @@ public class LockedApplication extends Application {
return new LockedApplication(new Builder(this).with(deploymentJobs().with(issueId)));
}
- public LockedApplication withJobCompletion(DeploymentJobs.JobReport report, ApplicationVersion applicationVersion,
- Instant notificationTime, Controller controller) {
- return new LockedApplication(new Builder(this).with(deploymentJobs().withCompletion(
- report, applicationVersion, notificationTime, controller))
- );
+ public LockedApplication withJobCompletion(DeploymentJobs.JobReport report, Instant notificationTime, Controller controller) {
+ return new LockedApplication(new Builder(this).with(deploymentJobs().withCompletion(report, notificationTime, controller)));
}
public LockedApplication withJobTriggering(JobType type, Change change, Instant triggerTime,
@@ -122,8 +119,8 @@ public class LockedApplication extends Application {
return new LockedApplication(new Builder(this).with(validationOverrides));
}
- public LockedApplication withChange(Change change) {
- return new LockedApplication(new Builder(this).withChange(change));
+ public LockedApplication withDeploying(Change deploying) {
+ return new LockedApplication(new Builder(this).withDeploying(deploying));
}
public LockedApplication withOutstandingChange(boolean outstandingChange) {
@@ -149,17 +146,6 @@ public class LockedApplication extends Application {
}
public Optional<ApplicationVersion> deployApplicationVersion(DeploymentJobs.JobType jobType, Controller controller) {
- return deployApplicationVersion(jobType, controller, false);
- }
-
- public Optional<ApplicationVersion> deployApplicationVersion(DeploymentJobs.JobType jobType, Controller controller,
- boolean currentVersion) {
- if (currentVersion) {
- Optional<ApplicationVersion> version = oldestDeployedApplicationVersion();
- if (version.isPresent()) {
- return version;
- }
- }
return jobType == JobType.component
? Optional.empty()
: deployApplicationVersionIn(jobType.zone(controller.system()).get());
@@ -219,7 +205,7 @@ public class LockedApplication extends Application {
return this;
}
- private Builder withChange(Change deploying) {
+ private Builder withDeploying(Change deploying) {
this.deploying = deploying;
return this;
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationVersion.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationVersion.java
index 31ee5fa6d44..304d82b2bec 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationVersion.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationVersion.java
@@ -11,19 +11,18 @@ import java.util.Optional;
* @author bratseth
* @author mpolden
*/
-public class ApplicationVersion implements Comparable<ApplicationVersion> {
+public class ApplicationVersion {
- /**
- * Used in cases where application version cannot be determined, such as manual deployments (e.g. in dev
- * environment)
- */
+ // TODO: Remove the need for this
public static final ApplicationVersion unknown = new ApplicationVersion();
- // This never changes and is only used to create a valid semantic version number, as required by application bundles
+ // Never changes. Only used to create a valid version number for the bundle
private static final String majorVersion = "1.0";
- // TODO: Remove after 2018-03-01
+ // TODO: Remove after introducing new application version
private final Optional<String> applicationPackageHash;
+
+ // TODO: Make mandatory
private final Optional<SourceRevision> source;
private final Optional<Long> buildNumber;
@@ -38,11 +37,11 @@ public class ApplicationVersion implements Comparable<ApplicationVersion> {
Objects.requireNonNull(applicationPackageHash, "applicationPackageHash cannot be null");
Objects.requireNonNull(source, "source cannot be null");
Objects.requireNonNull(buildNumber, "buildNumber cannot be null");
- if (!applicationPackageHash.isPresent() && source.isPresent() != buildNumber.isPresent()) {
- throw new IllegalArgumentException("both buildNumber and source must be set together");
+ if (buildNumber.isPresent() && !source.isPresent()) {
+ throw new IllegalArgumentException("both buildNumber and source must be set if buildNumber is set");
}
- if (buildNumber.isPresent() && buildNumber.get() <= 0) {
- throw new IllegalArgumentException("buildNumber must be > 0");
+ if ( ! buildNumber.isPresent() && ! applicationPackageHash.isPresent()) {
+ throw new IllegalArgumentException("applicationPackageHash must be given if buildNumber is unset");
}
this.applicationPackageHash = applicationPackageHash;
this.source = source;
@@ -69,14 +68,9 @@ public class ApplicationVersion implements Comparable<ApplicationVersion> {
if (applicationPackageHash.isPresent()) {
return applicationPackageHash.get();
}
- return source.map(sourceRevision -> String.format("%s.%d-%s", majorVersion, buildNumber.get(),
- abbreviateCommit(source.get().commit())))
- .orElse("unknown");
+ return String.format("%s.%d-%s", majorVersion, buildNumber.get(), abbreviateCommit(source.get().commit()));
}
- /** Returns the application package hash, if known */
- public Optional<String> applicationPackageHash() { return applicationPackageHash; }
-
/**
* Returns information about the source of this revision, or empty if the source is not know/defined
* (which is the case for command-line deployment from developers, but never for deployment jobs)
@@ -86,29 +80,23 @@ public class ApplicationVersion implements Comparable<ApplicationVersion> {
/** Returns the build number that built this version */
public Optional<Long> buildNumber() { return buildNumber; }
- /** Returns whether this is unknown */
- public boolean isUnknown() {
- return this.equals(unknown);
- }
-
@Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- ApplicationVersion that = (ApplicationVersion) o;
- return Objects.equals(applicationPackageHash, that.applicationPackageHash) &&
- Objects.equals(source, that.source) &&
- Objects.equals(buildNumber, that.buildNumber);
- }
+ public int hashCode() { return applicationPackageHash.hashCode(); }
@Override
- public int hashCode() {
- return Objects.hash(applicationPackageHash, source, buildNumber);
+ public boolean equals(Object other) {
+ if (this == other) return true;
+ if ( ! (other instanceof ApplicationVersion)) return false;
+ return this.applicationPackageHash.equals(((ApplicationVersion)other).applicationPackageHash);
}
@Override
public String toString() {
- return "Application package version: " + id() + source.map(s -> ", " + s.toString()).orElse("");
+ if (buildNumber.isPresent()) {
+ return "Application package version: " + abbreviateCommit(source.get().commit()) + "-" + buildNumber.get();
+ }
+ return "Application package revision '" + applicationPackageHash + "'" +
+ (source.isPresent() ? " with " + source.get() : "");
}
/** Abbreviate given commit hash to 9 characters */
@@ -116,11 +104,4 @@ public class ApplicationVersion implements Comparable<ApplicationVersion> {
return hash.length() <= 9 ? hash : hash.substring(0, 9);
}
- @Override
- public int compareTo(ApplicationVersion o) {
- if (!buildNumber().isPresent() || !o.buildNumber().isPresent()) {
- return 0; // No sorting for application package hash
- }
- return buildNumber().get().compareTo(o.buildNumber().get());
- }
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/DeploymentJobs.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/DeploymentJobs.java
index 932777e690d..bb7b39eed0f 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/DeploymentJobs.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/DeploymentJobs.java
@@ -55,13 +55,11 @@ public class DeploymentJobs {
}
/** Return a new instance with the given completion */
- public DeploymentJobs withCompletion(JobReport report, ApplicationVersion applicationVersion,
- Instant notificationTime, Controller controller) {
+ public DeploymentJobs withCompletion(JobReport report, Instant notificationTime, Controller controller) {
Map<JobType, JobStatus> status = new LinkedHashMap<>(this.status);
status.compute(report.jobType(), (type, job) -> {
if (job == null) job = JobStatus.initial(report.jobType());
- return job.withCompletion(report.buildNumber(), applicationVersion, report.jobError(), notificationTime,
- controller);
+ return job.withCompletion(report.buildNumber(), report.jobError(), notificationTime, controller);
});
return new DeploymentJobs(Optional.of(report.projectId()), status, issueId);
}
@@ -256,16 +254,11 @@ public class DeploymentJobs {
Objects.requireNonNull(sourceRevision, "sourceRevision cannot be null");
Objects.requireNonNull(jobError, "jobError cannot be null");
- if (jobType == JobType.component && !sourceRevision.isPresent()) {
- // TODO: Throw after 2018-03-01
- //throw new IllegalArgumentException("sourceRevision is required for job " + jobType);
- }
-
this.applicationId = applicationId;
this.projectId = projectId;
this.buildNumber = buildNumber;
this.jobType = jobType;
- this.sourceRevision = sourceRevision;
+ this.sourceRevision = sourceRevision; // TODO: Require non-empty source revision if jobType == component
this.jobError = jobError;
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/JobList.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/JobList.java
index fb9ab8735d8..41060a7af4c 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/JobList.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/JobList.java
@@ -172,7 +172,7 @@ public class JobList {
private static boolean failingApplicationChange(JobStatus job) {
if ( job.isSuccess()) return false;
if ( ! job.lastSuccess().isPresent()) return true; // An application which never succeeded is surely bad.
- if ( job.lastSuccess().get().applicationVersion().isUnknown()) return true; // Indicates the component job, which is always an application change.
+ if ( job.lastSuccess().get().applicationVersion() == ApplicationVersion.unknown) return true; // Indicates the component job, which is always an application change.
if ( ! job.firstFailing().get().version().equals(job.lastSuccess().get().version())) return false; // Version change may be to blame.
return ! job.firstFailing().get().applicationVersion().equals(job.lastSuccess().get().applicationVersion()); // Return whether there is an application change.
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/JobStatus.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/JobStatus.java
index e963fde8f94..e165d3c9fe5 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/JobStatus.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/JobStatus.java
@@ -57,31 +57,27 @@ public class JobStatus {
public JobStatus withTriggering(Version version, ApplicationVersion applicationVersion,
boolean upgrade, String reason, Instant triggerTime) {
- return new JobStatus(type, jobError, Optional.of(new JobRun(-1, version, applicationVersion, upgrade,
- reason, triggerTime)),
+ return new JobStatus(type, jobError, Optional.of(new JobRun(-1, version, applicationVersion, upgrade, reason, triggerTime)),
lastCompleted, firstFailing, lastSuccess);
}
- public JobStatus withCompletion(long runId, Optional<DeploymentJobs.JobError> jobError, Instant completionTime,
- Controller controller) {
- return withCompletion(runId, ApplicationVersion.unknown, jobError, completionTime, controller);
- }
-
- public JobStatus withCompletion(long runId, ApplicationVersion applicationVersion,
- Optional<DeploymentJobs.JobError> jobError, Instant completionTime,
- Controller controller) {
+ public JobStatus withCompletion(long runId, Optional<DeploymentJobs.JobError> jobError, Instant completionTime, Controller controller) {
Version version;
+ ApplicationVersion applicationVersion;
boolean upgrade;
String reason;
if (type == DeploymentJobs.JobType.component) { // not triggered by us
version = controller.systemVersion();
+ applicationVersion = ApplicationVersion.unknown;
upgrade = false;
reason = "Application commit";
- } else if (! lastTriggered.isPresent()) {
+ }
+ else if (! lastTriggered.isPresent()) {
throw new IllegalStateException("Got notified about completion of " + this +
", but that has neither been triggered nor deployed");
- } else {
+ }
+ else {
version = lastTriggered.get().version();
applicationVersion = lastTriggered.get().applicationVersion();
upgrade = lastTriggered.get().upgrade();
@@ -201,7 +197,7 @@ public class JobStatus {
/** Returns the Vespa version used on this run */
public Version version() { return version; }
- /** Returns the application version used in this run */
+ /** Returns the application version used for this run, or empty when not known */
public ApplicationVersion applicationVersion() { return applicationVersion; }
/** Returns a human-readable reason for this particular job run */
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 6560423f3b9..1beab1307c1 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
@@ -78,8 +78,7 @@ public class DeploymentTrigger {
*/
public void triggerFromCompletion(JobReport report) {
applications().lockOrThrow(report.applicationId(), application -> {
- application = application.withJobCompletion(report, applicationVersionFrom(report), clock.instant(),
- controller);
+ application = application.withJobCompletion(report, clock.instant(), controller);
application = application.withProjectId(report.projectId());
// Handle successful starting and ending
@@ -90,9 +89,8 @@ public class DeploymentTrigger {
if ( ! ( application.change().platform().isPresent())) {
ApplicationVersion applicationVersion = ApplicationVersion.unknown;
if (report.sourceRevision().isPresent())
- applicationVersion = ApplicationVersion.from(report.sourceRevision().get(),
- report.buildNumber());
- application = application.withChange(Change.of(applicationVersion));
+ applicationVersion = ApplicationVersion.from(report.sourceRevision().get(), report.buildNumber());
+ application = application.withDeploying(Change.of(applicationVersion));
}
}
else { // postpone
@@ -102,7 +100,7 @@ public class DeploymentTrigger {
}
else if (deploymentComplete(application)) {
// change completed
- application = application.withChange(Change.empty());
+ application = application.withDeploying(Change.empty());
}
}
@@ -141,7 +139,7 @@ public class DeploymentTrigger {
}
if (change.application().isPresent()) {
// If we don't yet know the application version we are deploying, then we are not complete
- if (change.application().get().isUnknown()) return false;
+ if (change.application().get() == ApplicationVersion.unknown) return false;
if ( ! change.application().get().equals(deployment.applicationVersion())) return false;
}
}
@@ -262,7 +260,7 @@ public class DeploymentTrigger {
if (application.change().isPresent() && ! application.deploymentJobs().hasFailures())
throw new IllegalArgumentException("Could not start " + change + " on " + application + ": " +
application.change() + " is already in progress");
- application = application.withChange(change);
+ application = application.withDeploying(change);
if (change.application().isPresent())
application = application.withOutstandingChange(false);
application = trigger(JobType.systemTest, application, false, change.toString());
@@ -278,7 +276,7 @@ public class DeploymentTrigger {
public void cancelChange(ApplicationId applicationId) {
applications().lockOrThrow(applicationId, application -> {
buildSystem.removeJobs(application.id());
- applications().store(application.withChange(Change.empty()));
+ applications().store(application.withDeploying(Change.empty()));
});
}
@@ -357,17 +355,10 @@ public class DeploymentTrigger {
application.change(),
clock.instant(),
application.deployVersionFor(jobType, controller),
- application.deployApplicationVersion(jobType, controller)
- .orElse(ApplicationVersion.unknown),
+ application.deployApplicationVersion(jobType, controller).orElse(ApplicationVersion.unknown),
reason);
}
- /** Create application version from job report */
- private ApplicationVersion applicationVersionFrom(JobReport report) {
- return report.sourceRevision().map(sr -> ApplicationVersion.from(sr, report.buildNumber()))
- .orElse(ApplicationVersion.unknown);
- }
-
/** Returns true if the given proposed job triggering should be effected */
private boolean allowedTriggering(JobType jobType, LockedApplication application) {
// Note: We could make a more fine-grained and more correct determination about whether to block
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 4b7993b3b7d..652f95a2d13 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
@@ -6,6 +6,7 @@ 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.vespa.hosted.controller.api.integration.zone.ZoneId;
import com.yahoo.slime.ArrayTraverser;
import com.yahoo.slime.Cursor;
import com.yahoo.slime.Inspector;
@@ -14,7 +15,6 @@ import com.yahoo.vespa.config.SlimeUtils;
import com.yahoo.vespa.hosted.controller.Application;
import com.yahoo.vespa.hosted.controller.api.integration.MetricsService.ApplicationMetrics;
import com.yahoo.vespa.hosted.controller.api.integration.organization.IssueId;
-import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.application.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.application.Change;
import com.yahoo.vespa.hosted.controller.application.ClusterInfo;
@@ -61,7 +61,6 @@ public class ApplicationSerializer {
private final String environmentField = "environment";
private final String regionField = "region";
private final String deployTimeField = "deployTime";
- private final String applicationBuildNumberField = "applicationBuildNumber";
private final String applicationPackageRevisionField = "applicationPackageRevision";
private final String applicationPackageHashField = "applicationPackageHash";
private final String sourceRevisionField = "sourceRevision";
@@ -199,15 +198,9 @@ public class ApplicationSerializer {
}
private void toSlime(ApplicationVersion applicationVersion, Cursor object) {
- if (applicationVersion.buildNumber().isPresent() && applicationVersion.source().isPresent()) {
- object.setLong(applicationBuildNumberField, applicationVersion.buildNumber().get());
+ object.setString(applicationPackageHashField, applicationVersion.id());
+ if (applicationVersion.source().isPresent())
toSlime(applicationVersion.source().get(), object.setObject(sourceRevisionField));
- } else if (applicationVersion.applicationPackageHash().isPresent()) { // TODO: Remove after 2018-03-01
- object.setString(applicationPackageHashField, applicationVersion.applicationPackageHash().get());
- if (applicationVersion.source().isPresent()){
- toSlime(applicationVersion.source().get(), object.setObject(sourceRevisionField));
- }
- }
}
private void toSlime(SourceRevision sourceRevision, Cursor object) {
@@ -243,7 +236,7 @@ public class ApplicationSerializer {
Cursor object = parent.setObject(jobRunObjectName);
object.setLong(jobRunIdField, jobRun.get().id());
object.setString(versionField, jobRun.get().version().toString());
- if ( ! jobRun.get().applicationVersion().isUnknown())
+ if ( jobRun.get().applicationVersion() != ApplicationVersion.unknown)
toSlime(jobRun.get().applicationVersion(), object.setObject(revisionField));
object.setBool(upgradeField, jobRun.get().upgrade());
object.setString(reasonField, jobRun.get().reason());
@@ -256,7 +249,7 @@ public class ApplicationSerializer {
Cursor object = parentObject.setObject(deployingField);
if (deploying.platform().isPresent())
object.setString(versionField, deploying.platform().get().toString());
- if (deploying.application().isPresent() && !deploying.application().get().isUnknown())
+ if (deploying.application().isPresent() && deploying.application().get() != ApplicationVersion.unknown)
toSlime(deploying.application().get(), object);
}
@@ -349,17 +342,10 @@ public class ApplicationSerializer {
private ApplicationVersion applicationVersionFromSlime(Inspector object) {
if ( ! object.valid()) return ApplicationVersion.unknown;
- Optional<String> applicationPackageHash = optionalString(object.field(applicationPackageHashField));
- Optional<Long> applicationBuildNumber = optionalLong(object.field(applicationBuildNumberField));
+ String applicationPackageHash = object.field(applicationPackageHashField).asString();
Optional<SourceRevision> sourceRevision = sourceRevisionFromSlime(object.field(sourceRevisionField));
- if (applicationPackageHash.isPresent()) { // TODO: Remove after 2018-03-01
- return sourceRevision.map(sr -> ApplicationVersion.from(applicationPackageHash.get(), sr))
- .orElseGet(() -> ApplicationVersion.from(applicationPackageHash.get()));
- }
- if (!sourceRevision.isPresent() || !applicationBuildNumber.isPresent()) {
- return ApplicationVersion.unknown;
- }
- return ApplicationVersion.from(sourceRevision.get(), applicationBuildNumber.get());
+ return sourceRevision.isPresent() ? ApplicationVersion.from(applicationPackageHash, sourceRevision.get())
+ : ApplicationVersion.from(applicationPackageHash);
}
private Optional<SourceRevision> sourceRevisionFromSlime(Inspector object) {
@@ -383,8 +369,7 @@ public class ApplicationSerializer {
Change change = Change.empty();
if (versionFieldValue.valid())
change = Change.of(Version.fromString(versionFieldValue.asString()));
- if (object.field(applicationBuildNumberField).valid() ||
- object.field(applicationPackageHashField).valid()) // TODO: Remove after 2018-03-01
+ if (object.field(applicationPackageHashField).valid())
change = change.with(applicationVersionFromSlime(object));
if ( ! change.isPresent()) // A deploy object with no fields -> unknown application change
change = Change.of(ApplicationVersion.unknown);
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 77e0fb1ef05..9b2174b881d 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
@@ -478,10 +478,9 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
}
private void toSlime(ApplicationVersion applicationVersion, Cursor object) {
- if (!applicationVersion.isUnknown()) {
- object.setString("hash", applicationVersion.id());
+ object.setString("hash", applicationVersion.id());
+ if (applicationVersion.source().isPresent())
sourceRevisionToSlime(applicationVersion.source(), object.setObject("source"));
- }
}
private void sourceRevisionToSlime(Optional<SourceRevision> revision, Cursor object) {
@@ -971,7 +970,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
private void toSlime(JobStatus.JobRun jobRun, Cursor object) {
object.setLong("id", jobRun.id());
object.setString("version", jobRun.version().toFullString());
- if (!jobRun.applicationVersion().isUnknown())
+ if (jobRun.applicationVersion() != ApplicationVersion.unknown)
toSlime(jobRun.applicationVersion(), object.setObject("revision"));
object.setString("reason", jobRun.reason());
object.setLong("at", jobRun.at().toEpochMilli());
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ArtifactRepositoryMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ArtifactRepositoryMock.java
index cfe60cd3e96..efbc10e8deb 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ArtifactRepositoryMock.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ArtifactRepositoryMock.java
@@ -14,22 +14,11 @@ import java.util.Objects;
*/
public class ArtifactRepositoryMock implements ArtifactRepository {
- private final Map<Integer, Artifact> repository = new HashMap<>();
+ private final Map<Integer, byte[]> repository = new HashMap<>();
public ArtifactRepositoryMock put(ApplicationId applicationId, ApplicationPackage applicationPackage,
String applicationVersion) {
- repository.put(artifactHash(applicationId, applicationVersion),
- new Artifact(applicationPackage.zippedContent()));
- return this;
- }
-
- public int hits(ApplicationId applicationId, String applicationVersion) {
- Artifact artifact = repository.get(artifactHash(applicationId, applicationVersion));
- return artifact == null ? 0 : artifact.hits;
- }
-
- public ArtifactRepository resetHits() {
- repository.values().forEach(Artifact::resetHits);
+ repository.put(artifactHash(applicationId, applicationVersion), applicationPackage.zippedContent());
return this;
}
@@ -40,32 +29,11 @@ public class ArtifactRepositoryMock implements ArtifactRepository {
throw new IllegalArgumentException("No application package found for " + applicationId + " with version "
+ applicationVersion);
}
- Artifact artifact = repository.get(artifactHash);
- artifact.recordHit();
- return artifact.data;
+ return repository.get(artifactHash);
}
private static int artifactHash(ApplicationId applicationId, String applicationVersion) {
return Objects.hash(applicationId, applicationVersion);
}
- private class Artifact {
-
- private final byte[] data;
- private int hits = 0;
-
- private Artifact(byte[] data) {
- this.data = data;
- }
-
- private void recordHit() {
- hits++;
- }
-
- private void resetHits() {
- hits = 0;
- }
-
- }
-
}
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 97bbaec6427..8d03b4f7121 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
@@ -11,7 +11,6 @@ import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.TenantName;
import com.yahoo.vespa.athenz.api.AthenzDomain;
-import com.yahoo.vespa.athenz.api.NToken;
import com.yahoo.vespa.config.SlimeUtils;
import com.yahoo.vespa.hosted.controller.api.Tenant;
import com.yahoo.vespa.hosted.controller.api.application.v4.model.DeployOptions;
@@ -22,13 +21,13 @@ import com.yahoo.vespa.hosted.controller.api.identifiers.PropertyId;
import com.yahoo.vespa.hosted.controller.api.identifiers.TenantId;
import com.yahoo.vespa.hosted.controller.api.identifiers.UserGroup;
import com.yahoo.vespa.hosted.controller.api.integration.BuildService.BuildJob;
+import com.yahoo.vespa.athenz.api.NToken;
import com.yahoo.vespa.hosted.controller.api.integration.dns.Record;
import com.yahoo.vespa.hosted.controller.api.integration.dns.RecordName;
import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.application.ApplicationPackage;
import com.yahoo.vespa.hosted.controller.application.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.application.Change;
-import com.yahoo.vespa.hosted.controller.application.Deployment;
import com.yahoo.vespa.hosted.controller.application.DeploymentJobs;
import com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobError;
import com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobType;
@@ -202,60 +201,129 @@ public class ControllerTest {
assertNull("Deployment job was removed", applications.require(app1.id()).deploymentJobs().jobStatus().get(productionCorpUsEast1));
}
+ // TODO: Replace above test with this one after introducing new application version number
@Test
- public void testDeploymentApplicationVersion() {
+ public void testDeploymentWithApplicationVersion() {
+ // Setup system
DeploymentTester tester = new DeploymentTester();
- Application app = tester.createApplication("app1", "tenant1", 1, 11L);
+ ApplicationController applications = tester.controller().applications();
+ Version version1 = Version.fromString("6.1"); // Set in config server mock
+ Application app1 = tester.createApplication("app1", "tenant1", 1, 11L);
+
+ // Component runs, uploads artifact and notifies completion
ApplicationPackage applicationPackage = new ApplicationPackageBuilder()
.environment(Environment.prod)
.region("corp-us-east-1")
.region("us-east-3")
.build();
- SourceRevision source = new SourceRevision("repo", "master", "commit1");
+ SourceRevision source = new SourceRevision("repo", "branch", "deadbeef");
+ String expectedVersionString = "1.0.37-deadbeef";
+ tester.artifactRepository().put(app1.id(), applicationPackage, expectedVersionString);
+ tester.notifyJobCompletion(component, app1, Optional.empty(), Optional.of(source), 37);
+ ApplicationVersion expectedVersion = ApplicationVersion.from(source, 37);
+ assertEquals(expectedVersionString, tester.controller().applications()
+ .require(app1.id())
+ .change().application().get().id());
+
+ // Deploy without application package
+ tester.deployAndNotify(app1, true, systemTest);
+ tester.deployAndNotify(app1, true, stagingTest);
+ assertEquals(4, applications.require(app1.id()).deploymentJobs().jobStatus().size());
+ assertStatus(JobStatus.initial(stagingTest)
+ .withTriggering(version1, expectedVersion, false, "", tester.clock().instant().minus(Duration.ofMillis(1)))
+ .withCompletion(42, Optional.empty(), tester.clock().instant(), tester.controller()), app1.id(), tester.controller());
- ApplicationVersion applicationVersion = ApplicationVersion.from(source, 101);
- tester.artifactRepository().put(app.id(), applicationPackage, applicationVersion.id());
- runDeployment(tester, app.id(), applicationVersion, applicationPackage, Optional.of(source), 101);
- assertEquals("Artifact is downloaded twice in staging and once for other zones", 5,
- tester.artifactRepository().hits(app.id(), applicationVersion.id()));
- }
+ // Causes first deployment job to be triggered
+ assertStatus(JobStatus.initial(productionCorpUsEast1)
+ .withTriggering(version1, expectedVersion, false, "", tester.clock().instant()), app1.id(), tester.controller());
+ tester.clock().advance(Duration.ofSeconds(1));
- @Test
- public void testDeploymentApplicationVersionMigration() {
- DeploymentTester tester = new DeploymentTester();
- Application app = tester.createApplication("app1", "tenant1", 1, 11L);
- ApplicationPackage applicationPackage = new ApplicationPackageBuilder()
+ // production job (failing)
+ tester.deployAndNotify(app1, false, productionCorpUsEast1);
+ assertEquals(4, applications.require(app1.id()).deploymentJobs().jobStatus().size());
+
+ JobStatus expectedJobStatus = JobStatus.initial(productionCorpUsEast1)
+ .withTriggering(version1, expectedVersion, false, "", tester.clock().instant())
+ .withCompletion(42, Optional.of(JobError.unknown), tester.clock().instant(), tester.controller());
+
+ assertStatus(expectedJobStatus, app1.id(), tester.controller());
+
+ // Simulate restart
+ tester.restartController();
+ applications = tester.controller().applications();
+
+ assertNotNull(tester.controller().tenants().tenant(new TenantId("tenant1")));
+ assertNotNull(applications.get(ApplicationId.from(TenantName.from("tenant1"),
+ ApplicationName.from("application1"),
+ InstanceName.from("default"))));
+ assertEquals(4, applications.require(app1.id()).deploymentJobs().jobStatus().size());
+
+
+ tester.clock().advance(Duration.ofHours(1));
+
+ tester.notifyJobCompletion(productionCorpUsEast1, app1, false); // Need to complete the job, or new jobs won't start.
+
+ // Component is triggered again
+ tester.artifactRepository().put(app1.id(), applicationPackage, "1.0.38-deadbeef");
+ tester.notifyJobCompletion(component, app1, Optional.empty(), Optional.of(source), 38);
+ tester.deployAndNotify(app1, Optional.empty(), true, false, systemTest);
+ expectedVersion = ApplicationVersion.from(source, 38);
+ assertStatus(JobStatus.initial(systemTest)
+ .withTriggering(version1, expectedVersion, false, "", tester.clock().instant().minus(Duration.ofMillis(1)))
+ .withCompletion(42, Optional.empty(), tester.clock().instant(), tester.controller()), app1.id(), tester.controller());
+ tester.deployAndNotify(app1, Optional.empty(), true, true, stagingTest);
+
+ // production job succeeding now
+ tester.deployAndNotify(app1, Optional.empty(), true, true, productionCorpUsEast1);
+ expectedJobStatus = expectedJobStatus
+ .withTriggering(version1, expectedVersion, false, "", tester.clock().instant().minus(Duration.ofMillis(1)))
+ .withCompletion(42, Optional.empty(), tester.clock().instant(), tester.controller());
+ assertStatus(expectedJobStatus, app1.id(), tester.controller());
+
+ // causes triggering of next production job
+ assertStatus(JobStatus.initial(productionUsEast3)
+ .withTriggering(version1, expectedVersion, false, "", tester.clock().instant()),
+ app1.id(), tester.controller());
+ tester.deployAndNotify(app1, Optional.empty(), true, true, productionUsEast3);
+
+ assertEquals(5, applications.get(app1.id()).get().deploymentJobs().jobStatus().size());
+
+ // prod zone removal is not allowed
+ applicationPackage = new ApplicationPackageBuilder()
.environment(Environment.prod)
- .region("corp-us-east-1")
.region("us-east-3")
.build();
- SourceRevision source = new SourceRevision("repo", "master", "commit1");
-
- // Scenario 1: Old fashioned deployment. Simulates existing production deployments
- ApplicationVersion v0 = ApplicationVersion.from(applicationPackage.hash(), source);
- runDeployment(tester, app.id(), v0, applicationPackage, Optional.empty(), 100);
- assertEquals("Nothing downloaded from repository", 0,
- tester.artifactRepository().hits(app.id(), v0.id()));
-
- // Scenario 2: New application version number is reported and package is downloaded by controller. In staging,
- // the application package from the deployer is used as v0 cannot be downloaded from repository.
- ApplicationVersion v1 = ApplicationVersion.from(source, 101);
- tester.artifactRepository().put(app.id(), applicationPackage, v1.id());
- runDeployment(tester, app.id(), v1, applicationPackage, Optional.of(source), 101);
- assertEquals("Artifact is downloaded once per zone", 4,
- tester.artifactRepository().hits(app.id(), v1.id()));
- assertEquals("v0 is never downloaded", 0,
- tester.artifactRepository().hits(app.id(), v0.id()));
- tester.artifactRepository().resetHits();
-
- // Scenario 3: Both application versions are available in repository
- ApplicationVersion v2 = ApplicationVersion.from(source, 102);
- tester.artifactRepository().put(app.id(), applicationPackage, v2.id());
- runDeployment(tester, app.id(), v2, applicationPackage, Optional.of(source), 102);
- assertEquals("Previous artifact is downloaded once", 1,
- tester.artifactRepository().hits(app.id(), v1.id()));
- assertEquals("Artifact is downloaded once per zone", 4,
- tester.artifactRepository().hits(app.id(), v2.id()));
+ tester.artifactRepository().put(app1.id(), applicationPackage, "1.0.56-cafed00d");
+ source = new SourceRevision("repo", "branch", "cafed00d");
+ tester.notifyJobCompletion(component, app1, Optional.empty(), Optional.of(source), 56);
+ try {
+ tester.deploy(systemTest, app1, Optional.empty(), false);
+ fail("Expected exception due to unallowed production deployment removal");
+ }
+ catch (IllegalArgumentException e) {
+ assertEquals("deployment-removal: application 'tenant1.app1' is deployed in corp-us-east-1, but does not include this zone in deployment.xml", e.getMessage());
+ }
+ assertNotNull("Zone was not removed",
+ applications.require(app1.id()).deployments().get(productionCorpUsEast1.zone(SystemName.main).get()));
+ JobStatus jobStatus = applications.require(app1.id()).deploymentJobs().jobStatus().get(productionCorpUsEast1);
+ assertNotNull("Deployment job was not removed", jobStatus);
+ assertEquals(42, jobStatus.lastCompleted().get().id());
+ assertEquals("staging-test completed", jobStatus.lastCompleted().get().reason());
+
+ // prod zone removal is allowed with override
+ applicationPackage = new ApplicationPackageBuilder()
+ .allow(ValidationId.deploymentRemoval)
+ .upgradePolicy("default")
+ .environment(Environment.prod)
+ .region("us-east-3")
+ .build();
+ tester.artifactRepository().put(app1.id(), applicationPackage, "1.0.103-c00ffefe");
+ source = new SourceRevision("repo", "branch", "c00ffefe");
+ tester.notifyJobCompletion(component, app1, Optional.empty(), Optional.of(source), 103);
+ tester.deployAndNotify(app1, Optional.empty(), true, true, systemTest);
+ assertNull("Zone was removed",
+ applications.require(app1.id()).deployments().get(productionCorpUsEast1.zone(SystemName.main).get()));
+ assertNull("Deployment job was removed", applications.require(app1.id()).deploymentJobs().jobStatus().get(productionCorpUsEast1));
}
@Test
@@ -594,20 +662,19 @@ public class ControllerTest {
@Test
public void testDeployUntestedChangeFails() {
- DeploymentTester tester = new DeploymentTester();
+ ControllerTester tester = new ControllerTester();
ApplicationController applications = tester.controller().applications();
- TenantId tenant = tester.controllerTester().createTenant("tenant1", "domain1", 11L);
- Application app = tester.controllerTester().createApplication(tenant, "app1", "default", 1);
- tester.deployCompletely(app, applicationPackage);
+ TenantId tenant = tester.createTenant("tenant1", "domain1", 11L);
+ Application app = tester.createApplication(tenant, "app1", "default", 1);
tester.controller().applications().lockOrThrow(app.id(), application -> {
- application = application.withChange(Change.of(Version.fromString("6.3")));
+ application = application.withDeploying(Change.of(Version.fromString("6.3")));
applications.store(application);
try {
- tester.controllerTester().deploy(app, ZoneId.from("prod", "corp-us-east-1"), applicationPackage);
+ tester.deploy(app, ZoneId.from("prod", "us-east-3"));
fail("Expected exception");
} catch (IllegalArgumentException e) {
- assertEquals("Rejecting deployment of application 'tenant1.app1' to zone prod.corp-us-east-1 as upgrade to 6.3 is not tested", e.getMessage());
+ assertEquals("Rejecting deployment of application 'tenant1.app1' to zone prod.us-east-3 as upgrade to 6.3 is not tested", e.getMessage());
}
});
}
@@ -848,51 +915,4 @@ public class ControllerTest {
}
- private void runDeployment(DeploymentTester tester, ApplicationId application,
- ApplicationVersion expectedVersion,
- ApplicationPackage applicationPackage, Optional<SourceRevision> sourceRevision,
- long initialBuildNumber) {
- Version vespaVersion = Version.fromString("6.1"); // Set in config server mock
- Application app = tester.applications().require(application);
-
- // Component notifies completion
- tester.notifyJobCompletion(component, app, Optional.empty(), sourceRevision, initialBuildNumber);
- ApplicationVersion change =
- sourceRevision.map(sr -> ApplicationVersion.from(sr, initialBuildNumber))
- .orElse(ApplicationVersion.unknown);
- assertEquals(change.id(), tester.controller().applications()
- .require(application)
- .change().application().get().id());
-
- // Deploy in test
- tester.deployAndNotify(app, applicationPackage, true, systemTest);
- tester.deployAndNotify(app, applicationPackage, true, stagingTest);
- //assertEquals(4, applications.require(application).deploymentJobs().jobStatus().size());
- assertStatus(JobStatus.initial(stagingTest)
- .withTriggering(vespaVersion, expectedVersion, false, "",
- tester.clock().instant().minus(Duration.ofMillis(1)))
- .withCompletion(42, Optional.empty(), tester.clock().instant(),
- tester.controller()), application, tester.controller());
-
- // Deploy in production
- tester.deployAndNotify(app, applicationPackage, true, productionCorpUsEast1);
- assertStatus(JobStatus.initial(productionCorpUsEast1)
- .withTriggering(vespaVersion, expectedVersion, false, "",
- tester.clock().instant().minus(Duration.ofMillis(1)))
- .withCompletion(42, Optional.empty(), tester.clock().instant(),
- tester.controller()), application, tester.controller());
- tester.deployAndNotify(app, applicationPackage, true, true, productionUsEast3);
- assertStatus(JobStatus.initial(productionUsEast3)
- .withTriggering(vespaVersion, expectedVersion, false, "",
- tester.clock().instant().minus(Duration.ofMillis(1)))
- .withCompletion(42, Optional.empty(), tester.clock().instant(),
- tester.controller()), application, tester.controller());
-
- // Verify deployed version
- app = tester.controller().applications().require(app.id());
- for (Deployment deployment : app.productionDeployments().values()) {
- assertEquals(expectedVersion, deployment.applicationVersion());
- }
- }
-
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java
index 58f2a21fa6a..d0dfe825558 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java
@@ -253,6 +253,10 @@ public class DeploymentTester {
deployCurrentVersion));
}
+ public void deployAndNotify(Application application, boolean success, JobType... job) {
+ deployAndNotify(application, Optional.empty(), success, true, job);
+ }
+
public void deployAndNotify(Application application, String upgradePolicy, boolean success, JobType... jobs) {
deployAndNotify(application, applicationPackage(upgradePolicy), success, true, jobs);
}
@@ -272,10 +276,6 @@ public class DeploymentTester {
consumeJobs(application, expectOnlyTheseJobs, jobs);
for (JobType job : jobs) {
if (success) {
- // Staging deploys twice, once with current version and once with new version
- if (job == JobType.stagingTest) {
- deploy(job, application, applicationPackage, true);
- }
deploy(job, application, applicationPackage, false);
}
notifyJobCompletion(job, application, success);
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 029eb335d82..5c61e43f9cf 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
@@ -320,7 +320,7 @@ public class DeploymentTriggerTest {
new JobControl(tester.controllerTester().curator()));
LockedApplication app = (LockedApplication)tester.createAndDeploy("default0", 3, "default");
// Store that we are upgrading but don't start the system-tests job
- tester.controller().applications().store(app.withChange(Change.of(Version.fromString("6.2"))));
+ tester.controller().applications().store(app.withDeploying(Change.of(Version.fromString("6.2"))));
assertEquals(0, tester.buildSystem().jobs().size());
readyJobsTrigger.run();
assertEquals(1, tester.buildSystem().jobs().size());
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 35bd63745c4..ffb9ee57351 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
@@ -27,9 +27,6 @@ import com.yahoo.vespa.hosted.controller.rotation.RotationId;
import org.junit.Test;
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.ArrayList;
import java.util.HashMap;
@@ -47,7 +44,7 @@ import static org.junit.Assert.assertFalse;
public class ApplicationSerializerTest {
private static final ApplicationSerializer applicationSerializer = new ApplicationSerializer();
- 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");
@@ -62,9 +59,9 @@ public class ApplicationSerializerTest {
"</validation-overrides>");
List<Deployment> deployments = new ArrayList<>();
- ApplicationVersion applicationVersion1 = ApplicationVersion.from(new SourceRevision("repo1", "branch1", "commit1"), 31);
+ ApplicationVersion applicationVersion1 = ApplicationVersion.from("appHash1");
ApplicationVersion applicationVersion2 = ApplicationVersion
- .from(new SourceRevision("repo1", "branch1", "commit1"), 32);
+ .from("appHash2", new SourceRevision("repo1", "branch1", "commit1"));
deployments.add(new Deployment(zone1, applicationVersion1, Version.fromString("1.2.3"), Instant.ofEpochMilli(3))); // One deployment without cluster info and utils
deployments.add(new Deployment(zone2, applicationVersion2, Version.fromString("1.2.3"), Instant.ofEpochMilli(5),
createClusterUtils(3, 0.2), createClusterInfo(3, 4),new DeploymentMetrics(2,3,4,5,6)));
@@ -148,19 +145,20 @@ public class ApplicationSerializerTest {
assertEquals(6, serialized.deployments().get(zone2).metrics().writeLatencyMillis(), Double.MIN_VALUE);
{ // test more deployment serialization cases
- Application original2 = writable(original).withChange(Change.of(ApplicationVersion.from("hash1")));
+ Application original2 = writable(original).withDeploying(Change.of(ApplicationVersion.from("hash1")));
Application serialized2 = applicationSerializer.fromSlime(applicationSerializer.toSlime(original2));
assertEquals(original2.change(), serialized2.change());
assertEquals(serialized2.change().application().get().source(),
original2.change().application().get().source());
- Application original3 = writable(original).withChange(Change.of(ApplicationVersion.from("hash1",
- new SourceRevision("a", "b", "c"))));
+ Application original3 = writable(original).withDeploying(Change.of(ApplicationVersion.from("hash1",
+ new SourceRevision("a", "b", "c"))));
Application serialized3 = applicationSerializer.fromSlime(applicationSerializer.toSlime(original3));
- assertEquals(original3.change(), serialized3.change());
+ assertEquals(original3.change(), serialized2.change());
assertEquals(serialized3.change().application().get().source(),
original3.change().application().get().source());
- Application original4 = writable(original).withChange(Change.empty());
+
+ Application original4 = writable(original).withDeploying(Change.empty());
Application serialized4 = applicationSerializer.fromSlime(applicationSerializer.toSlime(original4));
assertEquals(original4.change(), serialized4.change());
}
@@ -212,9 +210,8 @@ public class ApplicationSerializerTest {
}
@Test
- public void testCompleteApplicationDeserialization() throws Exception {
- byte[] applicationJson = Files.readAllBytes(testData.resolve("complete-application.json"));
- applicationSerializer.fromSlime(SlimeUtils.jsonToSlime(applicationJson));
+ public void testCompleteApplicationDeserialization() {
+ applicationSerializer.fromSlime(SlimeUtils.jsonToSlime(longApplicationJson.getBytes(StandardCharsets.UTF_8)));
// ok if no error
}
@@ -255,4 +252,5 @@ public class ApplicationSerializerTest {
"}\n";
}
+ private final String longApplicationJson = "{\"id\":\"tripod:service-aggregation-vespa:default\",\"deploymentSpecField\":\"<deployment version='1.0'>\\n <test />\\n <!--<staging />-->\\n <prod global-service-id=\\\"tripod\\\">\\n <region active=\\\"true\\\">us-east-3</region>\\n <region active=\\\"true\\\">us-west-1</region>\\n </prod>\\n</deployment>\\n\",\"validationOverrides\":\"<validation-overrides>\\n <allow until=\\\"2016-04-28\\\" comment=\\\"Renaming content cluster\\\">content-cluster-removal</allow>\\n <allow until=\\\"2016-08-22\\\" comment=\\\"Migrating us-east-3 to C-2E\\\">cluster-size-reduction</allow>\\n <allow until=\\\"2017-06-30\\\" comment=\\\"Test Vespa upgrade tests\\\">force-automatic-tenant-upgrade-test</allow>\\n</validation-overrides>\\n\",\"deployments\":[{\"zone\":{\"environment\":\"prod\",\"region\":\"us-west-1\"},\"version\":\"6.173.62\",\"deployTime\":1510837817704,\"applicationPackageRevision\":{\"applicationPackageHash\":\"9db423e1021d7b452d37ec6372bc757d9c1bda87\",\"sourceRevision\":{\"repositoryField\":\"git@git.ouroath.com:Tripod/service-aggregation-vespa.git\",\"branchField\":\"origin/master\",\"commitField\":\"49cd7bbb1ed9f4b922083cb042590b0885ffe22b\"}},\"clusterInfo\":{\"tripod\":{\"flavor\":\"d-3-16-100\",\"cost\":9,\"flavorCpu\":0,\"flavorMem\":0,\"flavorDisk\":0,\"clusterType\":\"container\",\"hostnames\":[\"oxy-oxygen-2001-4998-c-2942--10d1.gq1.yahoo.com\",\"oxy-oxygen-2001-4998-c-2942--10e2.gq1.yahoo.com\"]},\"tripodaggregation\":{\"flavor\":\"d-12-64-400\",\"cost\":38,\"flavorCpu\":0,\"flavorMem\":0,\"flavorDisk\":0,\"clusterType\":\"content\",\"hostnames\":[\"oxy-oxygen-2001-4998-c-2941--106a.gq1.yahoo.com\",\"zt74700-v6-23.ostk.bm2.prod.gq1.yahoo.com\",\"zt74714-v6-28.ostk.bm2.prod.gq1.yahoo.com\",\"zt74730-v6-13.ostk.bm2.prod.gq1.yahoo.com\",\"zt74717-v6-7.ostk.bm2.prod.gq1.yahoo.com\",\"2080260-v6-12.ostk.bm2.prod.gq1.yahoo.com\",\"zt74719-v6-23.ostk.bm2.prod.gq1.yahoo.com\",\"zt74722-v6-26.ostk.bm2.prod.gq1.yahoo.com\",\"zt74704-v6-9.ostk.bm2.prod.gq1.yahoo.com\",\"oxy-oxygen-2001-4998-c-2942--107d.gq1.yahoo.com\"]},\"tripodaggregationstream\":{\"flavor\":\"d-12-64-400\",\"cost\":38,\"flavorCpu\":0,\"flavorMem\":0,\"flavorDisk\":0,\"clusterType\":\"content\",\"hostnames\":[\"zt74727-v6-21.ostk.bm2.prod.gq1.yahoo.com\",\"zt74773-v6-8.ostk.bm2.prod.gq1.yahoo.com\",\"zt74699-v6-25.ostk.bm2.prod.gq1.yahoo.com\",\"zt74766-v6-27.ostk.bm2.prod.gq1.yahoo.com\"]}},\"clusterUtils\":{\"tripod\":{\"cpu\":0.1720353499228221,\"mem\":0.4986146831512451,\"disk\":0.0617671330041831,\"diskbusy\":0},\"tripodaggregation\":{\"cpu\":0.07505730001866318,\"mem\":0.7936344432830811,\"disk\":0.2260549694485994,\"diskbusy\":0},\"tripodaggregationstream\":{\"cpu\":0.01712671480989384,\"mem\":0.0225852754983035,\"disk\":0.006084436856721915,\"diskbusy\":0}},\"metrics\":{\"queriesPerSecond\":1.25,\"writesPerSecond\":43.83199977874756,\"documentCount\":525880277.9999999,\"queryLatencyMillis\":5.607503938674927,\"writeLatencyMillis\":20.57866265104621}},{\"zone\":{\"environment\":\"test\",\"region\":\"us-east-1\"},\"version\":\"6.173.62\",\"deployTime\":1511256872316,\"applicationPackageRevision\":{\"applicationPackageHash\":\"ec548fa61cbfab7a270a51d46b1263ec1be5d9a8\",\"sourceRevision\":{\"repositoryField\":\"git@git.ouroath.com:Tripod/service-aggregation-vespa.git\",\"branchField\":\"origin/master\",\"commitField\":\"234f3e4e77049d0b9538c9e1b356d17eb1dedb6a\"}},\"clusterInfo\":{},\"clusterUtils\":{},\"metrics\":{\"queriesPerSecond\":0,\"writesPerSecond\":0,\"documentCount\":0,\"queryLatencyMillis\":0,\"writeLatencyMillis\":0}},{\"zone\":{\"environment\":\"dev\",\"region\":\"us-east-1\"},\"version\":\"6.173.62\",\"deployTime\":1510597489464,\"applicationPackageRevision\":{\"applicationPackageHash\":\"59b883f263c2a3c23dfab249730097d7e0e1ed32\"},\"clusterInfo\":{\"tripod\":{\"flavor\":\"d-2-8-50\",\"cost\":5,\"flavorCpu\":0,\"flavorMem\":0,\"flavorDisk\":0,\"clusterType\":\"container\",\"hostnames\":[\"zt40807-v6-29.ostk.bm2.prod.bf1.yahoo.com\"]},\"tripodaggregation\":{\"flavor\":\"d-2-8-50\",\"cost\":5,\"flavorCpu\":0,\"flavorMem\":0,\"flavorDisk\":0,\"clusterType\":\"content\",\"hostnames\":[\"zt40807-v6-24.ostk.bm2.prod.bf1.yahoo.com\"]},\"tripodaggregationstream\":{\"flavor\":\"d-2-8-50\",\"cost\":5,\"flavorCpu\":0,\"flavorMem\":0,\"flavorDisk\":0,\"clusterType\":\"content\",\"hostnames\":[\"zt40694-v6-21.ostk.bm2.prod.bf1.yahoo.com\"]}},\"clusterUtils\":{\"tripod\":{\"cpu\":0.191833330678661,\"mem\":0.4625738318415235,\"disk\":0.05582004563850269,\"diskbusy\":0},\"tripodaggregation\":{\"cpu\":0.2227037978608054,\"mem\":0.2051752598416401,\"disk\":0.05471533698695047,\"diskbusy\":0},\"tripodaggregationstream\":{\"cpu\":0.1869410834020498,\"mem\":0.1691722576000564,\"disk\":0.04977374774258153,\"diskbusy\":0}},\"metrics\":{\"queriesPerSecond\":0,\"writesPerSecond\":0,\"documentCount\":30916,\"queryLatencyMillis\":0,\"writeLatencyMillis\":0}},{\"zone\":{\"environment\":\"prod\",\"region\":\"us-east-3\"},\"version\":\"6.173.62\",\"deployTime\":1510817190016,\"applicationPackageRevision\":{\"applicationPackageHash\":\"9db423e1021d7b452d37ec6372bc757d9c1bda87\",\"sourceRevision\":{\"repositoryField\":\"git@git.ouroath.com:Tripod/service-aggregation-vespa.git\",\"branchField\":\"origin/master\",\"commitField\":\"49cd7bbb1ed9f4b922083cb042590b0885ffe22b\"}},\"clusterInfo\":{\"tripod\":{\"flavor\":\"d-3-16-100\",\"cost\":9,\"flavorCpu\":0,\"flavorMem\":0,\"flavorDisk\":0,\"clusterType\":\"container\",\"hostnames\":[\"zt40738-v6-13.ostk.bm2.prod.bf1.yahoo.com\",\"zt40783-v6-31.ostk.bm2.prod.bf1.yahoo.com\"]},\"tripodaggregation\":{\"flavor\":\"d-12-64-400\",\"cost\":38,\"flavorCpu\":0,\"flavorMem\":0,\"flavorDisk\":0,\"clusterType\":\"content\",\"hostnames\":[\"zt40819-v6-7.ostk.bm2.prod.bf1.yahoo.com\",\"zt40661-v6-3.ostk.bm2.prod.bf1.yahoo.com\",\"zt40805-v6-30.ostk.bm2.prod.bf1.yahoo.com\",\"zt40702-v6-32.ostk.bm2.prod.bf1.yahoo.com\",\"zt40706-v6-3.ostk.bm2.prod.bf1.yahoo.com\",\"zt40691-v6-27.ostk.bm2.prod.bf1.yahoo.com\",\"zt40676-v6-15.ostk.bm2.prod.bf1.yahoo.com\",\"zt40788-v6-23.ostk.bm2.prod.bf1.yahoo.com\",\"zt40782-v6-30.ostk.bm2.prod.bf1.yahoo.com\",\"zt40802-v6-32.ostk.bm2.prod.bf1.yahoo.com\"]},\"tripodaggregationstream\":{\"flavor\":\"d-12-64-400\",\"cost\":38,\"flavorCpu\":0,\"flavorMem\":0,\"flavorDisk\":0,\"clusterType\":\"content\",\"hostnames\":[\"zt40779-v6-27.ostk.bm2.prod.bf1.yahoo.com\",\"zt40791-v6-15.ostk.bm2.prod.bf1.yahoo.com\",\"zt40733-v6-31.ostk.bm2.prod.bf1.yahoo.com\",\"zt40724-v6-30.ostk.bm2.prod.bf1.yahoo.com\"]}},\"clusterUtils\":{\"tripod\":{\"cpu\":0.2295038983007097,\"mem\":0.4627357390237263,\"disk\":0.05559941525894966,\"diskbusy\":0},\"tripodaggregation\":{\"cpu\":0.05340429087579549,\"mem\":0.8107630891552372,\"disk\":0.226444914138854,\"diskbusy\":0},\"tripodaggregationstream\":{\"cpu\":0.02148227413975218,\"mem\":0.02162174219104161,\"disk\":0.006057760545243265,\"diskbusy\":0}},\"metrics\":{\"queriesPerSecond\":1.734000012278557,\"writesPerSecond\":44.59999895095825,\"documentCount\":525868193.9999999,\"queryLatencyMillis\":5.65284947195106,\"writeLatencyMillis\":17.34593812832452}}],\"deploymentJobs\":{\"projectId\":102889,\"jobStatus\":[{\"jobType\":\"staging-test\",\"lastTriggered\":{\"id\":-1,\"version\":\"6.173.62\",\"revision\":{\"applicationPackageHash\":\"9db423e1021d7b452d37ec6372bc757d9c1bda87\",\"sourceRevision\":{\"repositoryField\":\"git@git.ouroath.com:Tripod/service-aggregation-vespa.git\",\"branchField\":\"origin/master\",\"commitField\":\"49cd7bbb1ed9f4b922083cb042590b0885ffe22b\"}},\"upgrade\":true,\"reason\":\"system-test completed\",\"at\":1510830134259},\"lastCompleted\":{\"id\":1184,\"version\":\"6.173.62\",\"revision\":{\"applicationPackageHash\":\"9db423e1021d7b452d37ec6372bc757d9c1bda87\",\"sourceRevision\":{\"repositoryField\":\"git@git.ouroath.com:Tripod/service-aggregation-vespa.git\",\"branchField\":\"origin/master\",\"commitField\":\"49cd7bbb1ed9f4b922083cb042590b0885ffe22b\"}},\"upgrade\":true,\"reason\":\"system-test completed\",\"at\":1510830684960},\"lastSuccess\":{\"id\":1184,\"version\":\"6.173.62\",\"revision\":{\"applicationPackageHash\":\"9db423e1021d7b452d37ec6372bc757d9c1bda87\",\"sourceRevision\":{\"repositoryField\":\"git@git.ouroath.com:Tripod/service-aggregation-vespa.git\",\"branchField\":\"origin/master\",\"commitField\":\"49cd7bbb1ed9f4b922083cb042590b0885ffe22b\"}},\"upgrade\":true,\"reason\":\"system-test completed\",\"at\":1510830684960}},{\"jobType\":\"component\",\"lastCompleted\":{\"id\":849,\"version\":\"6.174.156\",\"upgrade\":false,\"reason\":\"Application commit\",\"at\":1511217733555},\"lastSuccess\":{\"id\":849,\"version\":\"6.174.156\",\"upgrade\":false,\"reason\":\"Application commit\",\"at\":1511217733555}},{\"jobType\":\"production-us-east-3\",\"lastTriggered\":{\"id\":-1,\"version\":\"6.173.62\",\"revision\":{\"applicationPackageHash\":\"9db423e1021d7b452d37ec6372bc757d9c1bda87\",\"sourceRevision\":{\"repositoryField\":\"git@git.ouroath.com:Tripod/service-aggregation-vespa.git\",\"branchField\":\"origin/master\",\"commitField\":\"49cd7bbb1ed9f4b922083cb042590b0885ffe22b\"}},\"upgrade\":true,\"reason\":\"staging-test completed\",\"at\":1510830685127},\"lastCompleted\":{\"id\":923,\"version\":\"6.173.62\",\"revision\":{\"applicationPackageHash\":\"9db423e1021d7b452d37ec6372bc757d9c1bda87\",\"sourceRevision\":{\"repositoryField\":\"git@git.ouroath.com:Tripod/service-aggregation-vespa.git\",\"branchField\":\"origin/master\",\"commitField\":\"49cd7bbb1ed9f4b922083cb042590b0885ffe22b\"}},\"upgrade\":true,\"reason\":\"staging-test completed\",\"at\":1510837650046},\"lastSuccess\":{\"id\":923,\"version\":\"6.173.62\",\"revision\":{\"applicationPackageHash\":\"9db423e1021d7b452d37ec6372bc757d9c1bda87\",\"sourceRevision\":{\"repositoryField\":\"git@git.ouroath.com:Tripod/service-aggregation-vespa.git\",\"branchField\":\"origin/master\",\"commitField\":\"49cd7bbb1ed9f4b922083cb042590b0885ffe22b\"}},\"upgrade\":true,\"reason\":\"staging-test completed\",\"at\":1510837650046}},{\"jobType\":\"production-us-west-1\",\"lastTriggered\":{\"id\":-1,\"version\":\"6.173.62\",\"revision\":{\"applicationPackageHash\":\"9db423e1021d7b452d37ec6372bc757d9c1bda87\",\"sourceRevision\":{\"repositoryField\":\"git@git.ouroath.com:Tripod/service-aggregation-vespa.git\",\"branchField\":\"origin/master\",\"commitField\":\"49cd7bbb1ed9f4b922083cb042590b0885ffe22b\"}},\"upgrade\":true,\"reason\":\"production-us-east-3 completed\",\"at\":1510837650139},\"lastCompleted\":{\"id\":646,\"version\":\"6.173.62\",\"revision\":{\"applicationPackageHash\":\"9db423e1021d7b452d37ec6372bc757d9c1bda87\",\"sourceRevision\":{\"repositoryField\":\"git@git.ouroath.com:Tripod/service-aggregation-vespa.git\",\"branchField\":\"origin/master\",\"commitField\":\"49cd7bbb1ed9f4b922083cb042590b0885ffe22b\"}},\"upgrade\":true,\"reason\":\"production-us-east-3 completed\",\"at\":1510843559162},\"lastSuccess\":{\"id\":646,\"version\":\"6.173.62\",\"revision\":{\"applicationPackageHash\":\"9db423e1021d7b452d37ec6372bc757d9c1bda87\",\"sourceRevision\":{\"repositoryField\":\"git@git.ouroath.com:Tripod/service-aggregation-vespa.git\",\"branchField\":\"origin/master\",\"commitField\":\"49cd7bbb1ed9f4b922083cb042590b0885ffe22b\"}},\"upgrade\":true,\"reason\":\"production-us-east-3 completed\",\"at\":1510843559162}},{\"jobType\":\"system-test\",\"jobError\":\"unknown\",\"lastTriggered\":{\"id\":-1,\"version\":\"6.173.62\",\"revision\":{\"applicationPackageHash\":\"ec548fa61cbfab7a270a51d46b1263ec1be5d9a8\",\"sourceRevision\":{\"repositoryField\":\"git@git.ouroath.com:Tripod/service-aggregation-vespa.git\",\"branchField\":\"origin/master\",\"commitField\":\"234f3e4e77049d0b9538c9e1b356d17eb1dedb6a\"}},\"upgrade\":false,\"reason\":\"Available change in component\",\"at\":1511256608649},\"lastCompleted\":{\"id\":1686,\"version\":\"6.173.62\",\"revision\":{\"applicationPackageHash\":\"ec548fa61cbfab7a270a51d46b1263ec1be5d9a8\",\"sourceRevision\":{\"repositoryField\":\"git@git.ouroath.com:Tripod/service-aggregation-vespa.git\",\"branchField\":\"origin/master\",\"commitField\":\"234f3e4e77049d0b9538c9e1b356d17eb1dedb6a\"}},\"upgrade\":false,\"reason\":\"Available change in component\",\"at\":1511256603353},\"firstFailing\":{\"id\":1659,\"version\":\"6.173.62\",\"revision\":{\"applicationPackageHash\":\"ec548fa61cbfab7a270a51d46b1263ec1be5d9a8\",\"sourceRevision\":{\"repositoryField\":\"git@git.ouroath.com:Tripod/service-aggregation-vespa.git\",\"branchField\":\"origin/master\",\"commitField\":\"234f3e4e77049d0b9538c9e1b356d17eb1dedb6a\"}},\"upgrade\":false,\"reason\":\"component completed\",\"at\":1511219070725},\"lastSuccess\":{\"id\":1658,\"version\":\"6.173.62\",\"revision\":{\"applicationPackageHash\":\"9db423e1021d7b452d37ec6372bc757d9c1bda87\",\"sourceRevision\":{\"repositoryField\":\"git@git.ouroath.com:Tripod/service-aggregation-vespa.git\",\"branchField\":\"origin/master\",\"commitField\":\"49cd7bbb1ed9f4b922083cb042590b0885ffe22b\"}},\"upgrade\":true,\"reason\":\"Upgrading to 6.173.62\",\"at\":1511175754163}}]},\"deployingField\":{\"applicationPackageHash\":\"ec548fa61cbfab7a270a51d46b1263ec1be5d9a8\",\"sourceRevision\":{\"repositoryField\":\"git@git.ouroath.com:Tripod/service-aggregation-vespa.git\",\"branchField\":\"origin/master\",\"commitField\":\"234f3e4e77049d0b9538c9e1b356d17eb1dedb6a\"}},\"outstandingChangeField\":false,\"queryQuality\":100,\"writeQuality\":99.99894341115082}";
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/complete-application.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/complete-application.json
deleted file mode 100644
index 59cb709eb3f..00000000000
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/complete-application.json
+++ /dev/null
@@ -1,514 +0,0 @@
-{
- "id": "tenant1:app1:default",
- "deploymentSpecField": "<deployment version='1.0'>\n <test />\n <!--<staging />-->\n <prod global-service-id=\"foo\">\n <region active=\"true\">us-east-3</region>\n <region active=\"true\">us-west-1</region>\n </prod>\n</deployment>\n",
- "validationOverrides": "<validation-overrides>\n <allow until=\"2016-04-28\" comment=\"Renaming content cluster\">content-cluster-removal</allow>\n <allow until=\"2016-08-22\" comment=\"Migrating us-east-3 to C-2E\">cluster-size-reduction</allow>\n <allow until=\"2017-06-30\" comment=\"Test Vespa upgrade tests\">force-automatic-tenant-upgrade-test</allow>\n</validation-overrides>\n",
- "deployments": [
- {
- "zone": {
- "environment": "prod",
- "region": "us-west-1"
- },
- "version": "6.173.62",
- "deployTime": 1510837817704,
- "applicationPackageRevision": {
- "applicationPackageHash": "9db423e1021d7b452d37ec6372bc757d9c1bda87",
- "sourceRevision": {
- "repositoryField": "git@git.host:user/repo.git",
- "branchField": "origin/master",
- "commitField": "49cd7bbb1ed9f4b922083cb042590b0885ffe22b"
- }
- },
- "clusterInfo": {
- "cluster1": {
- "flavor": "d-3-16-100",
- "cost": 9,
- "flavorCpu": 0,
- "flavorMem": 0,
- "flavorDisk": 0,
- "clusterType": "container",
- "hostnames": [
- "node1",
- "node2"
- ]
- },
- "cluster2": {
- "flavor": "d-12-64-400",
- "cost": 38,
- "flavorCpu": 0,
- "flavorMem": 0,
- "flavorDisk": 0,
- "clusterType": "content",
- "hostnames": [
- "node3",
- "node4",
- "node5"
- ]
- },
- "cluster3": {
- "flavor": "d-12-64-400",
- "cost": 38,
- "flavorCpu": 0,
- "flavorMem": 0,
- "flavorDisk": 0,
- "clusterType": "content",
- "hostnames": [
- "node6",
- "node7",
- "node8",
- "node9"
- ]
- }
- },
- "clusterUtils": {
- "cluster1": {
- "cpu": 0.1720353499228221,
- "mem": 0.4986146831512451,
- "disk": 0.0617671330041831,
- "diskbusy": 0
- },
- "cluster2": {
- "cpu": 0.07505730001866318,
- "mem": 0.7936344432830811,
- "disk": 0.2260549694485994,
- "diskbusy": 0
- },
- "cluster3": {
- "cpu": 0.01712671480989384,
- "mem": 0.0225852754983035,
- "disk": 0.006084436856721915,
- "diskbusy": 0
- }
- },
- "metrics": {
- "queriesPerSecond": 1.25,
- "writesPerSecond": 43.83199977874756,
- "documentCount": 525880277.9999999,
- "queryLatencyMillis": 5.607503938674927,
- "writeLatencyMillis": 20.57866265104621
- }
- },
- {
- "zone": {
- "environment": "test",
- "region": "us-east-1"
- },
- "version": "6.173.62",
- "deployTime": 1511256872316,
- "applicationPackageRevision": {
- "applicationPackageHash": "ec548fa61cbfab7a270a51d46b1263ec1be5d9a8",
- "sourceRevision": {
- "repositoryField": "git@git.host:user/repo.git",
- "branchField": "origin/master",
- "commitField": "234f3e4e77049d0b9538c9e1b356d17eb1dedb6a"
- }
- },
- "clusterInfo": {},
- "clusterUtils": {},
- "metrics": {
- "queriesPerSecond": 0,
- "writesPerSecond": 0,
- "documentCount": 0,
- "queryLatencyMillis": 0,
- "writeLatencyMillis": 0
- }
- },
- {
- "zone": {
- "environment": "dev",
- "region": "us-east-1"
- },
- "version": "6.173.62",
- "deployTime": 1510597489464,
- "applicationPackageRevision": {
- "applicationPackageHash": "59b883f263c2a3c23dfab249730097d7e0e1ed32"
- },
- "clusterInfo": {
- "cluster1": {
- "flavor": "d-2-8-50",
- "cost": 5,
- "flavorCpu": 0,
- "flavorMem": 0,
- "flavorDisk": 0,
- "clusterType": "container",
- "hostnames": [
- "node1"
- ]
- },
- "cluster2": {
- "flavor": "d-2-8-50",
- "cost": 5,
- "flavorCpu": 0,
- "flavorMem": 0,
- "flavorDisk": 0,
- "clusterType": "content",
- "hostnames": [
- "node2"
- ]
- },
- "cluster3": {
- "flavor": "d-2-8-50",
- "cost": 5,
- "flavorCpu": 0,
- "flavorMem": 0,
- "flavorDisk": 0,
- "clusterType": "content",
- "hostnames": [
- "node3"
- ]
- }
- },
- "clusterUtils": {
- "cluster1": {
- "cpu": 0.191833330678661,
- "mem": 0.4625738318415235,
- "disk": 0.05582004563850269,
- "diskbusy": 0
- },
- "cluster2": {
- "cpu": 0.2227037978608054,
- "mem": 0.2051752598416401,
- "disk": 0.05471533698695047,
- "diskbusy": 0
- },
- "cluster3": {
- "cpu": 0.1869410834020498,
- "mem": 0.1691722576000564,
- "disk": 0.04977374774258153,
- "diskbusy": 0
- }
- },
- "metrics": {
- "queriesPerSecond": 0,
- "writesPerSecond": 0,
- "documentCount": 30916,
- "queryLatencyMillis": 0,
- "writeLatencyMillis": 0
- }
- },
- {
- "zone": {
- "environment": "prod",
- "region": "us-east-3"
- },
- "version": "6.173.62",
- "deployTime": 1510817190016,
- "applicationPackageRevision": {
- "applicationPackageHash": "9db423e1021d7b452d37ec6372bc757d9c1bda87",
- "sourceRevision": {
- "repositoryField": "git@git.host:user/repo.git",
- "branchField": "origin/master",
- "commitField": "49cd7bbb1ed9f4b922083cb042590b0885ffe22b"
- }
- },
- "clusterInfo": {
- "cluster1": {
- "flavor": "d-3-16-100",
- "cost": 9,
- "flavorCpu": 0,
- "flavorMem": 0,
- "flavorDisk": 0,
- "clusterType": "container",
- "hostnames": [
- "node1",
- "node2"
- ]
- },
- "cluster2": {
- "flavor": "d-12-64-400",
- "cost": 38,
- "flavorCpu": 0,
- "flavorMem": 0,
- "flavorDisk": 0,
- "clusterType": "content",
- "hostnames": [
- "node1",
- "node2",
- "node3"
- ]
- },
- "cluster3": {
- "flavor": "d-12-64-400",
- "cost": 38,
- "flavorCpu": 0,
- "flavorMem": 0,
- "flavorDisk": 0,
- "clusterType": "content",
- "hostnames": [
- "node1",
- "node2",
- "node3",
- "node4"
- ]
- }
- },
- "clusterUtils": {
- "cluster1": {
- "cpu": 0.2295038983007097,
- "mem": 0.4627357390237263,
- "disk": 0.05559941525894966,
- "diskbusy": 0
- },
- "cluster2": {
- "cpu": 0.05340429087579549,
- "mem": 0.8107630891552372,
- "disk": 0.226444914138854,
- "diskbusy": 0
- },
- "cluster3": {
- "cpu": 0.02148227413975218,
- "mem": 0.02162174219104161,
- "disk": 0.006057760545243265,
- "diskbusy": 0
- }
- },
- "metrics": {
- "queriesPerSecond": 1.734000012278557,
- "writesPerSecond": 44.59999895095825,
- "documentCount": 525868193.9999999,
- "queryLatencyMillis": 5.65284947195106,
- "writeLatencyMillis": 17.34593812832452
- }
- }
- ],
- "deploymentJobs": {
- "projectId": 102889,
- "jobStatus": [
- {
- "jobType": "staging-test",
- "lastTriggered": {
- "id": -1,
- "version": "6.173.62",
- "revision": {
- "applicationPackageHash": "9db423e1021d7b452d37ec6372bc757d9c1bda87",
- "sourceRevision": {
- "repositoryField": "git@git.host:user/repo.git",
- "branchField": "origin/master",
- "commitField": "49cd7bbb1ed9f4b922083cb042590b0885ffe22b"
- }
- },
- "upgrade": true,
- "reason": "system-test completed",
- "at": 1510830134259
- },
- "lastCompleted": {
- "id": 1184,
- "version": "6.173.62",
- "revision": {
- "applicationPackageHash": "9db423e1021d7b452d37ec6372bc757d9c1bda87",
- "sourceRevision": {
- "repositoryField": "git@git.host:user/repo.git",
- "branchField": "origin/master",
- "commitField": "49cd7bbb1ed9f4b922083cb042590b0885ffe22b"
- }
- },
- "upgrade": true,
- "reason": "system-test completed",
- "at": 1510830684960
- },
- "lastSuccess": {
- "id": 1184,
- "version": "6.173.62",
- "revision": {
- "applicationPackageHash": "9db423e1021d7b452d37ec6372bc757d9c1bda87",
- "sourceRevision": {
- "repositoryField": "git@git.host:user/repo.git",
- "branchField": "origin/master",
- "commitField": "49cd7bbb1ed9f4b922083cb042590b0885ffe22b"
- }
- },
- "upgrade": true,
- "reason": "system-test completed",
- "at": 1510830684960
- }
- },
- {
- "jobType": "component",
- "lastCompleted": {
- "id": 849,
- "version": "6.174.156",
- "upgrade": false,
- "reason": "Application commit",
- "at": 1511217733555
- },
- "lastSuccess": {
- "id": 849,
- "version": "6.174.156",
- "upgrade": false,
- "reason": "Application commit",
- "at": 1511217733555
- }
- },
- {
- "jobType": "production-us-east-3",
- "lastTriggered": {
- "id": -1,
- "version": "6.173.62",
- "revision": {
- "applicationPackageHash": "9db423e1021d7b452d37ec6372bc757d9c1bda87",
- "sourceRevision": {
- "repositoryField": "git@git.host:user/repo.git",
- "branchField": "origin/master",
- "commitField": "49cd7bbb1ed9f4b922083cb042590b0885ffe22b"
- }
- },
- "upgrade": true,
- "reason": "staging-test completed",
- "at": 1510830685127
- },
- "lastCompleted": {
- "id": 923,
- "version": "6.173.62",
- "revision": {
- "applicationPackageHash": "9db423e1021d7b452d37ec6372bc757d9c1bda87",
- "sourceRevision": {
- "repositoryField": "git@git.host:user/repo.git",
- "branchField": "origin/master",
- "commitField": "49cd7bbb1ed9f4b922083cb042590b0885ffe22b"
- }
- },
- "upgrade": true,
- "reason": "staging-test completed",
- "at": 1510837650046
- },
- "lastSuccess": {
- "id": 923,
- "version": "6.173.62",
- "revision": {
- "applicationPackageHash": "9db423e1021d7b452d37ec6372bc757d9c1bda87",
- "sourceRevision": {
- "repositoryField": "git@git.host:user/repo.git",
- "branchField": "origin/master",
- "commitField": "49cd7bbb1ed9f4b922083cb042590b0885ffe22b"
- }
- },
- "upgrade": true,
- "reason": "staging-test completed",
- "at": 1510837650046
- }
- },
- {
- "jobType": "production-us-west-1",
- "lastTriggered": {
- "id": -1,
- "version": "6.173.62",
- "revision": {
- "applicationPackageHash": "9db423e1021d7b452d37ec6372bc757d9c1bda87",
- "sourceRevision": {
- "repositoryField": "git@git.host:user/repo.git",
- "branchField": "origin/master",
- "commitField": "49cd7bbb1ed9f4b922083cb042590b0885ffe22b"
- }
- },
- "upgrade": true,
- "reason": "production-us-east-3 completed",
- "at": 1510837650139
- },
- "lastCompleted": {
- "id": 646,
- "version": "6.173.62",
- "revision": {
- "applicationPackageHash": "9db423e1021d7b452d37ec6372bc757d9c1bda87",
- "sourceRevision": {
- "repositoryField": "git@git.host:user/repo.git",
- "branchField": "origin/master",
- "commitField": "49cd7bbb1ed9f4b922083cb042590b0885ffe22b"
- }
- },
- "upgrade": true,
- "reason": "production-us-east-3 completed",
- "at": 1510843559162
- },
- "lastSuccess": {
- "id": 646,
- "version": "6.173.62",
- "revision": {
- "applicationPackageHash": "9db423e1021d7b452d37ec6372bc757d9c1bda87",
- "sourceRevision": {
- "repositoryField": "git@git.host:user/repo.git",
- "branchField": "origin/master",
- "commitField": "49cd7bbb1ed9f4b922083cb042590b0885ffe22b"
- }
- },
- "upgrade": true,
- "reason": "production-us-east-3 completed",
- "at": 1510843559162
- }
- },
- {
- "jobType": "system-test",
- "jobError": "unknown",
- "lastTriggered": {
- "id": -1,
- "version": "6.173.62",
- "revision": {
- "applicationPackageHash": "ec548fa61cbfab7a270a51d46b1263ec1be5d9a8",
- "sourceRevision": {
- "repositoryField": "git@git.host:user/repo.git",
- "branchField": "origin/master",
- "commitField": "234f3e4e77049d0b9538c9e1b356d17eb1dedb6a"
- }
- },
- "upgrade": false,
- "reason": "Available change in component",
- "at": 1511256608649
- },
- "lastCompleted": {
- "id": 1686,
- "version": "6.173.62",
- "revision": {
- "applicationPackageHash": "ec548fa61cbfab7a270a51d46b1263ec1be5d9a8",
- "sourceRevision": {
- "repositoryField": "git@git.host:user/repo.git",
- "branchField": "origin/master",
- "commitField": "234f3e4e77049d0b9538c9e1b356d17eb1dedb6a"
- }
- },
- "upgrade": false,
- "reason": "Available change in component",
- "at": 1511256603353
- },
- "firstFailing": {
- "id": 1659,
- "version": "6.173.62",
- "revision": {
- "applicationPackageHash": "ec548fa61cbfab7a270a51d46b1263ec1be5d9a8",
- "sourceRevision": {
- "repositoryField": "git@git.host:user/repo.git",
- "branchField": "origin/master",
- "commitField": "234f3e4e77049d0b9538c9e1b356d17eb1dedb6a"
- }
- },
- "upgrade": false,
- "reason": "component completed",
- "at": 1511219070725
- },
- "lastSuccess": {
- "id": 1658,
- "version": "6.173.62",
- "revision": {
- "applicationPackageHash": "9db423e1021d7b452d37ec6372bc757d9c1bda87",
- "sourceRevision": {
- "repositoryField": "git@git.host:user/repo.git",
- "branchField": "origin/master",
- "commitField": "49cd7bbb1ed9f4b922083cb042590b0885ffe22b"
- }
- },
- "upgrade": true,
- "reason": "Upgrading to 6.173.62",
- "at": 1511175754163
- }
- }
- ]
- },
- "deployingField": {
- "applicationPackageHash": "ec548fa61cbfab7a270a51d46b1263ec1be5d9a8",
- "sourceRevision": {
- "repositoryField": "git@git.host:user/repo.git",
- "branchField": "origin/master",
- "commitField": "234f3e4e77049d0b9538c9e1b356d17eb1dedb6a"
- }
- },
- "outstandingChangeField": false,
- "queryQuality": 100,
- "writeQuality": 99.99894341115082
-}