summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Bratseth <jonbratseth@yahoo.com>2018-01-29 10:05:43 +0100
committerGitHub <noreply@github.com>2018-01-29 10:05:43 +0100
commit89e160f6924c41e182fad7af44a409bef8604440 (patch)
tree4144559af991b7072c3dbb6046ca884adfdb61dc
parent13b092d7ccb756bad38b7ee26fb781ace108e51c (diff)
parent3dc07725bd350e6d7e7cc84265b962e3faa5a0f2 (diff)
Merge pull request #4790 from vespa-engine/bratseth/cleanup-change
Bratseth/cleanup change
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Application.java57
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java19
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedApplication.java12
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationList.java26
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationVersion.java22
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Change.java148
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/DeploymentJobs.java12
-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.java24
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentOrder.java2
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java87
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployer.java9
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Upgrader.java15
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializer.java76
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java48
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java61
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java26
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java11
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployerTest.java12
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployerTest.java14
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java31
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java36
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-deployment-cancelled.json2
23 files changed, 359 insertions, 393 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 c054d81db35..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
@@ -13,7 +13,6 @@ import com.yahoo.vespa.hosted.controller.api.integration.organization.IssueId;
import com.yahoo.vespa.hosted.controller.application.ApplicationRotation;
import com.yahoo.vespa.hosted.controller.application.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.application.Change;
-import com.yahoo.vespa.hosted.controller.application.Change.VersionChange;
import com.yahoo.vespa.hosted.controller.application.Deployment;
import com.yahoo.vespa.hosted.controller.application.DeploymentJobs;
import com.yahoo.vespa.hosted.controller.rotation.RotationId;
@@ -30,9 +29,9 @@ import java.util.stream.Collectors;
/**
* An instance of an application.
- *
+ *
* This is immutable.
- *
+ *
* @author bratseth
*/
public class Application {
@@ -42,7 +41,7 @@ public class Application {
private final ValidationOverrides validationOverrides;
private final Map<ZoneId, Deployment> deployments;
private final DeploymentJobs deploymentJobs;
- private final Optional<Change> deploying;
+ private final Change change;
private final boolean outstandingChange;
private final Optional<IssueId> ownershipIssueId;
private final ApplicationMetrics metrics;
@@ -52,22 +51,22 @@ public class Application {
public Application(ApplicationId id) {
this(id, DeploymentSpec.empty, ValidationOverrides.empty, Collections.emptyMap(),
new DeploymentJobs(Optional.empty(), Collections.emptyList(), Optional.empty()),
- Optional.empty(), false, Optional.empty(), new ApplicationMetrics(0, 0),
+ Change.empty(), false, Optional.empty(), new ApplicationMetrics(0, 0),
Optional.empty());
}
/** Used from persistence layer: Do not use */
- public Application(ApplicationId id, DeploymentSpec deploymentSpec, ValidationOverrides validationOverrides,
- List<Deployment> deployments, DeploymentJobs deploymentJobs, Optional<Change> deploying,
+ public Application(ApplicationId id, DeploymentSpec deploymentSpec, ValidationOverrides validationOverrides,
+ List<Deployment> deployments, DeploymentJobs deploymentJobs, Change change,
boolean outstandingChange, Optional<IssueId> ownershipIssueId, ApplicationMetrics metrics,
Optional<RotationId> rotation) {
- this(id, deploymentSpec, validationOverrides,
+ this(id, deploymentSpec, validationOverrides,
deployments.stream().collect(Collectors.toMap(Deployment::zone, d -> d)),
- deploymentJobs, deploying, outstandingChange, ownershipIssueId, metrics, rotation);
+ deploymentJobs, change, outstandingChange, ownershipIssueId, metrics, rotation);
}
Application(ApplicationId id, DeploymentSpec deploymentSpec, ValidationOverrides validationOverrides,
- Map<ZoneId, Deployment> deployments, DeploymentJobs deploymentJobs, Optional<Change> deploying,
+ Map<ZoneId, Deployment> deployments, DeploymentJobs deploymentJobs, Change change,
boolean outstandingChange, Optional<IssueId> ownershipIssueId, ApplicationMetrics metrics,
Optional<RotationId> rotation) {
Objects.requireNonNull(id, "id cannot be null");
@@ -75,7 +74,7 @@ public class Application {
Objects.requireNonNull(validationOverrides, "validationOverrides cannot be null");
Objects.requireNonNull(deployments, "deployments cannot be null");
Objects.requireNonNull(deploymentJobs, "deploymentJobs cannot be null");
- Objects.requireNonNull(deploying, "deploying cannot be null");
+ Objects.requireNonNull(change, "change cannot be null");
Objects.requireNonNull(metrics, "metrics cannot be null");
Objects.requireNonNull(rotation, "rotation cannot be null");
this.id = id;
@@ -83,7 +82,7 @@ public class Application {
this.validationOverrides = validationOverrides;
this.deployments = ImmutableMap.copyOf(deployments);
this.deploymentJobs = deploymentJobs;
- this.deploying = deploying;
+ this.change = change;
this.outstandingChange = outstandingChange;
this.ownershipIssueId = ownershipIssueId;
this.metrics = metrics;
@@ -91,24 +90,24 @@ public class Application {
}
public ApplicationId id() { return id; }
-
- /**
- * Returns the last deployed deployment spec of this application,
- * or the empty deployment spec if it has never been deployed
+
+ /**
+ * Returns the last deployed deployment spec of this application,
+ * or the empty deployment spec if it has never been deployed
*/
public DeploymentSpec deploymentSpec() { return deploymentSpec; }
/**
- * Returns the last deployed validation overrides of this application,
+ * Returns the last deployed validation overrides of this application,
* or the empty validation overrides if it has never been deployed
* (or was deployed with an empty/missing validation overrides)
*/
public ValidationOverrides validationOverrides() { return validationOverrides; }
-
+
/** Returns an immutable map of the current deployments of this */
public Map<ZoneId, Deployment> deployments() { return deployments; }
- /**
+ /**
* Returns an immutable map of the current *production* deployments of this
* (deployments also includes manually deployed environments)
*/
@@ -121,10 +120,10 @@ public class Application {
public DeploymentJobs deploymentJobs() { return deploymentJobs; }
/**
- * Returns the change that is currently in the process of being deployed on this application,
- * or empty if no change is currently being deployed.
+ * Returns the change that should currently be deployed for this application,
+ * which is empty when no change is in progress.
*/
- public Optional<Change> deploying() { return deploying; }
+ public Change change() { return change; }
/**
* Returns whether this has an outstanding change (in the source repository), which
@@ -152,10 +151,7 @@ public class Application {
/** Returns the version a new deployment to this zone should use for this application */
public Version deployVersionIn(ZoneId zone, Controller controller) {
- if (deploying().isPresent() && deploying().get() instanceof VersionChange)
- return ((Change.VersionChange) deploying().get()).version();
-
- return versionIn(zone, controller);
+ return change.platform().orElse(versionIn(zone, controller));
}
/** Returns the current version this application has, or if none; should use, in the given zone */
@@ -166,8 +162,13 @@ public class Application {
/** 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 (deploying().isPresent() && deploying().get() instanceof Change.ApplicationChange)
- return ((Change.ApplicationChange) deploying().get()).version();
+ if (change().application().isPresent()) {
+ ApplicationVersion version = change().application().get();
+ 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 89b134cc228..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
@@ -39,7 +39,6 @@ import com.yahoo.vespa.hosted.controller.api.integration.routing.RoutingGenerato
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.JobReport;
@@ -292,7 +291,7 @@ public class ApplicationController {
version = application.versionIn(zone, controller);
} else if (canDeployDirectlyTo(zone, options)) {
version = options.vespaVersion.map(Version::new).orElse(controller.systemVersion());
- } else if ( ! application.deploying().isPresent() && ! zone.environment().isManuallyDeployed()) {
+ } else if (! application.change().isPresent() && ! zone.environment().isManuallyDeployed()) {
return unexpectedDeployment(applicationId, zone, applicationPackageFromDeployer);
} else {
version = application.deployVersionIn(zone, controller);
@@ -322,9 +321,9 @@ public class ApplicationController {
validate(applicationPackage.deploymentSpec());
// TODO: Remove after introducing new application version number
- if (!options.deployCurrentVersion && applicationPackageFromDeployer.isPresent()) {
- if (application.deploying().isPresent() && application.deploying().get() instanceof Change.ApplicationChange) {
- application = application.withDeploying(Optional.of(Change.ApplicationChange.of(applicationVersion)));
+ if ( ! options.deployCurrentVersion && applicationPackageFromDeployer.isPresent()) {
+ if (application.change().application().isPresent()) {
+ application = application.withDeploying(application.change().with(applicationVersion));
}
if (!canDeployDirectlyTo(zone, options) && jobType.isPresent()) {
// Update with (potentially) missing information about what we triggered:
@@ -333,10 +332,10 @@ public class ApplicationController {
// for future use.
JobStatus.JobRun triggering = getOrCreateTriggering(application, version, jobType.get());
application = application.withJobTriggering(jobType.get(),
- application.deploying(),
+ application.change(),
triggering.at(),
version,
- Optional.of(applicationVersion),
+ applicationVersion,
triggering.reason());
}
}
@@ -359,9 +358,9 @@ public class ApplicationController {
// Validate automated deployment
if (!canDeployDirectlyTo(zone, options)) {
- if (!application.deploymentJobs().isDeployableTo(zone.environment(), application.deploying())) {
+ if (!application.deploymentJobs().isDeployableTo(zone.environment(), application.change())) {
throw new IllegalArgumentException("Rejecting deployment of " + application + " to " + zone +
- " as " + application.deploying().get() + " is not tested");
+ " as " + application.change() + " is not tested");
}
Deployment existingDeployment = application.deployments().get(zone);
if (zone.environment().isProduction() && existingDeployment != null &&
@@ -474,7 +473,7 @@ public class ApplicationController {
}
private JobStatus.JobRun incompleteTriggeringEvent(Version version) {
- return new JobStatus.JobRun(-1, version, Optional.empty(), false, "", clock.instant());
+ return new JobStatus.JobRun(-1, version, ApplicationVersion.unknown, false, "", clock.instant());
}
private DeployOptions withVersion(Version version, DeployOptions options) {
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 b50ecb82c50..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
@@ -64,8 +64,8 @@ public class LockedApplication extends Application {
return new LockedApplication(new Builder(this).with(deploymentJobs().withCompletion(report, notificationTime, controller)));
}
- public LockedApplication withJobTriggering(JobType type, Optional<Change> change, Instant triggerTime,
- Version version, Optional<ApplicationVersion> applicationVersion,
+ public LockedApplication withJobTriggering(JobType type, Change change, Instant triggerTime,
+ Version version, ApplicationVersion applicationVersion,
String reason) {
return new LockedApplication(new Builder(this).with(deploymentJobs().withTriggering(type, change, version, applicationVersion, reason, triggerTime)));
}
@@ -119,7 +119,7 @@ public class LockedApplication extends Application {
return new LockedApplication(new Builder(this).with(validationOverrides));
}
- public LockedApplication withDeploying(Optional<Change> deploying) {
+ public LockedApplication withDeploying(Change deploying) {
return new LockedApplication(new Builder(this).withDeploying(deploying));
}
@@ -166,7 +166,7 @@ public class LockedApplication extends Application {
private ValidationOverrides validationOverrides;
private Map<ZoneId, Deployment> deployments;
private DeploymentJobs deploymentJobs;
- private Optional<Change> deploying;
+ private Change deploying;
private boolean hasOutstandingChange;
private Optional<IssueId> ownershipIssueId;
private ApplicationMetrics metrics;
@@ -178,7 +178,7 @@ public class LockedApplication extends Application {
this.validationOverrides = application.validationOverrides();
this.deployments = application.deployments();
this.deploymentJobs = application.deploymentJobs();
- this.deploying = application.deploying();
+ this.deploying = application.change();
this.hasOutstandingChange = application.hasOutstandingChange();
this.ownershipIssueId = application.ownershipIssueId();
this.metrics = application.metrics();
@@ -205,7 +205,7 @@ public class LockedApplication extends Application {
return this;
}
- private Builder withDeploying(Optional<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/ApplicationList.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationList.java
index f8c7319fabc..777cb4011b6 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationList.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationList.java
@@ -17,7 +17,7 @@ import java.util.stream.Stream;
/**
* A list of applications which can be filtered in various ways.
- *
+ *
* @author bratseth
*/
public class ApplicationList {
@@ -27,9 +27,9 @@ public class ApplicationList {
private ApplicationList(Iterable<Application> applications) {
this.list = ImmutableList.copyOf(applications);
}
-
+
// ----------------------------------- Factories
-
+
public static ApplicationList from(Iterable<Application> applications) {
return new ApplicationList(applications);
}
@@ -54,7 +54,7 @@ public class ApplicationList {
/** Returns the subset of applications which are currently upgrading (to any version) */
public ApplicationList upgrading() {
- return listOf(list.stream().filter(ApplicationList::isUpgrading));
+ return listOf(list.stream().filter(application -> application.change().platform().isPresent()));
}
/** Returns the subset of applications which are currently upgrading to the given version */
@@ -67,7 +67,7 @@ public class ApplicationList {
return listOf(list.stream().filter(application -> ! isUpgradingTo(version, application)));
}
- /**
+ /**
* Returns the subset of applications which are currently not upgrading to the given version,
* or returns all if no version is specified
*/
@@ -78,7 +78,7 @@ public class ApplicationList {
/** Returns the subset of applications which is currently not deploying a change */
public ApplicationList notDeploying() {
- return listOf(list.stream().filter(application -> ! application.deploying().isPresent()));
+ return listOf(list.stream().filter(application -> ! application.change().isPresent()));
}
/** Returns the subset of applications which currently does not have any failing jobs */
@@ -125,7 +125,7 @@ public class ApplicationList {
public ApplicationList without(UpgradePolicy policy) {
return listOf(list.stream().filter(a -> a.deploymentSpec().upgradePolicy() != policy));
}
-
+
/** Returns the subset of applications which have at least one deployment on a lower version than the given one */
public ApplicationList onLowerVersionThan(Version version) {
return listOf(list.stream()
@@ -134,7 +134,7 @@ public class ApplicationList {
}
/**
- * Returns the subset of applications which are not pull requests:
+ * Returns the subset of applications which are not pull requests:
* Pull requests changes the application instance name to (default-pr)?[pull-request-number]
*/
public ApplicationList notPullRequest() {
@@ -170,16 +170,8 @@ public class ApplicationList {
// ----------------------------------- Internal helpers
- private static boolean isUpgrading(Application application) {
- if ( ! (application.deploying().isPresent()) ) return false;
- if ( ! (application.deploying().get() instanceof Change.VersionChange) ) return false;
- return true;
- }
-
private static boolean isUpgradingTo(Version version, Application application) {
- if ( ! (application.deploying().isPresent()) ) return false;
- if ( ! (application.deploying().get() instanceof Change.VersionChange) ) return false;
- return ((Change.VersionChange)application.deploying().get()).version().equals(version);
+ return application.change().platform().equals(Optional.of(version));
}
private static boolean failingOn(Version version, Application application) {
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 aee178af275..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
@@ -13,15 +13,25 @@ import java.util.Optional;
*/
public class ApplicationVersion {
+ // TODO: Remove the need for this
+ public static final ApplicationVersion unknown = new ApplicationVersion();
+
// Never changes. Only used to create a valid version number for the bundle
private static final String majorVersion = "1.0";
// 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;
+ private ApplicationVersion() {
+ this.applicationPackageHash = Optional.empty();
+ this.source = Optional.empty();
+ this.buildNumber = Optional.empty();
+ }
+
private ApplicationVersion(Optional<String> applicationPackageHash, Optional<SourceRevision> source,
Optional<Long> buildNumber) {
Objects.requireNonNull(applicationPackageHash, "applicationPackageHash cannot be null");
@@ -30,14 +40,14 @@ public class ApplicationVersion {
if (buildNumber.isPresent() && !source.isPresent()) {
throw new IllegalArgumentException("both buildNumber and source must be set if buildNumber is set");
}
- if (!buildNumber.isPresent() && !applicationPackageHash.isPresent()) {
+ if ( ! buildNumber.isPresent() && ! applicationPackageHash.isPresent()) {
throw new IllegalArgumentException("applicationPackageHash must be given if buildNumber is unset");
}
this.applicationPackageHash = applicationPackageHash;
this.source = source;
this.buildNumber = buildNumber;
}
-
+
/** Create an application package revision where there is no information about its source */
public static ApplicationVersion from(String applicationPackageHash) {
return new ApplicationVersion(Optional.of(applicationPackageHash), Optional.empty(), Optional.empty());
@@ -61,7 +71,7 @@ public class ApplicationVersion {
return String.format("%s.%d-%s", majorVersion, buildNumber.get(), abbreviateCommit(source.get().commit()));
}
- /**
+ /**
* 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)
*/
@@ -69,17 +79,17 @@ public class ApplicationVersion {
/** Returns the build number that built this version */
public Optional<Long> buildNumber() { return buildNumber; }
-
+
@Override
public int hashCode() { return applicationPackageHash.hashCode(); }
-
+
@Override
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() {
if (buildNumber.isPresent()) {
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 08291373656..13d66c8d083 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
@@ -9,98 +9,90 @@ import java.util.Objects;
import java.util.Optional;
/**
- * A change to an application
- *
+ * The changes to an application we currently wish to complete deploying.
+ * A goal of the system is to deploy platform and application versions separately.
+ * However, this goal must some times be traded against others, so a change can
+ * consist of both an application and platform version change.
+ *
+ * This is immutable.
+ *
* @author bratseth
*/
-public abstract class Change {
+public final class Change {
+
+ private static final Change empty = new Change(Optional.empty(), Optional.empty());
+
+ /** The platform version we are upgrading to, or empty if none */
+ private final Optional<Version> platform;
+
+ /** The application version we are changing to, or empty if none */
+ private final Optional<ApplicationVersion> application;
+
+ private Change(Optional<Version> platform, Optional<ApplicationVersion> application) {
+ Objects.requireNonNull(platform, "platform cannot be null");
+ Objects.requireNonNull(application, "application cannot be null");
+ this.platform = platform;
+ this.application = application;
+ }
/** Returns true if this change is blocked by the given spec at the given instant */
- public abstract boolean blockedBy(DeploymentSpec deploymentSpec, Instant instant);
-
- /** A change to the application package version of an application */
- public static class ApplicationChange extends Change {
-
- // TODO: Make non-optional
- private final Optional<ApplicationVersion> version;
-
- private ApplicationChange(Optional<ApplicationVersion> version) {
- Objects.requireNonNull(version, "version cannot be null");
- this.version = version;
- }
-
- /** The application package version in this change, or empty if not known yet */
- public Optional<ApplicationVersion> version() { return version; }
-
- @Override
- public boolean blockedBy(DeploymentSpec deploymentSpec, Instant instant) {
- return ! deploymentSpec.canChangeRevisionAt(instant);
- }
-
- @Override
- public int hashCode() { return version.hashCode(); }
-
- @Override
- public boolean equals(Object other) {
- if (this == other) return true;
- if ( ! (other instanceof ApplicationChange)) return false;
- return ((ApplicationChange)other).version.equals(this.version);
- }
-
- /**
- * Creates an application change which we don't know anything about.
- * We are notified that a change has occurred by completion of the component job
- * but do not get to know about what the change is until a subsequent deployment
- * happens.
- */
- public static ApplicationChange unknown() {
- return new ApplicationChange(Optional.empty());
- }
-
- public static ApplicationChange of(ApplicationVersion version) {
- return new ApplicationChange(Optional.of(version));
- }
-
- @Override
- public String toString() {
- return "application change to " + version.map(ApplicationVersion::toString).orElse("an unknown version");
- }
-
+ public boolean blockedBy(DeploymentSpec deploymentSpec, Instant instant) {
+ if (platform.isPresent() && ! deploymentSpec.canUpgradeAt(instant)) return true;
+ if (application.isPresent() && ! deploymentSpec.canChangeRevisionAt(instant)) return true;
+ return false;
}
- /** A change to the Vespa version running an application */
- public static class VersionChange extends Change {
+ /** Returns whether a change shoudl currently be deployed */
+ public boolean isPresent() {
+ return platform.isPresent() || application.isPresent();
+ }
- private final Version version;
+ /** Returns the platform version change which should currently be deployed, if any */
+ public Optional<Version> platform() { return platform; }
- public VersionChange(Version version) {
- Objects.requireNonNull(version, "version cannot be null");
- this.version = version;
- }
+ /** Returns the application version change which should currently be deployed, if any */
+ public Optional<ApplicationVersion> application() { return application; }
- /** The Vespa version this changes to */
- public Version version() { return version; }
+ /** Returns an instance representing no change */
+ public static Change empty() { return empty; }
- @Override
- public boolean blockedBy(DeploymentSpec deploymentSpec, Instant instant) {
- return ! deploymentSpec.canUpgradeAt(instant);
- }
+ /** 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));
+ }
- @Override
- public int hashCode() { return version.hashCode(); }
+ @Override
+ public int hashCode() { return Objects.hash(platform, application); }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) return true;
+ if ( ! (other instanceof Change)) return false;
+ Change o = (Change)other;
+ if ( ! o.platform.equals(this.platform)) return false;
+ if ( ! o.application.equals(this.application)) return false;
+ return true;
+ }
- @Override
- public boolean equals(Object other) {
- if (this == other) return true;
- if ( ! (other instanceof VersionChange)) return false;
- return ((VersionChange)other).version.equals(this.version);
- }
+ @Override
+ public String toString() {
+ String platformString = platform.map(v -> "upgrade to " + v).orElse(null);
+ String applicationString = application.map(v -> "application change to " + v).orElse(null);
+ if (platformString != null && applicationString != null)
+ return platformString + " and " + applicationString;
+ if (platformString != null)
+ return platformString;
+ if (applicationString != null)
+ return applicationString;
+ return "no change";
+ }
- @Override
- public String toString() {
- return "version change to " + version;
- }
+ public static Change of(ApplicationVersion applicationVersion) {
+ return new Change(Optional.empty(), Optional.of(applicationVersion));
+ }
+ public static Change of(Version platformChange) {
+ return new Change(Optional.of(platformChange), Optional.empty());
}
}
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 c432503a790..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
@@ -65,9 +65,9 @@ public class DeploymentJobs {
}
public DeploymentJobs withTriggering(JobType jobType,
- Optional<Change> change,
+ Change change,
Version version,
- Optional<ApplicationVersion> applicationVersion,
+ ApplicationVersion applicationVersion,
String reason,
Instant triggerTime) {
Map<JobType, JobStatus> status = new LinkedHashMap<>(this.status);
@@ -75,7 +75,7 @@ public class DeploymentJobs {
if (job == null) job = JobStatus.initial(jobType);
return job.withTriggering(version,
applicationVersion,
- change.isPresent() && change.get() instanceof Change.VersionChange,
+ change.platform().isPresent(),
reason,
triggerTime);
});
@@ -117,14 +117,14 @@ public class DeploymentJobs {
}
/** Returns whether change can be deployed to the given environment */
- public boolean isDeployableTo(Environment environment, Optional<Change> change) {
+ public boolean isDeployableTo(Environment environment, Change change) {
if (environment == null || ! change.isPresent()) {
return true;
}
if (environment == Environment.staging) {
- return isSuccessful(change.get(), JobType.systemTest);
+ return isSuccessful(change, JobType.systemTest);
} else if (environment == Environment.prod) {
- return isSuccessful(change.get(), JobType.stagingTest);
+ return isSuccessful(change, JobType.stagingTest);
}
return true; // other environments do not have any preconditions
}
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 932229b6bb6..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().isPresent()) 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 71c4a380a29..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
@@ -55,7 +55,7 @@ public class JobStatus {
return new JobStatus(type, Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty());
}
- public JobStatus withTriggering(Version version, Optional<ApplicationVersion> applicationVersion,
+ 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)),
lastCompleted, firstFailing, lastSuccess);
@@ -63,12 +63,12 @@ public class JobStatus {
public JobStatus withCompletion(long runId, Optional<DeploymentJobs.JobError> jobError, Instant completionTime, Controller controller) {
Version version;
- Optional<ApplicationVersion> applicationVersion;
+ ApplicationVersion applicationVersion;
boolean upgrade;
String reason;
if (type == DeploymentJobs.JobType.component) { // not triggered by us
version = controller.systemVersion();
- applicationVersion = Optional.empty();
+ applicationVersion = ApplicationVersion.unknown;
upgrade = false;
reason = "Application commit";
}
@@ -167,13 +167,12 @@ public class JobStatus {
private final long id;
private final Version version;
- // TODO: Make non-optional after introducing new application version number
- private final Optional<ApplicationVersion> applicationVersion;
+ private final ApplicationVersion applicationVersion;
private final boolean upgrade;
private final String reason;
private final Instant at;
- public JobRun(long id, Version version, Optional<ApplicationVersion> applicationVersion,
+ public JobRun(long id, Version version, ApplicationVersion applicationVersion,
boolean upgrade, String reason, Instant at) {
Objects.requireNonNull(version, "version cannot be null");
Objects.requireNonNull(applicationVersion, "applicationVersion cannot be null");
@@ -199,7 +198,7 @@ public class JobStatus {
public Version version() { return version; }
/** Returns the application version used for this run, or empty when not known */
- public Optional<ApplicationVersion> applicationVersion() { return applicationVersion; }
+ public ApplicationVersion applicationVersion() { return applicationVersion; }
/** Returns a human-readable reason for this particular job run */
public String reason() { return reason; }
@@ -210,14 +209,9 @@ public class JobStatus {
// TODO: Consider a version and application version for each JobStatus, to compare against a Target (instead of Change, which is, really, a Target).
/** Returns whether the job last completed for the given change */
public boolean lastCompletedWas(Change change) {
- if (change instanceof Change.ApplicationChange) {
- Change.ApplicationChange applicationChange = (Change.ApplicationChange) change;
- return applicationVersion().equals(applicationChange.version());
- } else if (change instanceof Change.VersionChange) {
- Change.VersionChange versionChange = (Change.VersionChange) change;
- return version().equals(versionChange.version());
- }
- throw new IllegalArgumentException("Unexpected change: " + change.getClass());
+ if (change.platform().isPresent() && ! change.platform().get().equals(version())) return false;
+ if (change.application().isPresent() && ! change.application().get().equals(applicationVersion)) return false;
+ return true;
}
@Override
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentOrder.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentOrder.java
index d506e8f3dcd..66bb05df308 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentOrder.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentOrder.java
@@ -46,7 +46,7 @@ public class DeploymentOrder {
/** Returns a list of jobs to trigger after the given job */
// TODO: This does too much - should just tell us the order, as advertised
public List<JobType> nextAfter(JobType job, LockedApplication application) {
- if ( ! application.deploying().isPresent()) { // Change was cancelled
+ if ( ! application.change().isPresent()) { // Change was cancelled
return Collections.emptyList();
}
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 09768796445..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
@@ -12,7 +12,6 @@ import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.application.ApplicationList;
import com.yahoo.vespa.hosted.controller.application.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.application.Change;
-import com.yahoo.vespa.hosted.controller.application.Change.VersionChange;
import com.yahoo.vespa.hosted.controller.application.Deployment;
import com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobError;
import com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobReport;
@@ -87,17 +86,11 @@ public class DeploymentTrigger {
if (report.jobType() == JobType.component) {
if (acceptNewApplicationVersionNow(application)) {
// Set this as the change we are doing, unless we are already pushing a platform change
- if ( ! ( application.deploying().isPresent() &&
- application.deploying().get() instanceof Change.VersionChange)) {
- Change.ApplicationChange applicationChange = Change.ApplicationChange.unknown();
- // TODO: Remove guard when source is always reported by component
- if (report.sourceRevision().isPresent()) {
- applicationChange = Change.ApplicationChange.of(
- ApplicationVersion.from(report.sourceRevision().get(),
- report.buildNumber())
- );
- }
- application = application.withDeploying(Optional.of(applicationChange));
+ if ( ! ( application.change().platform().isPresent())) {
+ ApplicationVersion applicationVersion = ApplicationVersion.unknown;
+ if (report.sourceRevision().isPresent())
+ applicationVersion = ApplicationVersion.from(report.sourceRevision().get(), report.buildNumber());
+ application = application.withDeploying(Change.of(applicationVersion));
}
}
else { // postpone
@@ -107,7 +100,7 @@ public class DeploymentTrigger {
}
else if (deploymentComplete(application)) {
// change completed
- application = application.withDeploying(Optional.empty());
+ application = application.withDeploying(Change.empty());
}
}
@@ -128,8 +121,8 @@ public class DeploymentTrigger {
/** Returns whether all production zones listed in deployment spec has this change (or a newer version, if upgrade) */
private boolean deploymentComplete(LockedApplication application) {
- if ( ! application.deploying().isPresent()) return true;
- Change change = application.deploying().get();
+ if ( ! application.change().isPresent()) return true;
+ Change change = application.change();
for (JobType job : order.jobsFrom(application.deploymentSpec())) {
if ( ! job.isProduction()) continue;
@@ -141,18 +134,15 @@ public class DeploymentTrigger {
if (deployment == null) return false;
// Check actual job outcome (the deployment)
- if (change instanceof VersionChange) {
- if (((VersionChange)change).version().isAfter(deployment.version())) return false; // later is ok
+ if (change.platform().isPresent()) {
+ if (change.platform().get().isAfter(deployment.version())) return false; // later is ok
}
- else if (((Change.ApplicationChange)change).version().isPresent()) {
- if ( ! ((Change.ApplicationChange)change).version().get().equals(deployment.applicationVersion())) return false;
+ 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() == ApplicationVersion.unknown) return false;
+ if ( ! change.application().get().equals(deployment.applicationVersion())) return false;
}
- else {
- return false; // If we don't yet know the application version we are deploying, then we are not complete
- }
-
}
-
return true;
}
@@ -168,14 +158,14 @@ public class DeploymentTrigger {
/** Find the next step to trigger if any, and triggers it */
public void triggerReadyJobs(LockedApplication application) {
- if ( ! application.deploying().isPresent()) return;
+ if ( ! application.change().isPresent()) return;
List<JobType> jobs = order.jobsFrom(application.deploymentSpec());
// Should the first step be triggered?
if ( ! jobs.isEmpty() && jobs.get(0).equals(JobType.systemTest) ) {
JobStatus systemTestStatus = application.deploymentJobs().jobStatus().get(JobType.systemTest);
- if (application.deploying().get() instanceof Change.VersionChange) {
- Version target = ((Change.VersionChange) application.deploying().get()).version();
+ if (application.change().platform().isPresent()) {
+ Version target = application.change().platform().get();
if (systemTestStatus == null
|| ! systemTestStatus.lastTriggered().isPresent()
|| ! systemTestStatus.isSuccess()
@@ -218,13 +208,11 @@ public class DeploymentTrigger {
* which is newer (different) than the one last completed successfully in next
*/
private boolean changesAvailable(Application application, JobStatus previous, JobStatus next) {
- if ( ! application.deploying().isPresent()) return false;
+ if ( ! application.change().isPresent()) return false;
if (next == null) return true;
- Change change = application.deploying().get();
-
- if (change instanceof Change.VersionChange) { // Propagate upgrade while making sure we never downgrade
- Version targetVersion = ((Change.VersionChange)change).version();
+ if (application.change().platform().isPresent()) { // Propagate upgrade while making sure we never downgrade
+ Version targetVersion = application.change().platform().get();
if (next.type().isTest()) {
// Is it not yet this job's turn to upgrade?
@@ -256,7 +244,7 @@ public class DeploymentTrigger {
else { // Application version changes do not need to handle downgrading
if ( ! previous.lastSuccess().isPresent()) return false;
if ( ! next.lastSuccess().isPresent()) return true;
- return previous.lastSuccess().get().applicationVersion().isPresent() &&
+ return previous.lastSuccess().get().applicationVersion() != ApplicationVersion.unknown &&
! previous.lastSuccess().get().applicationVersion().equals(next.lastSuccess().get().applicationVersion());
}
}
@@ -269,14 +257,13 @@ public class DeploymentTrigger {
*/
public void triggerChange(ApplicationId applicationId, Change change) {
applications().lockOrThrow(applicationId, application -> {
- if (application.deploying().isPresent() && ! application.deploymentJobs().hasFailures())
+ if (application.change().isPresent() && ! application.deploymentJobs().hasFailures())
throw new IllegalArgumentException("Could not start " + change + " on " + application + ": " +
- application.deploying().get() + " is already in progress");
- application = application.withDeploying(Optional.of(change));
- if (change instanceof Change.ApplicationChange)
+ application.change() + " is already in progress");
+ application = application.withDeploying(change);
+ if (change.application().isPresent())
application = application.withOutstandingChange(false);
- application = trigger(JobType.systemTest, application, false,
- (change instanceof Change.VersionChange ? "Upgrading to " + ((Change.VersionChange)change).version() : "Deploying " + change));
+ application = trigger(JobType.systemTest, application, false, change.toString());
applications().store(application);
});
}
@@ -289,7 +276,7 @@ public class DeploymentTrigger {
public void cancelChange(ApplicationId applicationId) {
applications().lockOrThrow(applicationId, application -> {
buildSystem.removeJobs(application.id());
- applications().store(application.withDeploying(Optional.empty()));
+ applications().store(application.withDeploying(Change.empty()));
});
}
@@ -353,7 +340,7 @@ public class DeploymentTrigger {
if (jobType == null) return application; // we are passed null when the last job has been reached
// Never allow untested changes to go through
// Note that this may happen because a new change catches up and prevents an older one from continuing
- if ( ! application.deploymentJobs().isDeployableTo(jobType.environment(), application.deploying())) {
+ if ( ! application.deploymentJobs().isDeployableTo(jobType.environment(), application.change())) {
log.warning(String.format("Want to trigger %s for %s with reason %s, but change is untested", jobType,
application, reason));
return application;
@@ -361,14 +348,14 @@ public class DeploymentTrigger {
if ( ! force && ! allowedTriggering(jobType, application)) return application;
log.info(String.format("Triggering %s for %s, %s: %s", jobType, application,
- application.deploying().map(d -> "deploying " + d).orElse("restarted deployment"),
+ application.change().isPresent() ? "deploying " + application.change() : "restarted deployment",
reason));
buildSystem.addJob(application.id(), jobType, first);
return application.withJobTriggering(jobType,
- application.deploying(),
+ application.change(),
clock.instant(),
application.deployVersionFor(jobType, controller),
- application.deployApplicationVersion(jobType, controller),
+ application.deployApplicationVersion(jobType, controller).orElse(ApplicationVersion.unknown),
reason);
}
@@ -379,12 +366,12 @@ public class DeploymentTrigger {
// this leads to some additional corner cases, and the possibility of blocking an application
// fix to a version upgrade, so not doing it now
- if (jobType.isProduction() && application.deploying().isPresent() &&
- application.deploying().get().blockedBy(application.deploymentSpec(), clock.instant())) return false;
+ if (jobType.isProduction() && application.change().isPresent() &&
+ application.change().blockedBy(application.deploymentSpec(), clock.instant())) return false;
// Don't downgrade or redeploy the same version in production needlessly
- if (application.deploying().isPresent() && application.deploying().get() instanceof VersionChange &&
- jobType.isProduction() && alreadyDeployed(((VersionChange) application.deploying().get()).version(), application, jobType)) return false;
+ if (application.change().platform().isPresent() &&
+ jobType.isProduction() && alreadyDeployed((application.change().platform().get()), application, jobType)) return false;
if (application.deploymentJobs().isRunning(jobType, jobTimeoutLimit())) return false;
if ( ! hasJob(jobType, application)) return false;
@@ -418,9 +405,9 @@ public class DeploymentTrigger {
}
private boolean acceptNewApplicationVersionNow(LockedApplication application) {
- if ( ! application.deploying().isPresent()) return true;
+ if ( ! application.change().isPresent()) return true;
- if (application.deploying().get() instanceof Change.ApplicationChange) return true; // more changes are ok
+ if (application.change().application().isPresent()) return true; // more application changes are ok
if (application.deploymentJobs().hasFailures()) return true; // allow changes to fix upgrade problems
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployer.java
index 4485a603f61..3dd63a511e1 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployer.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployer.java
@@ -4,17 +4,18 @@ package com.yahoo.vespa.hosted.controller.maintenance;
import com.yahoo.vespa.hosted.controller.Application;
import com.yahoo.vespa.hosted.controller.Controller;
import com.yahoo.vespa.hosted.controller.application.ApplicationList;
+import com.yahoo.vespa.hosted.controller.application.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.application.Change;
import java.time.Duration;
/**
* Deploys application changes which have been postponed due to an ongoing upgrade
- *
+ *
* @author bratseth
*/
public class OutstandingChangeDeployer extends Maintainer {
-
+
public OutstandingChangeDeployer(Controller controller, Duration interval, JobControl jobControl) {
super(controller, interval, jobControl);
}
@@ -23,9 +24,9 @@ public class OutstandingChangeDeployer extends Maintainer {
protected void maintain() {
ApplicationList applications = ApplicationList.from(controller().applications().asList()).notPullRequest();
for (Application application : applications.asList()) {
- if (application.hasOutstandingChange() && ! application.deploying().isPresent())
+ if (application.hasOutstandingChange() && ! application.change().isPresent())
controller().applications().deploymentTrigger().triggerChange(application.id(),
- Change.ApplicationChange.unknown());
+ Change.of(ApplicationVersion.unknown));
}
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Upgrader.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Upgrader.java
index 5b87f9eaa86..75f348904dd 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Upgrader.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Upgrader.java
@@ -20,7 +20,7 @@ import java.util.logging.Logger;
/**
* Maintenance job which schedules applications for Vespa version upgrade
- *
+ *
* @author bratseth
* @author mpolden
*/
@@ -39,7 +39,7 @@ public class Upgrader extends Maintainer {
* Schedule application upgrades. Note that this implementation must be idempotent.
*/
@Override
- public void maintain() {
+ public void maintain() {
// Determine target versions for each upgrade policy
Optional<Version> canaryTarget = controller().versionStatus().systemVersion().map(VespaVersion::versionNumber);
Optional<Version> defaultTarget = newestVersionWithConfidence(VespaVersion.Confidence.normal);
@@ -66,26 +66,25 @@ public class Upgrader extends Maintainer {
defaultTarget.ifPresent(target -> upgrade(applications().with(UpgradePolicy.defaultPolicy), target));
conservativeTarget.ifPresent(target -> upgrade(applications().with(UpgradePolicy.conservative), target));
}
-
+
private Optional<Version> newestVersionWithConfidence(VespaVersion.Confidence confidence) {
return reversed(controller().versionStatus().versions()).stream()
.filter(v -> v.confidence().equalOrHigherThan(confidence))
.findFirst()
.map(VespaVersion::versionNumber);
}
-
+
private List<VespaVersion> reversed(List<VespaVersion> versions) {
List<VespaVersion> reversed = new ArrayList<>(versions.size());
for (int i = 0; i < versions.size(); i++)
reversed.add(versions.get(versions.size() - 1 - i));
return reversed;
}
-
+
/** Returns a list of all applications */
private ApplicationList applications() { return ApplicationList.from(controller().applications().asList()); }
-
+
private void upgrade(ApplicationList applications, Version version) {
- Change.VersionChange change = new Change.VersionChange(version);
applications = applications.notPullRequest(); // Pull requests are deployed as separate applications to test then deleted; No need to upgrade
applications = applications.hasProductionDeployment();
applications = applications.onLowerVersionThan(version);
@@ -96,7 +95,7 @@ public class Upgrader extends Maintainer {
applications = applications.first(numberOfApplicationsToUpgrade()); // throttle upgrades
for (Application application : applications.asList()) {
try {
- controller().applications().deploymentTrigger().triggerChange(application.id(), change);
+ controller().applications().deploymentTrigger().triggerChange(application.id(), Change.of(version));
} catch (IllegalArgumentException e) {
log.log(Level.INFO, "Could not trigger change: " + Exceptions.toMessageString(e));
}
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 1514d98610a..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
@@ -38,7 +38,7 @@ import java.util.Optional;
/**
* Serializes applications to/from slime.
* This class is multithread safe.
- *
+ *
* @author bratseth
*/
public class ApplicationSerializer {
@@ -67,12 +67,12 @@ public class ApplicationSerializer {
private final String repositoryField = "repositoryField";
private final String branchField = "branchField";
private final String commitField = "commitField";
-
+
// DeploymentJobs fields
private final String projectIdField = "projectId";
private final String jobStatusField = "jobStatus";
private final String issueIdField = "jiraIssueId";
-
+
// JobStatus field
private final String jobTypeField = "jobType";
private final String errorField = "jobError";
@@ -80,7 +80,7 @@ public class ApplicationSerializer {
private final String lastCompletedField = "lastCompleted";
private final String firstFailingField = "firstFailing";
private final String lastSuccessField = "lastSuccess";
-
+
// JobRun fields
private final String jobRunIdField = "id";
private final String versionField = "version";
@@ -116,7 +116,7 @@ public class ApplicationSerializer {
// ------------------ Serialization
-
+
public Slime toSlime(Application application) {
Slime slime = new Slime();
Cursor root = slime.setObject();
@@ -125,7 +125,7 @@ public class ApplicationSerializer {
root.setString(validationOverridesField, application.validationOverrides().xmlForm());
deploymentsToSlime(application.deployments().values(), root.setArray(deploymentsField));
toSlime(application.deploymentJobs(), root.setObject(deploymentJobsField));
- toSlime(application.deploying(), root);
+ toSlime(application.change(), root);
root.setBool(outstandingChangeField, application.hasOutstandingChange());
application.ownershipIssueId().ifPresent(issueId -> root.setString(ownershipIssueIdField, issueId.value()));
root.setDouble(queryQualityField, application.metrics().queryServiceQuality());
@@ -138,7 +138,7 @@ public class ApplicationSerializer {
for (Deployment deployment : deployments)
deploymentToSlime(deployment, array.addObject());
}
-
+
private void deploymentToSlime(Deployment deployment, Cursor object) {
zoneIdToSlime(deployment.zone(), object.setObject(zoneField));
object.setString(versionField, deployment.version().toString());
@@ -196,19 +196,19 @@ public class ApplicationSerializer {
object.setString(environmentField, zone.environment().value());
object.setString(regionField, zone.region().value());
}
-
+
private void toSlime(ApplicationVersion applicationVersion, Cursor object) {
object.setString(applicationPackageHashField, applicationVersion.id());
if (applicationVersion.source().isPresent())
toSlime(applicationVersion.source().get(), object.setObject(sourceRevisionField));
}
-
+
private void toSlime(SourceRevision sourceRevision, Cursor object) {
object.setString(repositoryField, sourceRevision.repository());
object.setString(branchField, sourceRevision.branch());
object.setString(commitField, sourceRevision.commit());
}
-
+
private void toSlime(DeploymentJobs deploymentJobs, Cursor cursor) {
deploymentJobs.projectId().ifPresent(projectId -> cursor.setLong(projectIdField, projectId));
jobStatusToSlime(deploymentJobs.jobStatus().values(), cursor.setArray(jobStatusField));
@@ -219,7 +219,7 @@ public class ApplicationSerializer {
for (JobStatus jobStatus : jobStatuses)
toSlime(jobStatus, jobStatusArray.addObject());
}
-
+
private void toSlime(JobStatus jobStatus, Cursor object) {
object.setString(jobTypeField, jobStatus.type().jobName());
if (jobStatus.jobError().isPresent())
@@ -230,40 +230,40 @@ public class ApplicationSerializer {
jobRunToSlime(jobStatus.firstFailing(), object, firstFailingField);
jobRunToSlime(jobStatus.lastSuccess(), object, lastSuccessField);
}
-
+
private void jobRunToSlime(Optional<JobStatus.JobRun> jobRun, Cursor parent, String jobRunObjectName) {
if ( ! jobRun.isPresent()) return;
Cursor object = parent.setObject(jobRunObjectName);
object.setLong(jobRunIdField, jobRun.get().id());
object.setString(versionField, jobRun.get().version().toString());
- if ( jobRun.get().applicationVersion().isPresent())
- toSlime(jobRun.get().applicationVersion().get(), object.setObject(revisionField));
+ 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());
object.setLong(atField, jobRun.get().at().toEpochMilli());
}
-
- private void toSlime(Optional<Change> deploying, Cursor parentObject) {
+
+ private void toSlime(Change deploying, Cursor parentObject) {
if ( ! deploying.isPresent()) return;
Cursor object = parentObject.setObject(deployingField);
- if (deploying.get() instanceof Change.VersionChange)
- object.setString(versionField, ((Change.VersionChange)deploying.get()).version().toString());
- else if (((Change.ApplicationChange)deploying.get()).version().isPresent())
- toSlime(((Change.ApplicationChange)deploying.get()).version().get(), object);
+ if (deploying.platform().isPresent())
+ object.setString(versionField, deploying.platform().get().toString());
+ if (deploying.application().isPresent() && deploying.application().get() != ApplicationVersion.unknown)
+ toSlime(deploying.application().get(), object);
}
// ------------------ Deserialization
public Application fromSlime(Slime slime) {
Inspector root = slime.get();
-
+
ApplicationId id = ApplicationId.fromSerializedForm(root.field(idField).asString());
DeploymentSpec deploymentSpec = DeploymentSpec.fromXml(root.field(deploymentSpecField).asString(), false);
ValidationOverrides validationOverrides = ValidationOverrides.fromXml(root.field(validationOverridesField).asString());
List<Deployment> deployments = deploymentsFromSlime(root.field(deploymentsField));
DeploymentJobs deploymentJobs = deploymentJobsFromSlime(root.field(deploymentJobsField));
- Optional<Change> deploying = changeFromSlime(root.field(deployingField));
+ Change deploying = changeFromSlime(root.field(deployingField));
boolean outstandingChange = root.field(outstandingChangeField).asBool();
Optional<IssueId> ownershipIssueId = optionalString(root.field(ownershipIssueIdField)).map(IssueId::from);
ApplicationMetrics metrics = new ApplicationMetrics(root.field(queryQualityField).asDouble(),
@@ -282,7 +282,7 @@ public class ApplicationSerializer {
private Deployment deploymentFromSlime(Inspector deploymentObject) {
return new Deployment(zoneIdFromSlime(deploymentObject.field(zoneField)),
- applicationVersionFromSlime(deploymentObject.field(applicationPackageRevisionField)).get(),
+ applicationVersionFromSlime(deploymentObject.field(applicationPackageRevisionField)),
Version.fromString(deploymentObject.field(versionField).asString()),
Instant.ofEpochMilli(deploymentObject.field(deployTimeField).asLong()),
clusterUtilsMapFromSlime(deploymentObject.field(clusterUtilsField)),
@@ -340,14 +340,14 @@ public class ApplicationSerializer {
return ZoneId.from(object.field(environmentField).asString(), object.field(regionField).asString());
}
- private Optional<ApplicationVersion> applicationVersionFromSlime(Inspector object) {
- if ( ! object.valid()) return Optional.empty();
+ private ApplicationVersion applicationVersionFromSlime(Inspector object) {
+ if ( ! object.valid()) return ApplicationVersion.unknown;
String applicationPackageHash = object.field(applicationPackageHashField).asString();
Optional<SourceRevision> sourceRevision = sourceRevisionFromSlime(object.field(sourceRevisionField));
- return sourceRevision.isPresent() ? Optional.of(ApplicationVersion.from(applicationPackageHash, sourceRevision.get()))
- : Optional.of(ApplicationVersion.from(applicationPackageHash));
+ return sourceRevision.isPresent() ? ApplicationVersion.from(applicationPackageHash, sourceRevision.get())
+ : ApplicationVersion.from(applicationPackageHash);
}
-
+
private Optional<SourceRevision> sourceRevisionFromSlime(Inspector object) {
if ( ! object.valid()) return Optional.empty();
return Optional.of(new SourceRevision(object.field(repositoryField).asString(),
@@ -363,23 +363,25 @@ public class ApplicationSerializer {
return new DeploymentJobs(projectId, jobStatusList, issueId);
}
- private Optional<Change> changeFromSlime(Inspector object) {
- if ( ! object.valid()) return Optional.empty();
+ private Change changeFromSlime(Inspector object) {
+ if ( ! object.valid()) return Change.empty();
Inspector versionFieldValue = object.field(versionField);
+ Change change = Change.empty();
if (versionFieldValue.valid())
- return Optional.of(new Change.VersionChange(Version.fromString(versionFieldValue.asString())));
- else if (object.field(applicationPackageHashField).valid())
- return Optional.of(Change.ApplicationChange.of(applicationVersionFromSlime(object).get()));
- else
- return Optional.of(Change.ApplicationChange.unknown());
+ change = Change.of(Version.fromString(versionFieldValue.asString()));
+ 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);
+ return change;
}
-
+
private List<JobStatus> jobStatusListFromSlime(Inspector array) {
List<JobStatus> jobStatusList = new ArrayList<>();
array.traverse((ArrayTraverser) (int i, Inspector item) -> jobStatusList.add(jobStatusFromSlime(item)));
return jobStatusList;
}
-
+
private JobStatus jobStatusFromSlime(Inspector object) {
DeploymentJobs.JobType jobType = DeploymentJobs.JobType.fromJobName(object.field(jobTypeField).asString());
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 a489e1d9f63..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
@@ -98,7 +98,7 @@ import java.util.logging.Level;
/**
* This implements the application/v4 API which is used to deploy and manage applications
* on hosted Vespa.
- *
+ *
* @author bratseth
* @author mpolden
*/
@@ -123,7 +123,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
public Duration getTimeout() {
return Duration.ofMinutes(20); // deploys may take a long time;
}
-
+
@Override
public HttpResponse handle(HttpRequest request) {
try {
@@ -156,7 +156,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
return ErrorResponse.internalServerError(Exceptions.toMessageString(e));
}
}
-
+
private HttpResponse handleGET(HttpRequest request) {
Path path = new Path(request.getUri().getPath());
if (path.matches("/application/v4/")) return root(request);
@@ -213,7 +213,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
return setGlobalRotationOverride(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), true, request);
return ErrorResponse.notFoundError("Nothing at " + path);
}
-
+
private HttpResponse handleOPTIONS() {
// We implement this to avoid redirect loops on OPTIONS requests from browsers, but do not really bother
// spelling out the methods supported at each path, which we should
@@ -235,7 +235,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
? recursiveRoot(request)
: new ResourceResponse(request, "user", "tenant", "tenant-pipeline", "athensDomain", "property", "cookiefreshness");
}
-
+
private HttpResponse authenticatedUser(HttpRequest request) {
String userIdString = request.getProperty("userOverride");
if (userIdString == null)
@@ -243,7 +243,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
.map(UserId::id)
.orElseThrow(() -> new ForbiddenException("You must be authenticated or specify userOverride"));
UserId userId = new UserId(userIdString);
-
+
List<Tenant> tenants = controller.tenants().asList(userId);
Slime slime = new Slime();
@@ -255,7 +255,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
response.setBool("tenantExists", tenants.stream().map(Tenant::getId).anyMatch(id -> id.isTenantFor(userId)));
return new SlimeJsonResponse(slime);
}
-
+
private HttpResponse tenants(HttpRequest request) {
Slime slime = new Slime();
Cursor response = slime.setArray();
@@ -263,7 +263,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
tenantInTenantsListToSlime(tenant, request.getUri(), response.addObject());
return new SlimeJsonResponse(slime);
}
-
+
/** Lists the screwdriver project id for each application */
private HttpResponse tenantPipelines() {
Slime slime = new Slime();
@@ -281,7 +281,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
response.setArray("brokenTenantPipelines"); // not used but may need to be present
return new SlimeJsonResponse(slime);
}
-
+
private HttpResponse athenzDomains(HttpRequest request) {
Slime slime = new Slime();
Cursor response = slime.setObject();
@@ -307,7 +307,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
private HttpResponse cookieFreshness(HttpRequest request) {
Slime slime = new Slime();
String passThruHeader = request.getHeader(SetBouncerPassthruHeaderFilter.BOUNCER_PASSTHRU_HEADER_FIELD);
- slime.setObject().setBool("shouldRefreshCookie",
+ slime.setObject().setBool("shouldRefreshCookie",
! SetBouncerPassthruHeaderFilter.BOUNCER_PASSTHRU_COOKIE_OK.equals(passThruHeader));
return new SlimeJsonResponse(slime);
}
@@ -332,7 +332,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
toSlime(application, array.addObject(), request);
return new SlimeJsonResponse(slime);
}
-
+
private HttpResponse application(String tenantName, String applicationName, HttpRequest request) {
ApplicationId applicationId = ApplicationId.from(tenantName, applicationName, "default");
Application application =
@@ -348,12 +348,12 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
object.setString("application", application.id().application().value());
object.setString("instance", application.id().instance().value());
// Currently deploying change
- if (application.deploying().isPresent()) {
+ if (application.change().isPresent()) {
Cursor deployingObject = object.setObject("deploying");
- if (application.deploying().get() instanceof Change.VersionChange)
- deployingObject.setString("version", ((Change.VersionChange)application.deploying().get()).version().toString());
- else if (((Change.ApplicationChange)application.deploying().get()).version().isPresent())
- toSlime(((Change.ApplicationChange)application.deploying().get()).version().get(), deployingObject.setObject("revision"));
+ application.change().platform().ifPresent(v -> deployingObject.setString("version", v.toString()));
+ application.change().application()
+ .filter(v -> v != ApplicationVersion.unknown)
+ .ifPresent(v -> toSlime(v, deployingObject.setObject("revision")));
}
// Jobs sorted according to deployment spec
@@ -594,7 +594,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
response.setResponse(result, serviceName, restPath);
return response;
}
-
+
private HttpResponse createUser(HttpRequest request) {
Optional<UserId> user = userFrom(request);
if ( ! user.isPresent() ) throw new ForbiddenException("Not authenticated.");
@@ -711,11 +711,11 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
ApplicationId id = ApplicationId.from(tenantName, applicationName, "default");
controller.applications().lockOrThrow(id, application -> {
- if (application.deploying().isPresent())
+ if (application.change().isPresent())
throw new IllegalArgumentException("Can not start a deployment of " + application + " at this time: " +
- application.deploying().get() + " is in progress");
+ application.change() + " is in progress");
- controller.applications().deploymentTrigger().triggerChange(application.id(), new Change.VersionChange(version));
+ controller.applications().deploymentTrigger().triggerChange(application.id(), Change.of(version));
});
return new MessageResponse("Triggered deployment of application '" + id + "' on version " + version);
}
@@ -724,14 +724,14 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
private HttpResponse cancelDeploy(String tenantName, String applicationName) {
ApplicationId id = ApplicationId.from(tenantName, applicationName, "default");
Application application = controller.applications().require(id);
- Optional<Change> change = application.deploying();
+ Change change = application.change();
if ( ! change.isPresent())
return new MessageResponse("No deployment in progress for " + application + " at this time");
controller.applications().lockOrThrow(id, lockedApplication ->
controller.applications().deploymentTrigger().cancelChange(id));
- return new MessageResponse("Cancelled " + change.get() + " for " + application);
+ return new MessageResponse("Cancelled " + change + " for " + application);
}
/** Schedule restart of deployment, or specific host in a deployment */
@@ -970,8 +970,8 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
private void toSlime(JobStatus.JobRun jobRun, Cursor object) {
object.setLong("id", jobRun.id());
object.setString("version", jobRun.version().toFullString());
- jobRun.applicationVersion().ifPresent(applicationVersion -> toSlime(applicationVersion,
- object.setObject("revision")));
+ 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/ControllerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java
index 1127e739689..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
@@ -101,14 +101,15 @@ public class ControllerTest {
Version version1 = Version.fromString("6.1"); // Set in config server mock
Application app1 = tester.createApplication("app1", "tenant1", 1, 11L);
tester.notifyJobCompletion(component, app1, true);
- assertFalse("Application version is currently not known",
- ((Change.ApplicationChange)tester.controller().applications().require(app1.id()).deploying().get()).version().isPresent());
+ assertEquals("Application version is currently not known",
+ ApplicationVersion.unknown,
+ tester.controller().applications().require(app1.id()).change().application().get());
tester.deployAndNotify(app1, applicationPackage, true, systemTest);
tester.deployAndNotify(app1, applicationPackage, true, stagingTest);
assertEquals(4, applications.require(app1.id()).deploymentJobs().jobStatus().size());
- Optional<ApplicationVersion> applicationVersion = ((Change.ApplicationChange)tester.controller().applications().require(app1.id()).deploying().get()).version();
- assertTrue("Application version has been set during deployment", applicationVersion.isPresent());
+ ApplicationVersion applicationVersion = tester.controller().applications().require(app1.id()).change().application().get();
+ assertTrue("Application version has been set during deployment", applicationVersion != ApplicationVersion.unknown);
assertStatus(JobStatus.initial(stagingTest)
.withTriggering(version1, applicationVersion, false, "", tester.clock().instant().minus(Duration.ofMillis(1)))
.withCompletion(42, Optional.empty(), tester.clock().instant(), tester.controller()), app1.id(), tester.controller());
@@ -166,7 +167,7 @@ public class ControllerTest {
tester.deployAndNotify(app1, applicationPackage, true, productionUsEast3);
assertEquals(5, applications.get(app1.id()).get().deploymentJobs().jobStatus().size());
-
+
// prod zone removal is not allowed
applicationPackage = new ApplicationPackageBuilder()
.environment(Environment.prod)
@@ -178,7 +179,7 @@ public class ControllerTest {
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());
+ 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()));
@@ -220,22 +221,21 @@ public class ControllerTest {
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, ((Change.ApplicationChange) tester.controller().applications()
- .require(app1.id())
- .deploying()
- .get()).version().get().id());
+ 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, Optional.of(expectedVersion), false, "", tester.clock().instant().minus(Duration.ofMillis(1)))
+ .withTriggering(version1, expectedVersion, false, "", tester.clock().instant().minus(Duration.ofMillis(1)))
.withCompletion(42, Optional.empty(), tester.clock().instant(), tester.controller()), app1.id(), tester.controller());
// Causes first deployment job to be triggered
assertStatus(JobStatus.initial(productionCorpUsEast1)
- .withTriggering(version1, Optional.of(expectedVersion), false, "", tester.clock().instant()), app1.id(), tester.controller());
+ .withTriggering(version1, expectedVersion, false, "", tester.clock().instant()), app1.id(), tester.controller());
tester.clock().advance(Duration.ofSeconds(1));
// production job (failing)
@@ -243,7 +243,7 @@ public class ControllerTest {
assertEquals(4, applications.require(app1.id()).deploymentJobs().jobStatus().size());
JobStatus expectedJobStatus = JobStatus.initial(productionCorpUsEast1)
- .withTriggering(version1, Optional.of(expectedVersion), false, "", tester.clock().instant())
+ .withTriggering(version1, expectedVersion, false, "", tester.clock().instant())
.withCompletion(42, Optional.of(JobError.unknown), tester.clock().instant(), tester.controller());
assertStatus(expectedJobStatus, app1.id(), tester.controller());
@@ -269,20 +269,20 @@ public class ControllerTest {
tester.deployAndNotify(app1, Optional.empty(), true, false, systemTest);
expectedVersion = ApplicationVersion.from(source, 38);
assertStatus(JobStatus.initial(systemTest)
- .withTriggering(version1, Optional.of(expectedVersion), false, "", tester.clock().instant().minus(Duration.ofMillis(1)))
+ .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, Optional.of(expectedVersion), false, "", tester.clock().instant().minus(Duration.ofMillis(1)))
+ .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, Optional.of(expectedVersion), false, "", tester.clock().instant()),
+ .withTriggering(version1, expectedVersion, false, "", tester.clock().instant()),
app1.id(), tester.controller());
tester.deployAndNotify(app1, Optional.empty(), true, true, productionUsEast3);
@@ -325,7 +325,7 @@ public class ControllerTest {
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
public void testDeployVersion() {
// Setup system
@@ -377,11 +377,10 @@ public class ControllerTest {
app1 = applications.require(app1.id());
assertEquals("Application change preserves version", systemVersion, app1.oldestDeployedVersion().get());
assertEquals(systemVersion, tester.configServer().lastPrepareVersion().get());
- assertFalse("Change deployed", app1.deploying().isPresent());
+ assertFalse("Change deployed", app1.change().isPresent());
// Version upgrade changes system version
- Change.VersionChange change = new Change.VersionChange(newSystemVersion);
- applications.deploymentTrigger().triggerChange(app1.id(), change);
+ applications.deploymentTrigger().triggerChange(app1.id(), Change.of(newSystemVersion));
tester.deployAndNotify(app1, applicationPackage, true, systemTest);
tester.deployAndNotify(app1, applicationPackage, true, stagingTest);
tester.deployAndNotify(app1, applicationPackage, true, productionUsWest1);
@@ -415,7 +414,7 @@ public class ControllerTest {
controller.updateVersionStatus(new VersionStatus(versions));
return newSystemVersion;
}
-
+
@Test
public void testPullRequestDeployment() {
// Setup system
@@ -427,7 +426,7 @@ public class ControllerTest {
ApplicationId app1 = tester.createAndDeploy("tenant1", "domain1",
"application1", Environment.staging,
app1ProjectId).id();
-
+
// pull-request deployment - uses different instance id
ApplicationId app1pr = tester.createAndDeploy("tenant1", "domain1",
"application1", "default-pr1",
@@ -461,7 +460,7 @@ public class ControllerTest {
.filter(app -> app.id().application().equals(app2.application()))
.count());
}
-
+
@Test
public void testFailingSinceUpdates() {
// Setup system
@@ -474,13 +473,13 @@ public class ControllerTest {
Instant initialFailure = tester.clock().instant();
tester.notifyJobCompletion(component, app, true);
tester.deployAndNotify(app, applicationPackage, false, systemTest);
- assertEquals("Failure age is right at initial failure",
+ assertEquals("Failure age is right at initial failure",
initialFailure.plus(Duration.ofMillis(2)), firstFailing(app, tester).get().at());
// Failure again -- failingSince should remain the same
tester.clock().advance(Duration.ofMillis(1000));
tester.deployAndNotify(app, applicationPackage, false, systemTest);
- assertEquals("Failure age is right at second consecutive failure",
+ assertEquals("Failure age is right at second consecutive failure",
initialFailure.plus(Duration.ofMillis(2)), firstFailing(app, tester).get().at());
// Success resets failingSince
@@ -491,27 +490,27 @@ public class ControllerTest {
// Complete deployment
tester.deployAndNotify(app, applicationPackage, true, stagingTest);
tester.deployAndNotify(app, applicationPackage, true, productionCorpUsEast1);
-
+
// Two repeated failures again.
// Initial failure
tester.clock().advance(Duration.ofMillis(1000));
initialFailure = tester.clock().instant();
tester.notifyJobCompletion(component, app, true);
tester.deployAndNotify(app, applicationPackage, false, systemTest);
- assertEquals("Failure age is right at initial failure",
+ assertEquals("Failure age is right at initial failure",
initialFailure.plus(Duration.ofMillis(2)), firstFailing(app, tester).get().at());
// Failure again -- failingSince should remain the same
tester.clock().advance(Duration.ofMillis(1000));
tester.deployAndNotify(app, applicationPackage, false, systemTest);
- assertEquals("Failure age is right at second consecutive failure",
+ assertEquals("Failure age is right at second consecutive failure",
initialFailure.plus(Duration.ofMillis(2)), firstFailing(app, tester).get().at());
}
private Optional<JobStatus.JobRun> firstFailing(Application application, DeploymentTester tester) {
return tester.controller().applications().get(application.id()).get().deploymentJobs().jobStatus().get(systemTest).firstFailing();
}
-
+
@Test
public void testMigratingTenantToAthenzWillModifyAthenzDomainsCorrectly() {
ControllerTester tester = new ControllerTester();
@@ -669,13 +668,13 @@ public class ControllerTest {
Application app = tester.createApplication(tenant, "app1", "default", 1);
tester.controller().applications().lockOrThrow(app.id(), application -> {
- application = application.withDeploying(Optional.of(new Change.VersionChange(Version.fromString("6.3"))));
+ application = application.withDeploying(Change.of(Version.fromString("6.3")));
applications.store(application);
try {
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.us-east-3 as version change 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());
}
});
}
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 8de32b4b531..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
@@ -18,8 +18,8 @@ import com.yahoo.vespa.hosted.controller.application.Change;
import com.yahoo.vespa.hosted.controller.application.DeploymentJobs;
import com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobType;
import com.yahoo.vespa.hosted.controller.application.SourceRevision;
-import com.yahoo.vespa.hosted.controller.maintenance.ReadyJobsTrigger;
import com.yahoo.vespa.hosted.controller.maintenance.JobControl;
+import com.yahoo.vespa.hosted.controller.maintenance.ReadyJobsTrigger;
import com.yahoo.vespa.hosted.controller.maintenance.Upgrader;
import com.yahoo.vespa.hosted.controller.versions.VersionStatus;
@@ -94,12 +94,6 @@ public class DeploymentTester {
return controller().applications().require(application);
}
- public Optional<Change.VersionChange> versionChange(ApplicationId application) {
- return application(application).deploying()
- .filter(c -> c instanceof Change.VersionChange)
- .map(Change.VersionChange.class::cast);
- }
-
public void updateVersionStatus() {
controller().updateVersionStatus(VersionStatus.compute(controller(), tester.controller().systemVersion()));
}
@@ -154,7 +148,7 @@ public class DeploymentTester {
/** Deploy application completely using the given application package */
public void deployCompletely(Application application, ApplicationPackage applicationPackage) {
notifyJobCompletion(JobType.component, application, true);
- assertTrue(applications().require(application.id()).deploying().isPresent());
+ assertTrue(applications().require(application.id()).change().isPresent());
completeDeployment(application, applicationPackage, Optional.empty(), true);
}
@@ -178,7 +172,7 @@ public class DeploymentTester {
/** Deploy application using the given application package, but expecting to stop after test phases */
public void deployTestOnly(Application application, ApplicationPackage applicationPackage) {
notifyJobCompletion(JobType.component, application, true);
- assertTrue(applications().require(application.id()).deploying().isPresent());
+ assertTrue(applications().require(application.id()).change().isPresent());
completeDeployment(application, applicationPackage, Optional.empty(), false);
}
@@ -196,13 +190,13 @@ public class DeploymentTester {
}
}
if (failOnJob.isPresent()) {
- assertTrue(applications().require(application.id()).deploying().isPresent());
+ assertTrue(applications().require(application.id()).change().isPresent());
assertTrue(applications().require(application.id()).deploymentJobs().hasFailures());
} else if (includingProductionZones) {
- assertFalse(applications().require(application.id()).deploying().isPresent());
+ assertFalse(applications().require(application.id()).change().isPresent());
}
else {
- assertTrue(applications().require(application.id()).deploying().isPresent());
+ assertTrue(applications().require(application.id()).change().isPresent());
}
}
@@ -225,8 +219,8 @@ public class DeploymentTester {
}
public void completeUpgrade(Application application, Version version, ApplicationPackage applicationPackage) {
- assertTrue(application + " has a deployment", applications().require(application.id()).deploying().isPresent());
- assertEquals(new Change.VersionChange(version), applications().require(application.id()).deploying().get());
+ assertTrue(application + " has a deployment", applications().require(application.id()).change().isPresent());
+ assertEquals(Change.of(version), applications().require(application.id()).change());
completeDeployment(application, applicationPackage, Optional.empty(), true);
}
@@ -239,8 +233,8 @@ public class DeploymentTester {
}
private void completeUpgradeWithError(Application application, Version version, ApplicationPackage applicationPackage, Optional<JobType> failOnJob) {
- assertTrue(applications().require(application.id()).deploying().isPresent());
- assertEquals(new Change.VersionChange(version), applications().require(application.id()).deploying().get());
+ assertTrue(applications().require(application.id()).change().isPresent());
+ assertEquals(Change.of(version), applications().require(application.id()).change());
completeDeployment(application, applicationPackage, failOnJob, true);
}
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 74d03240ec3..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
@@ -13,13 +13,12 @@ import com.yahoo.vespa.hosted.controller.application.ApplicationPackage;
import com.yahoo.vespa.hosted.controller.application.Change;
import com.yahoo.vespa.hosted.controller.application.DeploymentJobs;
import com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobType;
-import com.yahoo.vespa.hosted.controller.maintenance.ReadyJobsTrigger;
import com.yahoo.vespa.hosted.controller.maintenance.JobControl;
+import com.yahoo.vespa.hosted.controller.maintenance.ReadyJobsTrigger;
import org.junit.Test;
import java.time.Duration;
import java.time.Instant;
-import java.util.Optional;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -221,13 +220,13 @@ public class DeploymentTriggerTest {
tester.deploy(DeploymentJobs.JobType.productionUsWest1, app, applicationPackage);
tester.notifyJobCompletion(DeploymentJobs.JobType.productionUsWest1, app, true);
assertTrue("Change is present as not all jobs are complete",
- tester.applications().require(app.id()).deploying().isPresent());
+ tester.applications().require(app.id()).change().isPresent());
// All jobs complete
tester.deploy(DeploymentJobs.JobType.productionUsEast3, app, applicationPackage);
tester.notifyJobCompletion(DeploymentJobs.JobType.productionUsEast3, app, true);
assertFalse("Change has been deployed",
- tester.applications().require(app.id()).deploying().isPresent());
+ tester.applications().require(app.id()).change().isPresent());
}
@Test
@@ -321,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.withDeploying(Optional.of(new Change.VersionChange(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());
@@ -350,7 +349,7 @@ public class DeploymentTriggerTest {
// Extra notification for last job
tester.notifyJobCompletion(JobType.productionCorpUsEast1, application, true);
assertFalse("Change has been deployed",
- tester.applications().require(application.id()).deploying().isPresent());
+ tester.applications().require(application.id()).change().isPresent());
assertTrue("All jobs consumed", buildSystem.jobs().isEmpty());
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployerTest.java
index b200e2d7e18..11e85c6be9f 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployerTest.java
@@ -58,7 +58,7 @@ public class FailureRedeployerTest {
tester.clock().advance(Duration.ofSeconds(1)); // Advance time so that we can detect jobs in progress
tester.deployAndNotify(app, applicationPackage, false, DeploymentJobs.JobType.productionUsEast3);
assertEquals("Production job is retried", 1, tester.buildSystem().jobs().size());
- assertEquals("Application has pending upgrade to " + version, version, tester.versionChange(app.id()).get().version());
+ assertEquals("Application has pending upgrade to " + version, version, tester.application(app.id()).change().platform().get());
// Another version is released, which cancels any pending upgrades to lower versions
version = Version.fromString("5.2");
@@ -66,7 +66,7 @@ public class FailureRedeployerTest {
tester.deployAndNotify(app, applicationPackage, true, DeploymentJobs.JobType.productionUsEast3); // Finish previous production job.
tester.upgrader().maintain();
assertEquals("Application starts upgrading to new version", 1, tester.buildSystem().jobs().size());
- assertEquals("Application has pending upgrade to " + version, version, tester.versionChange(app.id()).get().version());
+ assertEquals("Application has pending upgrade to " + version, version, tester.application(app.id()).change().platform().get());
// Failure redeployer does not retry failing job for prod.us-east-3 as there's an ongoing deployment
tester.clock().advance(Duration.ofMinutes(1));
@@ -150,7 +150,7 @@ public class FailureRedeployerTest {
tester.updateVersionStatus(version);
assertEquals(version, tester.controller().versionStatus().systemVersion().get().versionNumber());
tester.upgrader().maintain();
- assertEquals("Application has pending upgrade to " + version, version, tester.versionChange(app.id()).get().version());
+ assertEquals("Application has pending upgrade to " + version, version, tester.application(app.id()).change().platform().get());
// system-test fails and exhausts all immediate retries
tester.deployAndNotify(app, applicationPackage, false, DeploymentJobs.JobType.systemTest);
@@ -164,7 +164,7 @@ public class FailureRedeployerTest {
tester.updateVersionStatus(version);
assertEquals(version, tester.controller().versionStatus().systemVersion().get().versionNumber());
tester.upgrader().maintain();
- assertEquals("Application has pending upgrade to " + version, version, tester.versionChange(app.id()).get().version());
+ assertEquals("Application has pending upgrade to " + version, version, tester.application(app.id()).change().platform().get());
// Consume system-test job for 5.2
tester.buildSystem().takeJobsToRun();
@@ -225,12 +225,12 @@ public class FailureRedeployerTest {
// Deployment notifies completeness but has not actually made a deployment
tester.notifyJobCompletion(DeploymentJobs.JobType.productionCdUsCentral1, application, true);
- assertTrue("Change not really deployed", tester.application(application.id()).deploying().isPresent());
+ assertTrue("Change not really deployed", tester.application(application.id()).change().isPresent());
// Deployment actually deploys and notifies completeness
tester.deploy(DeploymentJobs.JobType.productionCdUsCentral1, application, applicationPackage);
tester.notifyJobCompletion(DeploymentJobs.JobType.productionCdUsCentral1, application, true);
- assertFalse("Change not really deployed", tester.application(application.id()).deploying().isPresent());
+ assertFalse("Change not really deployed", tester.application(application.id()).change().isPresent());
}
@Test
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 13636122cfd..3d34e78c759 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
@@ -20,28 +20,28 @@ import static org.junit.Assert.assertTrue;
* @author bratseth
*/
public class OutstandingChangeDeployerTest {
-
+
@Test
public void testChangeDeployer() {
DeploymentTester tester = new DeploymentTester();
tester.configServer().setDefaultVersion(new Version(6, 1));
- OutstandingChangeDeployer deployer = new OutstandingChangeDeployer(tester.controller(), Duration.ofMinutes(10),
+ OutstandingChangeDeployer deployer = new OutstandingChangeDeployer(tester.controller(), Duration.ofMinutes(10),
new JobControl(new MockCuratorDb()));
tester.createAndDeploy("app1", 11, "default");
tester.createAndDeploy("app2", 22, "default");
Version version = new Version(6, 2);
- tester.deploymentTrigger().triggerChange(tester.application("app1").id(), new Change.VersionChange(version));
-
- assertEquals(new Change.VersionChange(version), tester.application("app1").deploying().get());
+ tester.deploymentTrigger().triggerChange(tester.application("app1").id(), Change.of(version));
+
+ assertEquals(Change.of(version), tester.application("app1").change());
assertFalse(tester.application("app1").hasOutstandingChange());
tester.notifyJobCompletion(DeploymentJobs.JobType.component, tester.application("app1"), true);
assertTrue(tester.application("app1").hasOutstandingChange());
assertEquals(1, tester.buildSystem().jobs().size());
-
+
deployer.maintain();
assertEquals("No effect as job is in progress", 1, tester.buildSystem().jobs().size());
-
+
tester.deployCompletely("app1");
assertEquals("Upgrade done", 0, tester.buildSystem().jobs().size());
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 fd13b99f25e..ccc029a9654 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
@@ -9,7 +9,6 @@ import com.yahoo.vespa.hosted.controller.Application;
import com.yahoo.vespa.hosted.controller.ControllerTester;
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.Change;
import com.yahoo.vespa.hosted.controller.application.Deployment;
import com.yahoo.vespa.hosted.controller.application.DeploymentJobs;
import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder;
@@ -174,11 +173,11 @@ public class UpgraderTest {
assertEquals(VespaVersion.Confidence.normal, tester.controller().versionStatus().systemVersion().get().confidence());
tester.upgrader().maintain();
assertEquals("Upgrade of defaults are scheduled", 5, tester.buildSystem().jobs().size());
- assertEquals(version54, ((Change.VersionChange)tester.application(default0.id()).deploying().get()).version());
- assertEquals(version54, ((Change.VersionChange)tester.application(default1.id()).deploying().get()).version());
- assertEquals(version54, ((Change.VersionChange)tester.application(default2.id()).deploying().get()).version());
- assertEquals(version54, ((Change.VersionChange)tester.application(default3.id()).deploying().get()).version());
- assertEquals(version54, ((Change.VersionChange)tester.application(default4.id()).deploying().get()).version());
+ assertEquals(version54, tester.application(default0.id()).change().platform().get());
+ assertEquals(version54, tester.application(default1.id()).change().platform().get());
+ assertEquals(version54, tester.application(default2.id()).change().platform().get());
+ assertEquals(version54, tester.application(default3.id()).change().platform().get());
+ assertEquals(version54, tester.application(default4.id()).change().platform().get());
tester.completeUpgrade(default0, version54, "default");
// State: Default applications started upgrading to 5.4 (and one completed)
Version version55 = Version.fromString("5.5");
@@ -190,11 +189,11 @@ public class UpgraderTest {
assertEquals(VespaVersion.Confidence.normal, tester.controller().versionStatus().systemVersion().get().confidence());
tester.upgrader().maintain();
assertEquals("Upgrade of defaults are scheduled", 5, tester.buildSystem().jobs().size());
- assertEquals(version55, ((Change.VersionChange)tester.application(default0.id()).deploying().get()).version());
- assertEquals(version54, ((Change.VersionChange)tester.application(default1.id()).deploying().get()).version());
- assertEquals(version54, ((Change.VersionChange)tester.application(default2.id()).deploying().get()).version());
- assertEquals(version54, ((Change.VersionChange)tester.application(default3.id()).deploying().get()).version());
- assertEquals(version54, ((Change.VersionChange)tester.application(default4.id()).deploying().get()).version());
+ assertEquals(version55, tester.application(default0.id()).change().platform().get());
+ assertEquals(version54, tester.application(default1.id()).change().platform().get());
+ assertEquals(version54, tester.application(default2.id()).change().platform().get());
+ assertEquals(version54, tester.application(default3.id()).change().platform().get());
+ assertEquals(version54, tester.application(default4.id()).change().platform().get());
tester.completeUpgrade(default1, version54, "default");
tester.completeUpgrade(default2, version54, "default");
tester.completeUpgradeWithError(default3, version54, "default", DeploymentJobs.JobType.stagingTest);
@@ -216,7 +215,7 @@ public class UpgraderTest {
assertEquals("Upgrade of defaults are scheduled on 5.4 instead, since 5.5 broken: " +
"This is default3 since it failed upgrade on both 5.4 and 5.5",
1, tester.buildSystem().jobs().size());
- assertEquals("5.4", ((Change.VersionChange)tester.application(default3.id()).deploying().get()).version().toString());
+ assertEquals("5.4", tester.application(default3.id()).change().platform().get().toString());
}
@Test
@@ -320,7 +319,7 @@ public class UpgraderTest {
tester.notifyJobCompletion(DeploymentJobs.JobType.stagingTest, app, false);
assertTrue("Retries exhausted", tester.buildSystem().jobs().isEmpty());
assertTrue("Failure is recorded", tester.application(app.id()).deploymentJobs().hasFailures());
- assertTrue("Application has pending change", tester.application(app.id()).deploying().isPresent());
+ assertTrue("Application has pending change", tester.application(app.id()).change().isPresent());
// New version is released
version = Version.fromString("5.2");
@@ -379,7 +378,7 @@ public class UpgraderTest {
tester.upgrader().maintain();
// 5th app passes system-test, but does not trigger next job as upgrade is cancelled
- assertFalse("No change present", tester.applications().require(default4.id()).deploying().isPresent());
+ assertFalse("No change present", tester.applications().require(default4.id()).change().isPresent());
tester.notifyJobCompletion(DeploymentJobs.JobType.systemTest, default4, true);
assertTrue("All jobs consumed", tester.buildSystem().jobs().isEmpty());
}
@@ -476,7 +475,7 @@ public class UpgraderTest {
assertEquals(v2, tester.application("default0").deployments().get(ZoneId.from("prod.us-west-1")).version());
assertEquals("Last zone is upgraded to v1",
v1, tester.application("default0").deployments().get(ZoneId.from("prod.us-east-3")).version());
- assertFalse(tester.application("default0").deploying().isPresent());
+ assertFalse(tester.application("default0").change().isPresent());
}
@Test
@@ -747,7 +746,7 @@ public class UpgraderTest {
// 5th app never reports back and has a dead job, but no ongoing change
Application deadLocked = tester.applications().require(default4.id());
assertTrue("Jobs in progress", deadLocked.deploymentJobs().isRunning(tester.controller().applications().deploymentTrigger().jobTimeoutLimit()));
- assertFalse("No change present", deadLocked.deploying().isPresent());
+ assertFalse("No change present", deadLocked.change().isPresent());
// 4 out of 5 applications are repaired and confidence is restored
ApplicationPackage defaultApplicationPackageV2 = new ApplicationPackageBuilder()
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 f42a4c1deb3..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
@@ -70,10 +70,10 @@ public class ApplicationSerializerTest {
List<JobStatus> statusList = new ArrayList<>();
statusList.add(JobStatus.initial(DeploymentJobs.JobType.systemTest)
- .withTriggering(Version.fromString("5.6.7"), Optional.empty(), true, "Test", Instant.ofEpochMilli(7))
+ .withTriggering(Version.fromString("5.6.7"), ApplicationVersion.unknown, true, "Test", Instant.ofEpochMilli(7))
.withCompletion(30, Optional.empty(), Instant.ofEpochMilli(8), tester.controller()));
statusList.add(JobStatus.initial(DeploymentJobs.JobType.stagingTest)
- .withTriggering(Version.fromString("5.6.6"), Optional.empty(), true, "Test 2", Instant.ofEpochMilli(5))
+ .withTriggering(Version.fromString("5.6.6"), ApplicationVersion.unknown, true, "Test 2", Instant.ofEpochMilli(5))
.withCompletion(11, Optional.of(JobError.unknown), Instant.ofEpochMilli(6), tester.controller()));
DeploymentJobs deploymentJobs = new DeploymentJobs(projectId, statusList, Optional.empty());
@@ -82,7 +82,7 @@ public class ApplicationSerializerTest {
deploymentSpec,
validationOverrides,
deployments, deploymentJobs,
- Optional.of(new Change.VersionChange(Version.fromString("6.7"))),
+ Change.of(Version.fromString("6.7")),
true,
Optional.of(IssueId.from("1234")),
new MetricsService.ApplicationMetrics(0.5, 0.9),
@@ -114,7 +114,7 @@ public class ApplicationSerializerTest {
assertEquals(original.ownershipIssueId(), serialized.ownershipIssueId());
- assertEquals(original.deploying(), serialized.deploying());
+ assertEquals(original.change(), serialized.change());
assertEquals(original.rotation().get().id(), serialized.rotation().get().id());
// Test cluster utilization
@@ -145,24 +145,22 @@ public class ApplicationSerializerTest {
assertEquals(6, serialized.deployments().get(zone2).metrics().writeLatencyMillis(), Double.MIN_VALUE);
{ // test more deployment serialization cases
- Application original2 = writable(original).withDeploying(Optional.of(Change.ApplicationChange.of(ApplicationVersion
- .from("hash1"))));
+ Application original2 = writable(original).withDeploying(Change.of(ApplicationVersion.from("hash1")));
Application serialized2 = applicationSerializer.fromSlime(applicationSerializer.toSlime(original2));
- assertEquals(original2.deploying(), serialized2.deploying());
- assertEquals(((Change.ApplicationChange)serialized2.deploying().get()).version().get().source(),
- ((Change.ApplicationChange)original2.deploying().get()).version().get().source());
+ assertEquals(original2.change(), serialized2.change());
+ assertEquals(serialized2.change().application().get().source(),
+ original2.change().application().get().source());
- Application original3 = writable(original).withDeploying(Optional.of(Change.ApplicationChange.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.deploying(), serialized2.deploying());
- assertEquals(((Change.ApplicationChange)serialized3.deploying().get()).version().get().source(),
- ((Change.ApplicationChange)original3.deploying().get()).version().get().source());
+ assertEquals(original3.change(), serialized2.change());
+ assertEquals(serialized3.change().application().get().source(),
+ original3.change().application().get().source());
- Application original4 = writable(original).withDeploying(Optional.empty());
+ Application original4 = writable(original).withDeploying(Change.empty());
Application serialized4 = applicationSerializer.fromSlime(applicationSerializer.toSlime(original4));
- assertEquals(original4.deploying(), serialized4.deploying());
+ assertEquals(original4.change(), serialized4.change());
}
}
@@ -210,7 +208,7 @@ public class ApplicationSerializerTest {
Application application = applicationSerializer.fromSlime(applicationSlime(false));
assertFalse(application.deploymentJobs().jobStatus().get(DeploymentJobs.JobType.systemTest).lastCompleted().get().upgrade());
}
-
+
@Test
public void testCompleteApplicationDeserialization() {
applicationSerializer.fromSlime(SlimeUtils.jsonToSlime(longApplicationJson.getBytes(StandardCharsets.UTF_8)));
@@ -253,6 +251,6 @@ public class ApplicationSerializerTest {
" }\n" +
"}\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/restapi/application/responses/application-deployment-cancelled.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-deployment-cancelled.json
index d1e1ebe94fd..3b6d8ed71e9 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-deployment-cancelled.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-deployment-cancelled.json
@@ -1 +1 @@
-{"message":"Cancelled version change to 6.1 for application 'tenant1.application1'"}
+{"message":"Cancelled upgrade to 6.1 for application 'tenant1.application1'"}