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