diff options
28 files changed, 1200 insertions, 907 deletions
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 ffea3ca2da3..a5e483fa4ce 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 @@ -196,28 +196,39 @@ public class ApplicationController { return curator.readApplications(); } - /** Returns a snapshot of all applications */ + /** Returns all applications of a tenant */ + public List<Application> applicationList(TenantName tenant) { + return curator.readApplications(tenant); + } + + /** Returns a snapshot of all instances */ public List<Instance> asList() { return curator.readInstances(); } - /** Returns all applications of a tenant */ + /** Returns all instances of a tenant */ public List<Instance> asList(TenantName tenant) { return curator.readInstances(tenant); } + /** Returns all instances of an application */ + public List<Instance> asList(TenantAndApplicationId id) { + return curator.readInstances(id); + } + public ArtifactRepository artifacts() { return artifactRepository; } public ApplicationStore applicationStore() { return applicationStore; } /** Returns the oldest Vespa version installed on any active or reserved production node for the given application. */ public Version oldestInstalledPlatform(ApplicationId id) { - return get(id).flatMap(application -> application.productionDeployments().keySet().stream() - .flatMap(zone -> configServer.nodeRepository().list(zone, id, EnumSet.of(active, reserved)).stream()) - .map(Node::currentVersion) - .filter(version -> ! version.isEmpty()) - .min(naturalOrder())) - .orElse(controller.systemVersion()); + return asList(TenantAndApplicationId.from(id)).stream() + .flatMap(instance -> instance.productionDeployments().keySet().stream() + .flatMap(zone -> configServer.nodeRepository().list(zone, id, EnumSet.of(active, reserved)).stream()) + .map(Node::currentVersion) + .filter(version -> ! version.isEmpty())) + .min(naturalOrder()) + .orElse(controller.systemVersion()); } /** Change the global endpoint status for given deployment */ @@ -256,7 +267,7 @@ public class ApplicationController { * * @throws IllegalArgumentException if the application already exists */ - public Instance createApplication(ApplicationId id, Optional<Credentials> credentials) { + public Application createApplication(ApplicationId id, Optional<Credentials> credentials) { if (id.instance().isTester()) throw new IllegalArgumentException("'" + id + "' is a tester application!"); try (Lock lock = lock(TenantAndApplicationId.from(id)); @@ -279,7 +290,7 @@ public class ApplicationController { if ( ! id.instance().isTester()) // Only store the application permits for non-user applications. accessControl.createApplication(id, credentials.get()); } - LockedInstance application = new LockedInstance(new Instance(id, clock.instant()), lock); + LockedApplication application = new LockedApplication(new Application(id, clock.instant()), lock); store(application); log.info("Created " + application); return application.get(); @@ -757,6 +768,15 @@ public class ApplicationController { * * @param application a locked application to store */ + public void store(LockedApplication application) { + curator.writeApplication(application.get()); + } + + /** + * Replace any previous version of this application by this instance + * + * @param application a locked application to store + */ public void store(LockedInstance application) { curator.writeInstance(application.get()); } @@ -767,6 +787,18 @@ public class ApplicationController { * @param applicationId ID of the application to lock and get. * @param action Function which acts on the locked application. */ + public void lockApplicationIfPresent(ApplicationId applicationId, Consumer<LockedApplication> action) { + try (Lock lock = lock(applicationId)) { + getApplication(applicationId).map(application -> new LockedApplication(application, lock)).ifPresent(action); + } + } + + /** + * Acquire a locked instance to modify and store, if there is an instance with the given id. + * + * @param applicationId ID of the instance to lock and get. + * @param action Function which acts on the locked instance. + */ public void lockIfPresent(ApplicationId applicationId, Consumer<LockedInstance> action) { try (Lock lock = lock(TenantAndApplicationId.from(applicationId)); Lock oldLock = lock(applicationId)) { @@ -781,6 +813,19 @@ public class ApplicationController { * @param action Function which acts on the locked application. * @throws IllegalArgumentException when application does not exist. */ + public void lockApplicationOrThrow(ApplicationId applicationId, Consumer<LockedApplication> action) { + try (Lock lock = lock(applicationId)) { + action.accept(new LockedApplication(requireApplication(applicationId), lock)); + } + } + + /** + * Acquire a locked instance to modify and store, or throw an exception if no instance has the given id. + * + * @param applicationId ID of the instance to lock and require. + * @param action Function which acts on the locked instance. + * @throws IllegalArgumentException when instance does not exist. + */ public void lockOrThrow(ApplicationId applicationId, Consumer<LockedInstance> action) { try (Lock lock = lock(TenantAndApplicationId.from(applicationId)); Lock oldLock = lock(applicationId)) { 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 c3a710ec530..a6fce4bb0c4 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 @@ -96,8 +96,8 @@ public class LockedApplication { } /** Returns a read-only copy of this */ - public Instance get() { - return new Instance(id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs, change, + public Application get() { + return new Application(id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs, change, outstandingChange, ownershipIssueId, owner, majorVersion, metrics, pemDeployKey, rotations, rotationStatus); } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPolicies.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPolicies.java index b2006c4c1f4..d6080bcda6c 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPolicies.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPolicies.java @@ -51,7 +51,7 @@ public class RoutingPolicies { } } - /** Read all known routing policies for given application */ + /** Read all known routing policies for given instance */ public Set<RoutingPolicy> get(ApplicationId application) { return db.readRoutingPolicies(application); } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java index 9c5eb9db465..263429952d9 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java @@ -359,6 +359,7 @@ public class CuratorDb { } private Stream<ApplicationId> readApplicationIds() { + // TODO jonmv: Filter on number of parts in id when reading from applicationRoot again. return curator.getChildren(instanceRoot).stream().map(ApplicationId::fromSerializedForm); } @@ -394,7 +395,12 @@ public class CuratorDb { } public List<Instance> readInstances(TenantName name) { - return readInstances(application -> application.tenant().equals(name)); + return readInstances(instance -> instance.tenant().equals(name)); + } + + public List<Instance> readInstances(TenantAndApplicationId id) { + return readInstances(instance -> instance.tenant().equals(id.tenant()) + && instance.application().equals(id.application())); } private Stream<ApplicationId> readInstanceIds() { @@ -430,7 +436,7 @@ public class CuratorDb { * Use Application where applicable * * Stop writing Instance to old application path - * Read Application from application path + * Read Application and Instance parts from respective paths * * Stop writing instance part to application path, and vice versa * Remove unused parts of Instance and Application 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 123da447757..7585d372bc1 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 @@ -26,6 +26,7 @@ import com.yahoo.vespa.athenz.api.AthenzUser; import com.yahoo.vespa.athenz.client.zms.ZmsClientException; import com.yahoo.vespa.config.SlimeUtils; import com.yahoo.vespa.hosted.controller.AlreadyExistsException; +import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.Instance; import com.yahoo.vespa.hosted.controller.Controller; import com.yahoo.vespa.hosted.controller.NotExistsException; @@ -475,6 +476,150 @@ public class ApplicationApiHandler extends LoggingRequestHandler { return new MessageResponse(type.jobName() + " for " + id + " paused for " + DeploymentTrigger.maxPause); } + private void toSlime(Cursor object, Application application, HttpRequest request) { + object.setString("tenant", application.id().tenant().value()); + object.setString("application", application.id().application().value()); + object.setString("instance", application.id().instance().value()); + object.setString("deployments", withPath("/application/v4" + + "/tenant/" + application.id().tenant().value() + + "/application/" + application.id().application().value() + + "/instance/" + application.id().instance().value() + "/job/", + request.getUri()).toString()); + + application.deploymentJobs().statusOf(JobType.component) + .flatMap(JobStatus::lastSuccess) + .map(run -> run.application().source()) + .ifPresent(source -> sourceRevisionToSlime(source, object.setObject("source"))); + + application.deploymentJobs().projectId() + .ifPresent(id -> object.setLong("projectId", id)); + + // Currently deploying change + if ( ! application.change().isEmpty()) { + toSlime(object.setObject("deploying"), application.change()); + } + + // Outstanding change + if ( ! application.outstandingChange().isEmpty()) { + toSlime(object.setObject("outstandingChange"), application.outstandingChange()); + } + + // Jobs sorted according to deployment spec + List<JobStatus> jobStatus = controller.applications().deploymentTrigger() + .steps(application.deploymentSpec()) + .sortedJobs(application.deploymentJobs().jobStatus().values()); + + object.setBool("deployedInternally", application.deploymentJobs().deployedInternally()); + Cursor deploymentsArray = object.setArray("deploymentJobs"); + for (JobStatus job : jobStatus) { + Cursor jobObject = deploymentsArray.addObject(); + jobObject.setString("type", job.type().jobName()); + jobObject.setBool("success", job.isSuccess()); + + job.lastTriggered().ifPresent(jobRun -> toSlime(jobRun, jobObject.setObject("lastTriggered"))); + job.lastCompleted().ifPresent(jobRun -> toSlime(jobRun, jobObject.setObject("lastCompleted"))); + job.firstFailing().ifPresent(jobRun -> toSlime(jobRun, jobObject.setObject("firstFailing"))); + job.lastSuccess().ifPresent(jobRun -> toSlime(jobRun, jobObject.setObject("lastSuccess"))); + } + + // Change blockers + Cursor changeBlockers = object.setArray("changeBlockers"); + application.deploymentSpec().changeBlocker().forEach(changeBlocker -> { + Cursor changeBlockerObject = changeBlockers.addObject(); + changeBlockerObject.setBool("versions", changeBlocker.blocksVersions()); + changeBlockerObject.setBool("revisions", changeBlocker.blocksRevisions()); + changeBlockerObject.setString("timeZone", changeBlocker.window().zone().getId()); + Cursor days = changeBlockerObject.setArray("days"); + changeBlocker.window().days().stream().map(DayOfWeek::getValue).forEach(days::addLong); + Cursor hours = changeBlockerObject.setArray("hours"); + changeBlocker.window().hours().forEach(hours::addLong); + }); + + // Compile version. The version that should be used when building an application + object.setString("compileVersion", compileVersion(application.id()).toFullString()); + + application.majorVersion().ifPresent(majorVersion -> object.setLong("majorVersion", majorVersion)); + + // Rotation + Cursor globalRotationsArray = object.setArray("globalRotations"); + application.endpointsIn(controller.system()) + .scope(Endpoint.Scope.global) + .legacy(false) // Hide legacy names + .asList().stream() + .map(Endpoint::url) + .map(URI::toString) + .forEach(globalRotationsArray::addString); + + application.rotations().stream() + .map(AssignedRotation::rotationId) + .findFirst() + .ifPresent(rotation -> object.setString("rotationId", rotation.asString())); + + // Per-cluster rotations + Set<RoutingPolicy> routingPolicies = controller.applications().routingPolicies().get(application.id()); + for (RoutingPolicy policy : routingPolicies) { + policy.rotationEndpointsIn(controller.system()).asList().stream() + .map(Endpoint::url) + .map(URI::toString) + .forEach(globalRotationsArray::addString); + } + + // Deployments sorted according to deployment spec + List<Deployment> deployments = controller.applications().deploymentTrigger() + .steps(application.deploymentSpec()) + .sortedDeployments(application.deployments().values()); + Cursor instancesArray = object.setArray("instances"); + for (Deployment deployment : deployments) { + Cursor deploymentObject = instancesArray.addObject(); + + // Rotation status for this deployment + if (deployment.zone().environment() == Environment.prod) { + // 0 rotations: No fields written + // 1 rotation : Write legacy field and endpointStatus field + // >1 rotation : Write only endpointStatus field + if (application.rotations().size() == 1) { + // TODO(mpolden): Stop writing this field once clients stop expecting it + toSlime(application.rotationStatus().of(application.rotations().get(0).rotationId(), deployment), + deploymentObject); + } + if (!application.rotations().isEmpty()) { + toSlime(application.rotations(), application.rotationStatus(), deployment, deploymentObject); + } + } + + if (recurseOverDeployments(request)) // List full deployment information when recursive. + toSlime(deploymentObject, new DeploymentId(application.id(), deployment.zone()), deployment, request); + else { + deploymentObject.setString("environment", deployment.zone().environment().value()); + deploymentObject.setString("region", deployment.zone().region().value()); + deploymentObject.setString("instance", application.id().instance().value()); // pointless + deploymentObject.setString("url", withPath(request.getUri().getPath() + + "/environment/" + deployment.zone().environment().value() + + "/region/" + deployment.zone().region().value() + + ( request.getUri().getPath().contains("/instance/") ? "" : "/instance/" + application.id().instance().value()), + request.getUri()).toString()); + } + } + + application.pemDeployKey().ifPresent(key -> object.setString("pemDeployKey", key)); + + // Metrics + Cursor metricsObject = object.setObject("metrics"); + metricsObject.setDouble("queryServiceQuality", application.metrics().queryServiceQuality()); + metricsObject.setDouble("writeServiceQuality", application.metrics().writeServiceQuality()); + + // Activity + Cursor activity = object.setObject("activity"); + application.activity().lastQueried().ifPresent(instant -> activity.setLong("lastQueried", instant.toEpochMilli())); + application.activity().lastWritten().ifPresent(instant -> activity.setLong("lastWritten", instant.toEpochMilli())); + application.activity().lastQueriesPerSecond().ifPresent(value -> activity.setDouble("lastQueriesPerSecond", value)); + application.activity().lastWritesPerSecond().ifPresent(value -> activity.setDouble("lastWritesPerSecond", value)); + + application.ownershipIssueId().ifPresent(issueId -> object.setString("ownershipIssueId", issueId.value())); + application.owner().ifPresent(owner -> object.setString("owner", owner.username())); + application.deploymentJobs().issueId().ifPresent(issueId -> object.setString("deploymentIssueId", issueId.value())); + } + private void toSlime(Cursor object, Instance instance, HttpRequest request) { object.setString("tenant", instance.id().tenant().value()); object.setString("application", instance.id().application().value()); @@ -968,10 +1113,10 @@ public class ApplicationApiHandler extends LoggingRequestHandler { Optional<Credentials> credentials = controller.tenants().require(id.tenant()).type() == Tenant.Type.user ? Optional.empty() : Optional.of(accessControlRequests.credentials(id.tenant(), requestObject, request.getJDiscRequest())); - Instance instance = controller.applications().createApplication(id, credentials); + Application application = controller.applications().createApplication(id, credentials); Slime slime = new Slime(); - toSlime(instance, slime.setObject(), request); + toSlime(application, slime.setObject(), request); return new SlimeJsonResponse(slime); } catch (ZmsClientException e) { // TODO: Push conversion down @@ -1391,6 +1536,17 @@ public class ApplicationApiHandler extends LoggingRequestHandler { return Joiner.on("/").join(elements); } + private void toSlime(Application application, Cursor object, HttpRequest request) { + object.setString("tenant", application.id().tenant().value()); + object.setString("application", application.id().application().value()); + object.setString("instance", application.id().instance().value()); + object.setString("url", withPath("/application/v4" + + "/tenant/" + application.id().tenant().value() + + "/application/" + application.id().application().value() + + "/instance/" + application.id().instance().value(), + request.getUri()).toString()); + } + private void toSlime(Instance instance, Cursor object, HttpRequest request) { object.setString("tenant", instance.id().tenant().value()); object.setString("application", instance.id().application().value()); 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 57994e181c5..961c1746b39 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 @@ -35,6 +35,8 @@ import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder; import com.yahoo.vespa.hosted.controller.deployment.BuildJob; import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester; import com.yahoo.vespa.hosted.controller.integration.ZoneApiMock; +import com.yahoo.vespa.hosted.controller.persistence.ApplicationSerializer; +import com.yahoo.vespa.hosted.controller.persistence.InstanceSerializer; import com.yahoo.vespa.hosted.controller.persistence.MockCuratorDb; import com.yahoo.vespa.hosted.controller.persistence.OldMockCuratorDb; import com.yahoo.vespa.hosted.controller.rotation.RotationId; @@ -85,13 +87,14 @@ public class ControllerTest { // staging job - succeeding Version version1 = tester.defaultPlatformVersion(); - Instance app1 = tester.createApplication("app1", "tenant1", 1, 11L); + Application app1 = tester.createApplication("app1", "tenant1", 1, 11L); + Instance instance = tester.instance(app1.id()); tester.jobCompletion(component).application(app1).uploadArtifact(applicationPackage).submit(); assertEquals("Application version is known from completion of initial job", ApplicationVersion.from(BuildJob.defaultSourceRevision, BuildJob.defaultBuildNumber), tester.controller().applications().require(app1.id()).change().application().get()); - tester.deployAndNotify(app1, applicationPackage, true, systemTest); - tester.deployAndNotify(app1, applicationPackage, true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, stagingTest); assertEquals(4, applications.require(app1.id()).deploymentJobs().jobStatus().size()); ApplicationVersion applicationVersion = tester.controller().applications().require(app1.id()).change().application().get(); @@ -106,8 +109,8 @@ public class ControllerTest { tester.clock().advance(Duration.ofSeconds(1)); // production job (failing) after deployment - tester.deploy(productionUsWest1, app1, applicationPackage); - tester.deployAndNotify(app1, applicationPackage, false, productionUsWest1); + tester.deploy(productionUsWest1, instance.id(), applicationPackage); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), false, productionUsWest1); assertEquals(4, applications.require(app1.id()).deploymentJobs().jobStatus().size()); JobStatus expectedJobStatus = JobStatus.initial(productionUsWest1) @@ -115,7 +118,7 @@ public class ControllerTest { .withCompletion(42, Optional.of(JobError.unknown), tester.clock().instant().truncatedTo(MILLIS)) .withTriggering(version1, applicationVersion, - Optional.of(tester.application(app1.id()).deployments().get(productionUsWest1.zone(main))), + Optional.of(tester.instance(app1.id()).deployments().get(productionUsWest1.zone(main))), "", tester.clock().instant().truncatedTo(MILLIS)); // Re-triggering (due to failure) has application version info @@ -137,28 +140,28 @@ public class ControllerTest { // system and staging test job - succeeding tester.jobCompletion(component).application(app1).nextBuildNumber().uploadArtifact(applicationPackage).submit(); - applicationVersion = tester.application("app1").change().application().get(); - tester.deployAndNotify(app1, applicationPackage, true, systemTest); + applicationVersion = tester.instance("app1").change().application().get(); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, systemTest); assertStatus(JobStatus.initial(systemTest) - .withTriggering(version1, applicationVersion, Optional.of(tester.application(app1.id()).deployments().get(productionUsWest1.zone(main))), "", tester.clock().instant().truncatedTo(MILLIS)) + .withTriggering(version1, applicationVersion, Optional.of(tester.instance(app1.id()).deployments().get(productionUsWest1.zone(main))), "", tester.clock().instant().truncatedTo(MILLIS)) .withCompletion(42, Optional.empty(), tester.clock().instant().truncatedTo(MILLIS)), app1.id(), tester.controller()); tester.clock().advance(Duration.ofHours(1)); // Stop retrying tester.jobCompletion(productionUsWest1).application(app1).unsuccessful().submit(); - tester.deployAndNotify(app1, applicationPackage, true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, stagingTest); // production job succeeding now expectedJobStatus = expectedJobStatus - .withTriggering(version1, applicationVersion, Optional.of(tester.application(app1.id()).deployments().get(productionUsWest1.zone(main))), "", tester.clock().instant().truncatedTo(MILLIS)) + .withTriggering(version1, applicationVersion, Optional.of(tester.instance(app1.id()).deployments().get(productionUsWest1.zone(main))), "", tester.clock().instant().truncatedTo(MILLIS)) .withCompletion(42, Optional.empty(), tester.clock().instant().truncatedTo(MILLIS)); - tester.deployAndNotify(app1, applicationPackage, true, productionUsWest1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsWest1); assertStatus(expectedJobStatus, app1.id(), tester.controller()); // causes triggering of next production job assertStatus(JobStatus.initial(productionUsEast3) .withTriggering(version1, applicationVersion, Optional.empty(), "", tester.clock().instant().truncatedTo(MILLIS)), app1.id(), tester.controller()); - tester.deployAndNotify(app1, applicationPackage, true, productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsEast3); assertEquals(5, applications.get(app1.id()).get().deploymentJobs().jobStatus().size()); @@ -183,7 +186,7 @@ public class ControllerTest { .build(); tester.jobCompletion(component).application(app1).nextBuildNumber().nextBuildNumber().uploadArtifact(applicationPackage).submit(); try { - tester.deploy(systemTest, app1, applicationPackage); + tester.deploy(systemTest, instance.id(), applicationPackage); fail("Expected exception due to illegal production deployment removal"); } catch (IllegalArgumentException e) { @@ -206,7 +209,7 @@ public class ControllerTest { .region("us-east-3") .build(); tester.jobCompletion(component).application(app1).nextBuildNumber(2).uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(app1, applicationPackage, true, systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, systemTest); assertNull("Zone was removed", applications.require(app1.id()).deployments().get(productionUsWest1.zone(main))); assertNull("Deployment job was removed", applications.require(app1.id()).deploymentJobs().jobStatus().get(productionUsWest1)); @@ -214,7 +217,7 @@ public class ControllerTest { @Test public void testDeploymentApplicationVersion() { - Instance app = tester.createApplication("app1", "tenant1", 1, 11L); + Application app = tester.createApplication("app1", "tenant1", 1, 11L); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .region("us-west-1") @@ -282,7 +285,7 @@ public class ControllerTest { @Test public void testDnsAliasRegistration() { - Instance instance = tester.createApplication("app1", "tenant1", 1, 1L); + Application application = tester.createApplication("app1", "tenant1", 1, 1L); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) @@ -291,14 +294,14 @@ public class ControllerTest { .region("us-central-1") // Two deployments should result in each DNS alias being registered once .build(); - tester.deployCompletely(instance, applicationPackage); - Collection<Deployment> deployments = tester.application(instance.id()).deployments().values(); + tester.deployCompletely(application, applicationPackage); + Collection<Deployment> deployments = tester.instance(application.id()).deployments().values(); assertFalse(deployments.isEmpty()); for (Deployment deployment : deployments) { assertEquals("Rotation names are passed to config server in " + deployment.zone(), Set.of("rotation-id-01", "app1--tenant1.global.vespa.oath.cloud"), - tester.configServer().rotationNames().get(new DeploymentId(instance.id(), deployment.zone()))); + tester.configServer().rotationNames().get(new DeploymentId(application.id(), deployment.zone()))); } tester.flushDnsRequests(); @@ -312,7 +315,7 @@ public class ControllerTest { @Test public void testDnsAliasRegistrationLegacy() { - Instance instance = tester.createApplication("app1", "tenant1", 1, 1L); + Application application = tester.createApplication("app1", "tenant1", 1, 1L); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) @@ -321,8 +324,8 @@ public class ControllerTest { .region("us-central-1") // Two deployments should result in each DNS alias being registered once .build(); - tester.deployCompletely(instance, applicationPackage); - Collection<Deployment> deployments = tester.application(instance.id()).deployments().values(); + tester.deployCompletely(application, applicationPackage); + Collection<Deployment> deployments = tester.instance(application.id()).deployments().values(); assertFalse(deployments.isEmpty()); for (Deployment deployment : deployments) { assertEquals("Rotation names are passed to config server in " + deployment.zone(), @@ -330,7 +333,7 @@ public class ControllerTest { "app1--tenant1.global.vespa.oath.cloud", "app1.tenant1.global.vespa.yahooapis.com", "app1--tenant1.global.vespa.yahooapis.com"), - tester.configServer().rotationNames().get(new DeploymentId(instance.id(), deployment.zone()))); + tester.configServer().rotationNames().get(new DeploymentId(application.id(), deployment.zone()))); } tester.flushDnsRequests(); assertEquals(3, tester.controllerTester().nameService().records().size()); @@ -353,7 +356,7 @@ public class ControllerTest { @Test public void testDnsAliasRegistrationWithEndpoints() { - Instance instance = tester.createApplication("app1", "tenant1", 1, 1L); + Application application = tester.createApplication("app1", "tenant1", 1, 1L); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) @@ -365,8 +368,8 @@ public class ControllerTest { .region("us-central-1") .build(); - tester.deployCompletely(instance, applicationPackage); - Collection<Deployment> deployments = tester.application(instance.id()).deployments().values(); + tester.deployCompletely(application, applicationPackage); + Collection<Deployment> deployments = tester.instance(application.id()).deployments().values(); assertFalse(deployments.isEmpty()); var notWest = Set.of( @@ -379,7 +382,7 @@ public class ControllerTest { for (Deployment deployment : deployments) { assertEquals("Rotation names are passed to config server in " + deployment.zone(), ZoneId.from("prod.us-west-1").equals(deployment.zone()) ? west : notWest, - tester.configServer().rotationNames().get(new DeploymentId(instance.id(), deployment.zone()))); + tester.configServer().rotationNames().get(new DeploymentId(application.id(), deployment.zone()))); } tester.flushDnsRequests(); @@ -408,7 +411,7 @@ public class ControllerTest { @Test public void testDnsAliasRegistrationWithChangingZones() { - Instance instance = tester.createApplication("app1", "tenant1", 1, 1L); + Application application = tester.createApplication("app1", "tenant1", 1, 1L); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) @@ -417,16 +420,16 @@ public class ControllerTest { .region("us-central-1") .build(); - tester.deployCompletely(instance, applicationPackage); + tester.deployCompletely(application, applicationPackage); assertEquals( Set.of("rotation-id-01", "app1--tenant1.global.vespa.oath.cloud"), - tester.configServer().rotationNames().get(new DeploymentId(instance.id(), ZoneId.from("prod", "us-west-1"))) + tester.configServer().rotationNames().get(new DeploymentId(application.id(), ZoneId.from("prod", "us-west-1"))) ); assertEquals( Set.of("rotation-id-01", "app1--tenant1.global.vespa.oath.cloud"), - tester.configServer().rotationNames().get(new DeploymentId(instance.id(), ZoneId.from("prod", "us-central-1"))) + tester.configServer().rotationNames().get(new DeploymentId(application.id(), ZoneId.from("prod", "us-central-1"))) ); @@ -437,24 +440,24 @@ public class ControllerTest { .region("us-central-1") .build(); - tester.deployCompletely(instance, applicationPackage2, BuildJob.defaultBuildNumber + 1); + tester.deployCompletely(application, applicationPackage2, BuildJob.defaultBuildNumber + 1); assertEquals( Set.of("rotation-id-01", "app1--tenant1.global.vespa.oath.cloud"), - tester.configServer().rotationNames().get(new DeploymentId(instance.id(), ZoneId.from("prod", "us-west-1"))) + tester.configServer().rotationNames().get(new DeploymentId(application.id(), ZoneId.from("prod", "us-west-1"))) ); assertEquals( Set.of(), - tester.configServer().rotationNames().get(new DeploymentId(instance.id(), ZoneId.from("prod", "us-central-1"))) + tester.configServer().rotationNames().get(new DeploymentId(application.id(), ZoneId.from("prod", "us-central-1"))) ); - assertEquals(Set.of(RegionName.from("us-west-1")), tester.application(instance.id()).rotations().get(0).regions()); + assertEquals(Set.of(RegionName.from("us-west-1")), tester.instance(application.id()).rotations().get(0).regions()); } @Test public void testUnassignRotations() { - Instance instance = tester.createApplication("app1", "tenant1", 1, 1L); + Application application = tester.createApplication("app1", "tenant1", 1, 1L); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) @@ -463,7 +466,7 @@ public class ControllerTest { .region("us-central-1") // Two deployments should result in each DNS alias being registered once .build(); - tester.deployCompletely(instance, applicationPackage); + tester.deployCompletely(application, applicationPackage); ApplicationPackage applicationPackage2 = new ApplicationPackageBuilder() .environment(Environment.prod) @@ -471,17 +474,17 @@ public class ControllerTest { .region("us-central-1") // Two deployments should result in each DNS alias being registered once .build(); - tester.deployCompletely(instance, applicationPackage2, BuildJob.defaultBuildNumber + 1); + tester.deployCompletely(application, applicationPackage2, BuildJob.defaultBuildNumber + 1); assertEquals( List.of(AssignedRotation.fromStrings("qrs", "default", "rotation-id-01", Set.of())), - tester.application(instance.id()).rotations() + tester.instance(application.id()).rotations() ); assertEquals( Set.of(), - tester.configServer().rotationNames().get(new DeploymentId(instance.id(), ZoneId.from("prod", "us-west-1"))) + tester.configServer().rotationNames().get(new DeploymentId(application.id(), ZoneId.from("prod", "us-west-1"))) ); } @@ -489,7 +492,7 @@ public class ControllerTest { public void testUpdatesExistingDnsAlias() { // Application 1 is deployed and deleted { - Instance app1 = tester.createApplication("app1", "tenant1", 1, 1L); + Application app1 = tester.createApplication("app1", "tenant1", 1, 1L); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .endpoint("default", "foo") @@ -511,7 +514,7 @@ public class ControllerTest { .allow(ValidationId.deploymentRemoval) .build(); tester.jobCompletion(component).application(app1).nextBuildNumber().uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(app1, applicationPackage, true, systemTest); + tester.deployAndNotify(tester.instance(app1.id()).id(), Optional.of(applicationPackage), true, systemTest); tester.applications().deactivate(app1.id(), ZoneId.from(Environment.test, RegionName.from("us-east-1"))); tester.applications().deactivate(app1.id(), ZoneId.from(Environment.staging, RegionName.from("us-east-3"))); tester.applications().deleteApplication(app1.id().tenant(), app1.id().application(), tester.controllerTester().credentialsFor(app1.id())); @@ -535,7 +538,7 @@ public class ControllerTest { // Application 2 is deployed and assigned same rotation as application 1 had before deletion { - Instance app2 = tester.createApplication("app2", "tenant2", 2, 1L); + Application app2 = tester.createApplication("app2", "tenant2", 2, 1L); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .endpoint("default", "foo") @@ -554,7 +557,7 @@ public class ControllerTest { // Application 1 is recreated, deployed and assigned a new rotation { tester.buildService().clear(); - Instance app1 = tester.createApplication("app1", "tenant1", 1, 1L); + Application app1 = tester.createApplication("app1", "tenant1", 1, 1L); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .endpoint("default", "foo") @@ -562,8 +565,7 @@ public class ControllerTest { .region("us-central-1") .build(); tester.deployCompletely(app1, applicationPackage); - app1 = tester.applications().require(app1.id()); - assertEquals("rotation-id-02", app1.rotations().get(0).rotationId().asString()); + assertEquals("rotation-id-02", tester.instance(app1.id()).rotations().get(0).rotationId().asString()); // DNS records are created for the newly assigned rotation assertEquals(2, tester.controllerTester().nameService().records().size()); @@ -592,7 +594,7 @@ public class ControllerTest { .build(); // Create application - Instance app = tester.createApplication("app1", "tenant1", 1, 2L); + Application app = tester.createApplication("app1", "tenant1", 1, 2L); // Direct deploy is allowed when deployDirectly is true ZoneId zone = ZoneId.from("prod", "cd-us-central-1"); @@ -610,7 +612,7 @@ public class ControllerTest { Version seven = Version.fromString("7.2"); tester.upgradeSystem(seven); tester.controller().applications().deploy(app.id(), zone, Optional.of(applicationPackage), options); - assertEquals(six, tester.application(app.id()).deployments().get(zone).version()); + assertEquals(six, tester.instance(app.id()).deployments().get(zone).version()); } @Test @@ -622,7 +624,7 @@ public class ControllerTest { .build(); // Create application - Instance app = tester.createApplication("app1", "tenant1", 1, 2L); + Application app = tester.createApplication("app1", "tenant1", 1, 2L); ZoneId zone = ZoneId.from("dev", "us-east-1"); // Deploy @@ -636,7 +638,7 @@ public class ControllerTest { @Test public void testSuspension() { - Instance app = tester.createApplication("app1", "tenant1", 1, 11L); + Application app = tester.createApplication("app1", "tenant1", 1, 11L); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .region("us-west-1") @@ -660,7 +662,7 @@ public class ControllerTest { // second time will not fail @Test public void testDeletingApplicationThatHasAlreadyBeenDeleted() { - Instance app = tester.createApplication("app2", "tenant1", 1, 12L); + Application app = tester.createApplication("app2", "tenant1", 1, 12L); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .region("us-east-3") @@ -675,7 +677,7 @@ public class ControllerTest { @Test public void testDeployApplicationPackageWithApplicationDir() { - Instance instance = tester.createApplication("app1", "tenant1", 1, 1L); + Application instance = tester.createApplication("app1", "tenant1", 1, 1L); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .region("us-west-1") @@ -685,7 +687,7 @@ public class ControllerTest { @Test public void testDeployApplicationWithWarnings() { - Instance instance = tester.createApplication("app1", "tenant1", 1, 1L); + Application instance = tester.createApplication("app1", "tenant1", 1, 1L); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .region("us-west-1") @@ -710,7 +712,8 @@ public class ControllerTest { .build(); // Deploy app1 in production tester.deployCompletely(app1, applicationPackage); - var cert = certificate.apply(app1); + Instance instance1 = tester.instance(app1.id()); + var cert = certificate.apply(instance1); assertTrue("Provisions certificate in " + Environment.prod, cert.isPresent()); assertEquals(List.of( "vznqtz7a5ygwjkbhhj7ymxvlrekgt4l6g.vespa.oath.cloud", @@ -728,17 +731,18 @@ public class ControllerTest { // Next deployment reuses certificate tester.deployCompletely(app1, applicationPackage, BuildJob.defaultBuildNumber + 1); - assertEquals(cert, certificate.apply(app1)); + assertEquals(cert, certificate.apply(instance1)); // Create app2 var app2 = tester.createApplication("app2", "tenant2", 3, 4L); + Instance instance2 = tester.instance(app2.id()); ZoneId zone = ZoneId.from("dev", "us-east-1"); // Deploy app2 in dev tester.controller().applications().deploy(app2.id(), zone, Optional.of(applicationPackage), DeployOptions.none()); assertTrue("Application deployed and activated", tester.controllerTester().configServer().application(app2.id(), zone).get().activated()); - assertFalse("Does not provision certificate in " + Environment.dev, certificate.apply(app2).isPresent()); + assertFalse("Does not provision certificate in " + Environment.dev, certificate.apply(instance2).isPresent()); } @Test @@ -805,6 +809,15 @@ public class ControllerTest { newDb.writeInstance(instance2); assertEquals(instance2, oldDb.readInstance(instance2.id()).orElseThrow()); assertEquals(instance2, newDb.readInstance(instance2.id()).orElseThrow()); + + Application application = newDb.readApplication(instance1.id()).orElseThrow(); + assertEquals(new ApplicationSerializer().toSlime(application).toString(), + new InstanceSerializer().toSlime(instance1).toString()); + + oldDb.removeInstance(instance1.id()); + newDb.removeInstance(instance2.id()); + assertEquals(List.of(), oldDb.readInstances()); + assertEquals(List.of(), newDb.readInstances()); } private void runUpgrade(DeploymentTester tester, ApplicationId application, ApplicationVersion version) { @@ -813,11 +826,11 @@ public class ControllerTest { runDeployment(tester, tester.applications().require(application), version, Optional.of(next), Optional.empty()); } - private void runDeployment(DeploymentTester tester, ApplicationId application, ApplicationVersion version, + private void runDeployment(DeploymentTester tester, ApplicationId id, ApplicationVersion version, ApplicationPackage applicationPackage, SourceRevision sourceRevision, long buildNumber) { - Instance app = tester.applications().require(application); + Instance instance = tester.applications().require(id); tester.jobCompletion(component) - .application(app) + .application(tester.application(id)) .buildNumber(buildNumber) .sourceRevision(sourceRevision) .uploadArtifact(applicationPackage) @@ -825,9 +838,9 @@ public class ControllerTest { ApplicationVersion change = ApplicationVersion.from(sourceRevision, buildNumber); assertEquals(change.id(), tester.controller().applications() - .require(application) + .require(id) .change().application().get().id()); - runDeployment(tester, app, version, Optional.empty(), Optional.of(applicationPackage)); + runDeployment(tester, instance, version, Optional.empty(), Optional.of(applicationPackage)); } private void assertStatus(JobStatus expectedStatus, ApplicationId id, Controller controller) { @@ -842,27 +855,27 @@ public class ControllerTest { Version vespaVersion = upgrade.orElseGet(tester::defaultPlatformVersion); // Deploy in test - tester.deployAndNotify(app, applicationPackage, true, systemTest); - tester.deployAndNotify(app, applicationPackage, true, stagingTest); + tester.deployAndNotify(app.id(), applicationPackage, true, systemTest); + tester.deployAndNotify(app.id(), applicationPackage, true, stagingTest); JobStatus expected = JobStatus.initial(stagingTest) - .withTriggering(vespaVersion, version, Optional.ofNullable(tester.application(app.id()).deployments().get(productionUsWest1.zone(main))), "", + .withTriggering(vespaVersion, version, Optional.ofNullable(tester.instance(app.id()).deployments().get(productionUsWest1.zone(main))), "", tester.clock().instant().truncatedTo(MILLIS)) .withCompletion(42, Optional.empty(), tester.clock().instant().truncatedTo(MILLIS)); assertStatus(expected, app.id(), tester.controller()); // Deploy in production expected = JobStatus.initial(productionUsWest1) - .withTriggering(vespaVersion, version, Optional.ofNullable(tester.application(app.id()).deployments().get(productionUsWest1.zone(main))), "", + .withTriggering(vespaVersion, version, Optional.ofNullable(tester.instance(app.id()).deployments().get(productionUsWest1.zone(main))), "", tester.clock().instant().truncatedTo(MILLIS)) .withCompletion(42, Optional.empty(), tester.clock().instant().truncatedTo(MILLIS)); - tester.deployAndNotify(app, applicationPackage, true, productionUsWest1); + tester.deployAndNotify(app.id(), applicationPackage, true, productionUsWest1); assertStatus(expected, app.id(), tester.controller()); expected = JobStatus.initial(productionUsEast3) - .withTriggering(vespaVersion, version, Optional.ofNullable(tester.application(app.id()).deployments().get(productionUsEast3.zone(main))), "", + .withTriggering(vespaVersion, version, Optional.ofNullable(tester.instance(app.id()).deployments().get(productionUsEast3.zone(main))), "", tester.clock().instant().truncatedTo(MILLIS)) .withCompletion(42, Optional.empty(), tester.clock().instant().truncatedTo(MILLIS)); - tester.deployAndNotify(app, applicationPackage, true, productionUsEast3); + tester.deployAndNotify(app.id(), applicationPackage, true, productionUsEast3); assertStatus(expected, app.id(), tester.controller()); // Verify deployed version diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java index 6744bdea985..07c24030992 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java @@ -126,8 +126,11 @@ public final class ControllerTester { .ifPresent(configureFunc); } - public static BuildService.BuildJob buildJob(Instance instance, JobType jobType) { - return BuildService.BuildJob.of(instance.id(), instance.deploymentJobs().projectId().getAsLong(), jobType.jobName()); + public static BuildService.BuildJob buildJob(ApplicationId id, JobType jobType) { + if (jobType == JobType.component) + throw new AssertionError("Not supposed to happen"); + + return BuildService.BuildJob.of(id, 0, jobType.jobName()); } public Controller controller() { return controller; } @@ -157,27 +160,24 @@ public final class ControllerTester { } /** Creates the given tenant and application and deploys it */ - public Instance createAndDeploy(String tenantName, String domainName, String applicationName, Environment environment, long projectId, Long propertyId) { - return createAndDeploy(tenantName, domainName, applicationName, toZone(environment), projectId, propertyId); + public void createAndDeploy(String tenantName, String domainName, String applicationName, Environment environment, long projectId, Long propertyId) { + createAndDeploy(tenantName, domainName, applicationName, toZone(environment), projectId, propertyId); } /** Creates the given tenant and application and deploys it */ - public Instance createAndDeploy(String tenantName, String domainName, String applicationName, + public void createAndDeploy(String tenantName, String domainName, String applicationName, String instanceName, ZoneId zone, long projectId, Long propertyId) { - TenantName tenant = createTenant(tenantName, domainName, propertyId); - Instance instance = createApplication(tenant, applicationName, instanceName, projectId); - deploy(instance, zone); - return instance; + throw new AssertionError("Not supposed to use this"); } /** Creates the given tenant and application and deploys it */ - public Instance createAndDeploy(String tenantName, String domainName, String applicationName, ZoneId zone, long projectId, Long propertyId) { - return createAndDeploy(tenantName, domainName, applicationName, "default", zone, projectId, propertyId); + public void createAndDeploy(String tenantName, String domainName, String applicationName, ZoneId zone, long projectId, Long propertyId) { + createAndDeploy(tenantName, domainName, applicationName, "default", zone, projectId, propertyId); } /** Creates the given tenant and application and deploys it */ - public Instance createAndDeploy(String tenantName, String domainName, String applicationName, Environment environment, long projectId) { - return createAndDeploy(tenantName, domainName, applicationName, environment, projectId, null); + public void createAndDeploy(String tenantName, String domainName, String applicationName, Environment environment, long projectId) { + createAndDeploy(tenantName, domainName, applicationName, environment, projectId, null); } /** Create application from slime */ @@ -241,32 +241,32 @@ public final class ControllerTester { new OktaAccessToken("okta-token"))); } - public Instance createApplication(TenantName tenant, String applicationName, String instanceName, long projectId) { + public Application createApplication(TenantName tenant, String applicationName, String instanceName, long projectId) { ApplicationId applicationId = ApplicationId.from(tenant.value(), applicationName, instanceName); controller().applications().createApplication(applicationId, credentialsFor(applicationId)); - controller().applications().lockOrThrow(applicationId, lockedInstance -> - controller().applications().store(lockedInstance.withProjectId(OptionalLong.of(projectId)))); - return controller().applications().require(applicationId); + controller().applications().lockApplicationOrThrow(applicationId, application -> + controller().applications().store(application.withProjectId(OptionalLong.of(projectId)))); + return controller().applications().requireApplication(applicationId); } - public void deploy(Instance instance, ZoneId zone) { - deploy(instance, zone, new ApplicationPackage(new byte[0])); + public void deploy(ApplicationId id, ZoneId zone) { + deploy(id, zone, new ApplicationPackage(new byte[0])); } - public void deploy(Instance instance, ZoneId zone, ApplicationPackage applicationPackage) { - deploy(instance, zone, applicationPackage, false); + public void deploy(ApplicationId id, ZoneId zone, ApplicationPackage applicationPackage) { + deploy(id, zone, applicationPackage, false); } - public void deploy(Instance instance, ZoneId zone, ApplicationPackage applicationPackage, boolean deployCurrentVersion) { - deploy(instance, zone, Optional.of(applicationPackage), deployCurrentVersion); + public void deploy(ApplicationId id, ZoneId zone, ApplicationPackage applicationPackage, boolean deployCurrentVersion) { + deploy(id, zone, Optional.of(applicationPackage), deployCurrentVersion); } - public void deploy(Instance instance, ZoneId zone, Optional<ApplicationPackage> applicationPackage, boolean deployCurrentVersion) { - deploy(instance, zone, applicationPackage, deployCurrentVersion, Optional.empty()); + public void deploy(ApplicationId id, ZoneId zone, Optional<ApplicationPackage> applicationPackage, boolean deployCurrentVersion) { + deploy(id, zone, applicationPackage, deployCurrentVersion, Optional.empty()); } - public void deploy(Instance instance, ZoneId zone, Optional<ApplicationPackage> applicationPackage, boolean deployCurrentVersion, Optional<Version> version) { - controller().applications().deploy(instance.id(), + public void deploy(ApplicationId id, ZoneId zone, Optional<ApplicationPackage> applicationPackage, boolean deployCurrentVersion, Optional<Version> version) { + controller().applications().deploy(id, zone, applicationPackage, new DeployOptions(false, version, false, deployCurrentVersion)); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/BuildJob.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/BuildJob.java index 7b2aba296a4..afe4a1dba1f 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/BuildJob.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/BuildJob.java @@ -2,7 +2,7 @@ package com.yahoo.vespa.hosted.controller.deployment; import com.yahoo.config.provision.ApplicationId; -import com.yahoo.vespa.hosted.controller.Instance; +import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion; import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; import com.yahoo.vespa.hosted.controller.api.integration.deployment.SourceRevision; @@ -51,10 +51,10 @@ public class BuildJob { return this; } - public BuildJob application(Instance instance) { - this.applicationId = instance.id(); - if (instance.deploymentJobs().projectId().isPresent()) { - this.projectId = instance.deploymentJobs().projectId().getAsLong(); + public BuildJob application(Application application) { + this.applicationId = application.id(); + if (application.deploymentJobs().projectId().isPresent()) { + this.projectId = application.deploymentJobs().projectId().getAsLong(); } return this; } 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 02b45b77769..c1d8c32f516 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 @@ -7,6 +7,7 @@ import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.TenantName; import com.yahoo.config.provision.zone.ZoneApi; import com.yahoo.test.ManualClock; +import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.Instance; import com.yahoo.vespa.hosted.controller.ApplicationController; import com.yahoo.vespa.hosted.controller.Controller; @@ -112,11 +113,15 @@ public class DeploymentTester { public ConfigServerMock configServer() { return tester.serviceRegistry().configServerMock(); } - public Instance application(String name) { - return application(ApplicationId.from("tenant1", name, "default")); + public Application application(ApplicationId id) { + return controller().applications().requireApplication(id); } - public Instance application(ApplicationId application) { + public Instance instance(String name) { + return instance(ApplicationId.from("tenant1", name, "default")); + } + + public Instance instance(ApplicationId application) { return controller().applications().require(application); } @@ -169,11 +174,11 @@ public class DeploymentTester { return configServer().initialVersion(); } - public Instance createApplication(String applicationName, String tenantName, long projectId, long propertyId) { + public Application createApplication(String applicationName, String tenantName, long projectId, long propertyId) { return createApplication("default", applicationName, tenantName, projectId, propertyId); } - public Instance createApplication(String instanceName, String applicationName, String tenantName, long projectId, long propertyId) { + public Application createApplication(String instanceName, String applicationName, String tenantName, long projectId, long propertyId) { TenantName tenant = tester.createTenant(tenantName, UUID.randomUUID().toString(), propertyId); return tester.createApplication(tenant, applicationName, instanceName, projectId); } @@ -191,130 +196,134 @@ public class DeploymentTester { } /** Simulate the full lifecycle of an application deployment as declared in given application package */ - public Instance createAndDeploy(String applicationName, int projectId, ApplicationPackage applicationPackage) { + public Application createAndDeploy(String applicationName, int projectId, ApplicationPackage applicationPackage) { TenantName tenant = tester.createTenant("tenant1", "domain1", 1L); return createAndDeploy(tenant, applicationName, projectId, applicationPackage); } /** Simulate the full lifecycle of an application deployment as declared in given application package */ - public Instance createAndDeploy(TenantName tenant, String applicationName, int projectId, ApplicationPackage applicationPackage) { - Instance instance = tester.createApplication(tenant, applicationName, "default", projectId); - deployCompletely(instance, applicationPackage); - return applications().require(instance.id()); + public Application createAndDeploy(TenantName tenant, String applicationName, int projectId, ApplicationPackage applicationPackage) { + Application application = tester.createApplication(tenant, applicationName, "default", projectId); + deployCompletely(application, applicationPackage); + return applications().requireApplication(application.id()); } /** Simulate the full lifecycle of an application deployment to prod.us-west-1 with the given upgrade policy */ - public Instance createAndDeploy(String applicationName, int projectId, String upgradePolicy) { + public Application createAndDeploy(String applicationName, int projectId, String upgradePolicy) { return createAndDeploy(applicationName, projectId, applicationPackage(upgradePolicy)); } /** Simulate the full lifecycle of an application deployment to prod.us-west-1 with the given upgrade policy */ - public Instance createAndDeploy(TenantName tenant, String applicationName, int projectId, String upgradePolicy) { - return createAndDeploy(tenant, applicationName, projectId, applicationPackage(upgradePolicy)); + public void createAndDeploy(TenantName tenant, String applicationName, int projectId, String upgradePolicy) { + createAndDeploy(tenant, applicationName, projectId, applicationPackage(upgradePolicy)); } /** Deploy application completely using the given application package */ - public void deployCompletely(Instance instance, ApplicationPackage applicationPackage) { - deployCompletely(instance, applicationPackage, BuildJob.defaultBuildNumber); + public void deployCompletely(Application application, ApplicationPackage applicationPackage) { + deployCompletely(application, applicationPackage, BuildJob.defaultBuildNumber); } - public void completeDeploymentWithError(Instance instance, ApplicationPackage applicationPackage, long buildNumber, JobType failOnJob) { - jobCompletion(JobType.component).application(instance) + public void completeDeploymentWithError(Application application, ApplicationPackage applicationPackage, long buildNumber, JobType failOnJob) { + jobCompletion(JobType.component).application(application) .buildNumber(buildNumber) .uploadArtifact(applicationPackage) .submit(); - completeDeployment(instance, applicationPackage, Optional.ofNullable(failOnJob)); + completeDeployment(application, applicationPackage, Optional.ofNullable(failOnJob)); } - public void deployCompletely(Instance instance, ApplicationPackage applicationPackage, long buildNumber) { - completeDeploymentWithError(instance, applicationPackage, buildNumber, null); + public void deployCompletely(Application application, ApplicationPackage applicationPackage, long buildNumber) { + completeDeploymentWithError(application, applicationPackage, buildNumber, null); } - private void completeDeployment(Instance instance, ApplicationPackage applicationPackage, Optional<JobType> failOnJob) { - assertTrue(instance.id() + " has pending changes to deploy", applications().require(instance.id()).change().hasTargets()); + private void completeDeployment(Application application, ApplicationPackage applicationPackage, Optional<JobType> failOnJob) { + assertTrue(application.id() + " has pending changes to deploy", applications().require(application.id()).change().hasTargets()); DeploymentSteps steps = controller().applications().deploymentTrigger().steps(applicationPackage.deploymentSpec()); List<JobType> jobs = steps.jobs(); + // TODO jonmv: Change to list instances here. for (JobType job : jobs) { boolean failJob = failOnJob.map(j -> j.equals(job)).orElse(false); - deployAndNotify(instance, applicationPackage, ! failJob, job); + deployAndNotify(application.id(), applicationPackage, ! failJob, job); if (failJob) { break; } } if (failOnJob.isPresent()) { - assertTrue(applications().require(instance.id()).change().hasTargets()); - assertTrue(applications().require(instance.id()).deploymentJobs().hasFailures()); + assertTrue(applications().require(application.id()).change().hasTargets()); + assertTrue(applications().require(application.id()).deploymentJobs().hasFailures()); } else { - assertFalse(applications().require(instance.id()).change().hasTargets()); + assertFalse(applications().require(application.id()).change().hasTargets()); } if (updateDnsAutomatically) { flushDnsRequests(); } } - public void completeUpgrade(Instance instance, Version version, String upgradePolicy) { - completeUpgrade(instance, version, applicationPackage(upgradePolicy)); + public void completeUpgrade(Application application, Version version, String upgradePolicy) { + completeUpgrade(application, version, applicationPackage(upgradePolicy)); } - public void completeUpgrade(Instance instance, Version version, ApplicationPackage applicationPackage) { - assertTrue(instance + " has a change", applications().require(instance.id()).change().hasTargets()); - assertEquals(Change.of(version), applications().require(instance.id()).change()); - completeDeployment(instance, applicationPackage, Optional.empty()); + public void completeUpgrade(Application application, Version version, ApplicationPackage applicationPackage) { + assertTrue(application + " has a change", applications().require(application.id()).change().hasTargets()); + assertEquals(Change.of(version), applications().require(application.id()).change()); + completeDeployment(application, applicationPackage, Optional.empty()); } - public void completeUpgradeWithError(Instance instance, Version version, String upgradePolicy, JobType failOnJob) { - completeUpgradeWithError(instance, version, applicationPackage(upgradePolicy), Optional.of(failOnJob)); + public void completeUpgradeWithError(Application application, Version version, String upgradePolicy, JobType failOnJob) { + completeUpgradeWithError(application, version, applicationPackage(upgradePolicy), Optional.of(failOnJob)); } - public void completeUpgradeWithError(Instance instance, Version version, ApplicationPackage applicationPackage, JobType failOnJob) { - completeUpgradeWithError(instance, version, applicationPackage, Optional.of(failOnJob)); + public void completeUpgradeWithError(Application application, Version version, ApplicationPackage applicationPackage, JobType failOnJob) { + completeUpgradeWithError(application, version, applicationPackage, Optional.of(failOnJob)); } - private void completeUpgradeWithError(Instance instance, Version version, ApplicationPackage applicationPackage, Optional<JobType> failOnJob) { - assertTrue(applications().require(instance.id()).change().hasTargets()); - assertEquals(Change.of(version), applications().require(instance.id()).change()); - completeDeployment(instance, applicationPackage, failOnJob); + private void completeUpgradeWithError(Application application, Version version, ApplicationPackage applicationPackage, Optional<JobType> failOnJob) { + assertTrue(applications().require(application.id()).change().hasTargets()); + assertEquals(Change.of(version), applications().require(application.id()).change()); + completeDeployment(application, applicationPackage, failOnJob); } - public void deploy(JobType job, Instance instance, ApplicationPackage applicationPackage) { - deploy(job, instance, Optional.of(applicationPackage), false); + public void deploy(JobType job, ApplicationId id, ApplicationPackage applicationPackage) { + deploy(job, id, Optional.of(applicationPackage), false); } - public void deploy(JobType job, Instance instance, ApplicationPackage applicationPackage, + public void deploy(JobType job, ApplicationId id, ApplicationPackage applicationPackage, boolean deployCurrentVersion) { - deploy(job, instance, Optional.of(applicationPackage), deployCurrentVersion); + deploy(job, id, Optional.of(applicationPackage), deployCurrentVersion); } - public void deploy(JobType job, Instance instance, Optional<ApplicationPackage> applicationPackage, + public void deploy(JobType job, ApplicationId id, Optional<ApplicationPackage> applicationPackage, boolean deployCurrentVersion) { - tester.deploy(instance, job.zone(controller().system()), applicationPackage, deployCurrentVersion); + tester.deploy(id, job.zone(controller().system()), applicationPackage, deployCurrentVersion); } - public void deployAndNotify(Instance instance, String upgradePolicy, boolean success, JobType job) { - deployAndNotify(instance, applicationPackage(upgradePolicy), success, job); + public void deployAndNotify(Instance i, String upgradePolicy, boolean success, JobType job) { + deployAndNotify(i.id(), applicationPackage(upgradePolicy), success, job); } - public void deployAndNotify(Instance instance, ApplicationPackage applicationPackage, boolean success, JobType job) { - deployAndNotify(instance, Optional.of(applicationPackage), success, job); + public void deployAndNotify(ApplicationId id, ApplicationPackage applicationPackage, boolean success, JobType job) { + deployAndNotify(id, Optional.of(applicationPackage), success, job); } - public void deployAndNotify(Instance instance, boolean success, JobType job) { - deployAndNotify(instance, Optional.empty(), success, job); + public void deployAndNotify(Instance i, boolean success, JobType job) { + deployAndNotify(i.id(), Optional.empty(), success, job); + } + public void deployAndNotify(ApplicationId id, boolean success, JobType job) { + deployAndNotify(id, Optional.empty(), success, job); } - public void deployAndNotify(Instance instance, Optional<ApplicationPackage> applicationPackage, boolean success, JobType job) { + public void deployAndNotify(ApplicationId id, Optional<ApplicationPackage> applicationPackage, boolean success, JobType job) { if (success) { // Staging deploys twice, once with current version and once with new version if (job == JobType.stagingTest) { - deploy(job, instance, applicationPackage, true); + deploy(job, id, applicationPackage, true); } - deploy(job, instance, applicationPackage, false); + deploy(job, id, applicationPackage, false); } // Deactivate test deployments after deploy. This replicates the behaviour of the tenant pipeline if (job.isTest()) { - controller().applications().deactivate(instance.id(), job.zone(controller().system())); + controller().applications().deactivate(id, job.zone(controller().system())); } - jobCompletion(job).application(instance).success(success).submit(); + jobCompletion(job).application(id).success(success).submit(); } public Optional<JobStatus.JobRun> firstFailing(Instance instance, JobType job) { @@ -350,7 +359,7 @@ public class DeploymentTester { } private boolean isRunning(JobType job, ApplicationId application) { - return buildService().jobs().contains(ControllerTester.buildJob(application(application), job)); + return buildService().jobs().contains(ControllerTester.buildJob(instance(application).id(), job)); } } 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 7cb520f0fd9..389c1112dad 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java @@ -7,8 +7,8 @@ import com.yahoo.config.provision.TenantName; import com.yahoo.config.provision.zone.ZoneId; import com.yahoo.slime.Slime; import com.yahoo.vespa.config.SlimeUtils; +import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.Instance; -import com.yahoo.vespa.hosted.controller.ControllerTester; import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId; import com.yahoo.vespa.hosted.controller.api.integration.BuildService; import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion; @@ -68,7 +68,8 @@ public class DeploymentTriggerTest { @Test public void testTriggerFailing() { - Instance app = tester.createApplication("app1", "tenant1", 1, 1L); + Application app = tester.createApplication("app1", "tenant1", 1, 1L); + Instance instance = tester.instance(app.id()); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .upgradePolicy("default") .environment(Environment.prod) @@ -80,37 +81,39 @@ public class DeploymentTriggerTest { // Deploy completely once tester.jobCompletion(component).application(app).uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(app, applicationPackage, true, JobType.systemTest); - tester.deployAndNotify(app, applicationPackage, true, JobType.stagingTest); - tester.deployAndNotify(app, applicationPackage, true, JobType.productionUsWest1); + tester.deployAndNotify(instance.id(), applicationPackage, true, JobType.systemTest); + tester.deployAndNotify(instance.id(), applicationPackage, true, JobType.stagingTest); + tester.deployAndNotify(instance.id(), applicationPackage, true, JobType.productionUsWest1); // New version is released version = Version.fromString("6.3"); tester.upgradeSystem(version); // staging-test times out and is retried - tester.buildService().remove(buildJob(app, stagingTest)); + tester.buildService().remove(buildJob(app.id(), stagingTest)); tester.readyJobTrigger().maintain(); assertEquals("Retried dead job", 2, tester.buildService().jobs().size()); tester.assertRunning(stagingTest, app.id()); - tester.deployAndNotify(app, applicationPackage, true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, stagingTest); // system-test is now the only running job -- production jobs haven't started yet, since it is unfinished. tester.assertRunning(systemTest, app.id()); assertEquals(1, tester.buildService().jobs().size()); // system-test fails and is retried - tester.deployAndNotify(app, applicationPackage, false, JobType.systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), false, JobType.systemTest); assertEquals("Job is retried on failure", 1, tester.buildService().jobs().size()); - tester.deployAndNotify(app, applicationPackage, true, JobType.systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.systemTest); tester.assertRunning(productionUsWest1, app.id()); } @Test public void testIndependentInstances() { - Instance instance1 = tester.createApplication("instance1", "app", "tenant", 1, 1L); - Instance instance2 = tester.createApplication("instance2", "app", "tenant", 2, 1L); + Application app1 = tester.createApplication("instance1", "app", "tenant", 1, 1L); + Application app2 = tester.createApplication("instance2", "app", "tenant", 2, 1L); + Instance instance1 = tester.instance(app1.id()); + Instance instance2 = tester.instance(app2.id()); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .upgradePolicy("default") .environment(Environment.prod) @@ -121,27 +124,27 @@ public class DeploymentTriggerTest { tester.upgradeSystem(version); // Deploy completely once - tester.jobCompletion(component).application(instance1).uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(instance1, applicationPackage, true, JobType.systemTest); - tester.deployAndNotify(instance1, applicationPackage, true, JobType.stagingTest); - tester.deployAndNotify(instance1, applicationPackage, true, JobType.productionUsWest1); + tester.jobCompletion(component).application(app1).uploadArtifact(applicationPackage).submit(); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, JobType.systemTest); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, JobType.stagingTest); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, JobType.productionUsWest1); - tester.jobCompletion(component).application(instance2).uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(instance2, applicationPackage, true, JobType.systemTest); - tester.deployAndNotify(instance2, applicationPackage, true, JobType.stagingTest); - tester.deployAndNotify(instance2, applicationPackage, true, JobType.productionUsWest1); + tester.jobCompletion(component).application(app2).uploadArtifact(applicationPackage).submit(); + tester.deployAndNotify(instance2.id(), Optional.of(applicationPackage), true, JobType.systemTest); + tester.deployAndNotify(instance2.id(), Optional.of(applicationPackage), true, JobType.stagingTest); + tester.deployAndNotify(instance2.id(), Optional.of(applicationPackage), true, JobType.productionUsWest1); // New version is released Version newVersion = Version.fromString("6.3"); tester.upgradeSystem(newVersion); // instance1 upgrades, but not instance 2 - tester.deployAndNotify(instance1, applicationPackage, true, JobType.systemTest); - tester.deployAndNotify(instance1, applicationPackage, true, JobType.stagingTest); - tester.deployAndNotify(instance1, applicationPackage, true, JobType.productionUsWest1); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, JobType.systemTest); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, JobType.stagingTest); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, JobType.productionUsWest1); - Version instance1Version = tester.application(instance1.id()).deployments().get(JobType.productionUsWest1.zone(main)).version(); - Version instance2Version = tester.application(instance2.id()).deployments().get(JobType.productionUsWest1.zone(main)).version(); + Version instance1Version = tester.instance(app1.id()).deployments().get(JobType.productionUsWest1.zone(main)).version(); + Version instance2Version = tester.instance(app2.id()).deployments().get(JobType.productionUsWest1.zone(main)).version(); assertEquals(newVersion, instance1Version); assertEquals(version, instance2Version); @@ -152,26 +155,27 @@ public class DeploymentTriggerTest { InternalDeploymentTester iTester = new InternalDeploymentTester(); DeploymentTester tester = iTester.tester(); - Instance app = iTester.app(); + Instance instance = iTester.instance(); + Application application = tester.application(instance.id()); ApplicationPackage applicationPackage = InternalDeploymentTester.applicationPackage; - tester.jobCompletion(component).application(app).uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(app, true, systemTest); - tester.deployAndNotify(app, true, stagingTest); - tester.assertRunning(productionUsCentral1, app.id()); + tester.jobCompletion(component).application(application).uploadArtifact(applicationPackage).submit(); + tester.deployAndNotify(instance.id(), Optional.empty(), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, stagingTest); + tester.assertRunning(productionUsCentral1, instance.id()); // Jobs run externally are not affected. - tester.jobCompletion(component).application(app).nextBuildNumber().uploadArtifact(applicationPackage).submit(); - tester.assertRunning(productionUsCentral1, app.id()); - - tester.applications().deploymentTrigger().cancelChange(app.id(), ALL); - tester.deployAndNotify(app, false, systemTest); - tester.deployAndNotify(app, false, stagingTest); - tester.deployAndNotify(app, false, productionUsCentral1); - assertEquals(Change.empty(), tester.application(app.id()).change()); - tester.assertNotRunning(systemTest, app.id()); - tester.assertNotRunning(stagingTest, app.id()); - tester.assertNotRunning(productionUsCentral1, app.id()); + tester.jobCompletion(component).application(application).nextBuildNumber().uploadArtifact(applicationPackage).submit(); + tester.assertRunning(productionUsCentral1, instance.id()); + + tester.applications().deploymentTrigger().cancelChange(instance.id(), ALL); + tester.deployAndNotify(instance.id(), Optional.empty(), false, systemTest); + tester.deployAndNotify(instance.id(), Optional.empty(), false, stagingTest); + tester.deployAndNotify(instance.id(), Optional.empty(), false, productionUsCentral1); + assertEquals(Change.empty(), tester.instance(instance.id()).change()); + tester.assertNotRunning(systemTest, instance.id()); + tester.assertNotRunning(stagingTest, instance.id()); + tester.assertNotRunning(productionUsCentral1, instance.id()); RunId id = iTester.newRun(productionUsCentral1); assertTrue(iTester.jobs().active(id).isPresent()); @@ -194,7 +198,7 @@ public class DeploymentTriggerTest { tester.readyJobTrigger().maintain(); iTester.runJob(JobType.productionUsWest1); iTester.runJob(JobType.productionUsEast3); - assertEquals(Change.empty(), iTester.app().change()); + assertEquals(Change.empty(), iTester.instance().change()); tester.upgradeSystem(new Version("8.9")); iTester.runJob(JobType.systemTest); @@ -213,7 +217,8 @@ public class DeploymentTriggerTest { public void deploymentSpecDecidesTriggerOrder() { TenantName tenant = tester.controllerTester().createTenant("tenant1", "domain1", 1L); MockBuildService mockBuildService = tester.buildService(); - Instance instance = tester.controllerTester().createApplication(tenant, "app1", "default", 1L); + Application application = tester.controllerTester().createApplication(tenant, "app1", "default", 1L); + Instance instance = tester.instance(application.id()); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .region("us-east-3") @@ -222,21 +227,22 @@ public class DeploymentTriggerTest { .build(); // Component job finishes - tester.jobCompletion(component).application(instance).uploadArtifact(applicationPackage).submit(); + tester.jobCompletion(component).application(application).uploadArtifact(applicationPackage).submit(); // Application is deployed to all test environments and declared zones - tester.deployAndNotify(instance, applicationPackage, true, JobType.systemTest); - tester.deployAndNotify(instance, applicationPackage, true, JobType.stagingTest); - tester.deployAndNotify(instance, applicationPackage, true, JobType.productionUsEast3); - tester.deployAndNotify(instance, applicationPackage, true, JobType.productionUsCentral1); - tester.deployAndNotify(instance, applicationPackage, true, JobType.productionUsWest1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.productionUsCentral1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.productionUsWest1); assertTrue("All jobs consumed", mockBuildService.jobs().isEmpty()); } @Test public void deploymentsSpecWithDelays() { MockBuildService mockBuildService = tester.buildService(); - Instance instance = tester.createApplication("app1", "tenant1", 1, 1L); + Application application = tester.createApplication("app1", "tenant1", 1, 1L); + Instance instance = tester.instance(application.id()); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) @@ -249,11 +255,11 @@ public class DeploymentTriggerTest { .build(); // Component job finishes - tester.jobCompletion(component).application(instance).uploadArtifact(applicationPackage).submit(); + tester.jobCompletion(component).application(application).uploadArtifact(applicationPackage).submit(); // Test jobs pass - tester.deployAndNotify(instance, applicationPackage, true, JobType.systemTest); - tester.deployAndNotify(instance, applicationPackage, true, JobType.stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.stagingTest); tester.deploymentTrigger().triggerReadyJobs(); // No jobs have started yet, as 30 seconds have not yet passed. @@ -263,16 +269,16 @@ public class DeploymentTriggerTest { // 30 seconds later, the first jobs may trigger. assertEquals(1, mockBuildService.jobs().size()); - tester.assertRunning(productionUsWest1, instance.id()); + tester.assertRunning(productionUsWest1, application.id()); // 3 minutes pass, delayed trigger does nothing as us-west-1 is still in progress tester.clock().advance(Duration.ofMinutes(3)); tester.deploymentTrigger().triggerReadyJobs(); assertEquals(1, mockBuildService.jobs().size()); - tester.assertRunning(productionUsWest1, instance.id()); + tester.assertRunning(productionUsWest1, application.id()); // us-west-1 completes - tester.deployAndNotify(instance, applicationPackage, true, productionUsWest1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsWest1); // Delayed trigger does nothing as not enough time has passed after us-west-1 completion tester.deploymentTrigger().triggerReadyJobs(); @@ -286,7 +292,7 @@ public class DeploymentTriggerTest { // 4 minutes pass, us-central-1 is triggered tester.clock().advance(Duration.ofMinutes(1)); tester.deploymentTrigger().triggerReadyJobs(); - tester.deployAndNotify(instance, applicationPackage, true, JobType.productionUsCentral1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.productionUsCentral1); assertTrue("All jobs consumed", mockBuildService.jobs().isEmpty()); // Delayed trigger job runs again, with nothing to trigger @@ -297,7 +303,8 @@ public class DeploymentTriggerTest { @Test public void deploymentSpecWithParallelDeployments() { - Instance instance = tester.createApplication("app1", "tenant1", 1, 1L); + Application application = tester.createApplication("app1", "tenant1", 1, 1L); + Instance instance = tester.instance(application.id()); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) @@ -307,75 +314,76 @@ public class DeploymentTriggerTest { .build(); // Component job finishes - tester.jobCompletion(component).application(instance).uploadArtifact(applicationPackage).submit(); + tester.jobCompletion(component).application(application).uploadArtifact(applicationPackage).submit(); // Test jobs pass - tester.deployAndNotify(instance, applicationPackage, true, JobType.systemTest); - tester.deployAndNotify(instance, applicationPackage, true, JobType.stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.stagingTest); // Deploys in first region assertEquals(1, tester.buildService().jobs().size()); - tester.deployAndNotify(instance, applicationPackage, true, JobType.productionUsCentral1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.productionUsCentral1); // Deploys in two regions in parallel assertEquals(2, tester.buildService().jobs().size()); - tester.assertRunning(productionUsEast3, instance.id()); - tester.assertRunning(productionUsWest1, instance.id()); + tester.assertRunning(productionUsEast3, application.id()); + tester.assertRunning(productionUsWest1, application.id()); - tester.deploy(JobType.productionUsWest1, instance, applicationPackage, false); - tester.jobCompletion(JobType.productionUsWest1).application(instance).submit(); + tester.deploy(JobType.productionUsWest1, instance.id(), applicationPackage, false); + tester.jobCompletion(JobType.productionUsWest1).application(application).submit(); assertEquals("One job still running.", JobType.productionUsEast3.jobName(), tester.buildService().jobs().get(0).jobName()); - tester.deploy(JobType.productionUsEast3, instance, applicationPackage, false); - tester.jobCompletion(JobType.productionUsEast3).application(instance).submit(); + tester.deploy(JobType.productionUsEast3, instance.id(), applicationPackage, false); + tester.jobCompletion(JobType.productionUsEast3).application(application).submit(); // Last region completes assertEquals(1, tester.buildService().jobs().size()); - tester.deployAndNotify(instance, applicationPackage, true, JobType.productionEuWest1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.productionEuWest1); assertTrue("All jobs consumed", tester.buildService().jobs().isEmpty()); } @Test public void testNoOtherChangesDuringSuspension() { // Application is deployed in 3 regions: - Instance instance = tester.createApplication("app1", "tenant1", 1, 1L); + Application application = tester.createApplication("app1", "tenant1", 1, 1L); + Instance instance = tester.instance(application.id()); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .region("us-central-1") .parallel("us-west-1", "us-east-3") .build(); tester.jobCompletion(component) - .application(instance) + .application(application) .uploadArtifact(applicationPackage) .submit(); - tester.deployAndNotify(instance, applicationPackage, true, JobType.systemTest); - tester.deployAndNotify(instance, applicationPackage, true, JobType.stagingTest); - tester.deployAndNotify(instance, applicationPackage, true, JobType.productionUsCentral1); - tester.deployAndNotify(instance, applicationPackage, true, JobType.productionUsWest1); - tester.deployAndNotify(instance, applicationPackage, true, JobType.productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.productionUsCentral1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.productionUsWest1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.productionUsEast3); // The first production zone is suspended: - tester.configServer().setSuspended(new DeploymentId(instance.id(), JobType.productionUsCentral1.zone(tester.controller().system())), true); + tester.configServer().setSuspended(new DeploymentId(application.id(), JobType.productionUsCentral1.zone(tester.controller().system())), true); // A new change needs to be pushed out, but should not go beyond the suspended zone: tester.jobCompletion(component) - .application(instance) + .application(application) .nextBuildNumber() .sourceRevision(new SourceRevision("repository1", "master", "cafed00d")) .uploadArtifact(applicationPackage) .submit(); - tester.deployAndNotify(instance, applicationPackage, true, JobType.systemTest); - tester.deployAndNotify(instance, applicationPackage, true, JobType.stagingTest); - tester.deployAndNotify(instance, applicationPackage, true, JobType.productionUsCentral1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.productionUsCentral1); tester.triggerUntilQuiescence(); - tester.assertNotRunning(JobType.productionUsEast3, instance.id()); - tester.assertNotRunning(JobType.productionUsWest1, instance.id()); + tester.assertNotRunning(JobType.productionUsEast3, application.id()); + tester.assertNotRunning(JobType.productionUsWest1, application.id()); // The zone is unsuspended so jobs start: - tester.configServer().setSuspended(new DeploymentId(instance.id(), JobType.productionUsCentral1.zone(tester.controller().system())), false); + tester.configServer().setSuspended(new DeploymentId(application.id(), JobType.productionUsCentral1.zone(tester.controller().system())), false); tester.triggerUntilQuiescence(); - tester.deployAndNotify(instance, applicationPackage, true, JobType.productionUsWest1); - tester.deployAndNotify(instance, applicationPackage, true, JobType.productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.productionUsWest1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.productionUsEast3); } @Test @@ -385,21 +393,22 @@ public class DeploymentTriggerTest { .parallel("us-east-3", "us-west-1") .build(); - Instance app = tester.createApplication("app1", "tenant1", 1, 11L); + Application app = tester.createApplication("app1", "tenant1", 1, 11L); + Instance instance = tester.instance(app.id()); tester.jobCompletion(component).application(app).uploadArtifact(applicationPackage).submit(); // Test environments pass - tester.deployAndNotify(app, applicationPackage, true, JobType.systemTest); - tester.deployAndNotify(app, applicationPackage, true, JobType.stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.stagingTest); // Last declared job completes first - tester.deploy(JobType.productionUsWest1, app, applicationPackage); + tester.deploy(JobType.productionUsWest1, instance.id(), applicationPackage); tester.jobCompletion(JobType.productionUsWest1).application(app).submit(); assertTrue("Change is present as not all jobs are complete", tester.applications().require(app.id()).change().hasTargets()); // All jobs complete - tester.deploy(JobType.productionUsEast3, app, applicationPackage); + tester.deploy(JobType.productionUsEast3, instance.id(), applicationPackage); tester.jobCompletion(JobType.productionUsEast3).application(app).submit(); assertFalse("Change has been deployed", tester.applications().require(app.id()).change().hasTargets()); @@ -409,7 +418,8 @@ public class DeploymentTriggerTest { public void testSuccessfulDeploymentApplicationPackageChanged() { TenantName tenant = tester.controllerTester().createTenant("tenant1", "domain1", 1L); MockBuildService mockBuildService = tester.buildService(); - Instance instance = tester.controllerTester().createApplication(tenant, "app1", "default", 1L); + Application application = tester.controllerTester().createApplication(tenant, "app1", "default", 1L); + Instance instance = tester.instance(application.id()); ApplicationPackage previousApplicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .region("us-east-3") @@ -425,16 +435,16 @@ public class DeploymentTriggerTest { .build(); // Component job finishes - tester.jobCompletion(component).application(instance).uploadArtifact(newApplicationPackage).submit(); + tester.jobCompletion(component).application(application).uploadArtifact(newApplicationPackage).submit(); // Application is deployed to all test environments and declared zones - tester.deployAndNotify(instance, newApplicationPackage, true, JobType.systemTest); - tester.deploy(JobType.stagingTest, instance, previousApplicationPackage, true); - tester.deployAndNotify(instance, newApplicationPackage, true, JobType.stagingTest); - tester.deployAndNotify(instance, newApplicationPackage, true, JobType.productionUsEast3); - tester.deployAndNotify(instance, newApplicationPackage, true, JobType.productionUsCentral1); - tester.deployAndNotify(instance, newApplicationPackage, true, JobType.productionUsWest1); - tester.deployAndNotify(instance, newApplicationPackage, true, JobType.productionEuWest1); + tester.deployAndNotify(instance.id(), Optional.of(newApplicationPackage), true, JobType.systemTest); + tester.deploy(JobType.stagingTest, instance.id(), previousApplicationPackage, true); + tester.deployAndNotify(instance.id(), Optional.of(newApplicationPackage), true, JobType.stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(newApplicationPackage), true, JobType.productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.of(newApplicationPackage), true, JobType.productionUsCentral1); + tester.deployAndNotify(instance.id(), Optional.of(newApplicationPackage), true, JobType.productionUsWest1); + tester.deployAndNotify(instance.id(), Optional.of(newApplicationPackage), true, JobType.productionEuWest1); assertTrue("All jobs consumed", mockBuildService.jobs().isEmpty()); } @@ -457,7 +467,8 @@ public class DeploymentTriggerTest { .region("us-central-1") .region("us-east-3"); - Instance app = tester.createAndDeploy("app1", 1, applicationPackageBuilder.build()); + Application app = tester.createAndDeploy("app1", 1, applicationPackageBuilder.build()); + Instance instance = tester.instance(app.id()); tester.clock().advance(Duration.ofHours(1)); // --------------- Enter block window: 18:30 @@ -479,8 +490,8 @@ public class DeploymentTriggerTest { .uploadArtifact(changedApplication) .submit(); assertTrue(tester.applications().require(app.id()).outstandingChange().hasTargets()); - tester.deployAndNotify(app, changedApplication, true, systemTest); - tester.deployAndNotify(app, changedApplication, true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(changedApplication), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.of(changedApplication), true, stagingTest); tester.outstandingChangeDeployer().run(); assertTrue(tester.applications().require(app.id()).outstandingChange().hasTargets()); @@ -494,7 +505,7 @@ public class DeploymentTriggerTest { assertFalse(tester.applications().require(app.id()).outstandingChange().hasTargets()); tester.deploymentTrigger().triggerReadyJobs(); // Schedules staging test for the blocked production job(s) - assertEquals(singletonList(buildJob(app, productionUsWest1)), tester.buildService().jobs()); + assertEquals(singletonList(buildJob(app.id(), productionUsWest1)), tester.buildService().jobs()); } @Test @@ -506,7 +517,8 @@ public class DeploymentTriggerTest { .region("us-west-1") .region("us-east-3") .build(); - Instance instance = tester.createAndDeploy("app1", 1, applicationPackage); + Application application = tester.createAndDeploy("app1", 1, applicationPackage); + Instance instance = tester.instance(application.id()); // Application on (6.1, 1.0.42) Version v1 = Version.fromString("6.1"); @@ -514,56 +526,57 @@ public class DeploymentTriggerTest { // Application is mid-upgrade when block window begins, and has an outstanding change. Version v2 = Version.fromString("6.2"); tester.upgradeSystem(v2); - tester.jobCompletion(component).application(instance).nextBuildNumber().uploadArtifact(applicationPackage).submit(); + tester.jobCompletion(component).application(application).nextBuildNumber().uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(instance, applicationPackage, true, stagingTest); - tester.deployAndNotify(instance, applicationPackage, true, systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, systemTest); // Entering block window will keep the outstanding change in place. tester.clock().advance(Duration.ofHours(1)); tester.outstandingChangeDeployer().run(); - tester.deployAndNotify(instance, applicationPackage, true, productionUsWest1); - assertEquals(BuildJob.defaultBuildNumber, tester.application(instance.id()).deploymentJobs().jobStatus() + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsWest1); + assertEquals(BuildJob.defaultBuildNumber, tester.instance(application.id()).deploymentJobs().jobStatus() .get(productionUsWest1).lastSuccess().get().application().buildNumber().getAsLong()); - assertEquals((BuildJob.defaultBuildNumber + 1), tester.application(instance.id()).outstandingChange().application().get().buildNumber().getAsLong()); + assertEquals((BuildJob.defaultBuildNumber + 1), tester.instance(application.id()).outstandingChange().application().get().buildNumber().getAsLong()); tester.readyJobTrigger().maintain(); // Platform upgrade keeps rolling, since it has already deployed in a production zone, and tests for the new revision have also started. assertEquals(3, tester.buildService().jobs().size()); - tester.deployAndNotify(instance, applicationPackage, true, productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsEast3); assertEquals(2, tester.buildService().jobs().size()); // Upgrade is done, and oustanding change rolls out when block window ends. - assertEquals(Change.empty(), tester.application(instance.id()).change()); - assertFalse(tester.application(instance.id()).change().hasTargets()); - assertTrue(tester.application(instance.id()).outstandingChange().hasTargets()); + assertEquals(Change.empty(), tester.instance(application.id()).change()); + assertFalse(tester.instance(application.id()).change().hasTargets()); + assertTrue(tester.instance(application.id()).outstandingChange().hasTargets()); - tester.deployAndNotify(instance, applicationPackage, true, stagingTest); - tester.deployAndNotify(instance, applicationPackage, true, systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, systemTest); tester.clock().advance(Duration.ofHours(1)); tester.outstandingChangeDeployer().run(); - assertTrue(tester.application(instance.id()).change().hasTargets()); - assertFalse(tester.application(instance.id()).outstandingChange().hasTargets()); + assertTrue(tester.instance(application.id()).change().hasTargets()); + assertFalse(tester.instance(application.id()).outstandingChange().hasTargets()); tester.readyJobTrigger().run(); - tester.deployAndNotify(instance, applicationPackage, true, productionUsWest1); - tester.deployAndNotify(instance, applicationPackage, true, productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsWest1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsEast3); - assertFalse(tester.application(instance.id()).change().hasTargets()); - assertFalse(tester.application(instance.id()).outstandingChange().hasTargets()); + assertFalse(tester.instance(application.id()).change().hasTargets()); + assertFalse(tester.instance(application.id()).outstandingChange().hasTargets()); } @Test public void testJobPause() { - Instance app = tester.createAndDeploy("app", 3, "default"); + Application app = tester.createAndDeploy("app", 3, "default"); + Instance instance = tester.instance(app.id()); tester.upgradeSystem(new Version("9.8.7")); tester.applications().deploymentTrigger().pauseJob(app.id(), productionUsWest1, tester.clock().instant().plus(Duration.ofSeconds(1))); tester.applications().deploymentTrigger().pauseJob(app.id(), productionUsEast3, tester.clock().instant().plus(Duration.ofSeconds(3))); // us-west-1 does not trigger when paused. - tester.deployAndNotify(app, true, systemTest); - tester.deployAndNotify(app, true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, stagingTest); tester.assertNotRunning(productionUsWest1, app.id()); // us-west-1 triggers when no longer paused, but does not retry when paused again. @@ -571,17 +584,17 @@ public class DeploymentTriggerTest { tester.readyJobTrigger().run(); tester.assertRunning(productionUsWest1, app.id()); tester.applications().deploymentTrigger().pauseJob(app.id(), productionUsWest1, tester.clock().instant().plus(Duration.ofSeconds(1))); - tester.deployAndNotify(app, false, productionUsWest1); + tester.deployAndNotify(instance.id(), Optional.empty(), false, productionUsWest1); tester.assertNotRunning(productionUsWest1, app.id()); tester.clock().advance(Duration.ofMillis(1000)); tester.readyJobTrigger().run(); - tester.deployAndNotify(app, true, productionUsWest1); + tester.deployAndNotify(instance.id(), Optional.empty(), true, productionUsWest1); // us-east-3 does not automatically trigger when paused, but does when forced. tester.assertNotRunning(productionUsEast3, app.id()); tester.deploymentTrigger().forceTrigger(app.id(), productionUsEast3, "mrTrigger"); tester.assertRunning(productionUsEast3, app.id()); - assertFalse(tester.application(app.id()).deploymentJobs().jobStatus().get(productionUsEast3).pausedUntil().isPresent()); + assertFalse(tester.instance(app.id()).deploymentJobs().jobStatus().get(productionUsEast3).pausedUntil().isPresent()); } @Test @@ -589,7 +602,7 @@ public class DeploymentTriggerTest { ReadyJobsTrigger readyJobsTrigger = new ReadyJobsTrigger(tester.controller(), Duration.ofHours(1), new JobControl(tester.controllerTester().curator())); - Instance app = tester.createAndDeploy("default0", 3, "default"); + Application app = tester.createAndDeploy("default0", 3, "default"); // Store that we are upgrading but don't start the system-tests job tester.controller().applications().lockOrThrow(app.id(), locked -> { tester.controller().applications().store(locked.withChange(Change.of(Version.fromString("6.2")))); @@ -602,58 +615,61 @@ public class DeploymentTriggerTest { @Test public void applicationVersionIsNotDowngraded() { - Instance instance = tester.createApplication("app1", "tenant1", 1, 1L); - Supplier<Instance> app = () -> tester.application(instance.id()); + Application application = tester.createApplication("app1", "tenant1", 1, 1L); + Instance instance = tester.instance(application.id()); + Supplier<Instance> app = () -> tester.instance(application.id()); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .region("us-central-1") .region("eu-west-1") .build(); - tester.deployCompletely(instance, applicationPackage); + tester.deployCompletely(application, applicationPackage); // productionUsCentral1 fails after deployment, causing a mismatch between deployed and successful state. - tester.completeDeploymentWithError(instance, applicationPackage, BuildJob.defaultBuildNumber + 1, productionUsCentral1); + tester.completeDeploymentWithError(application, applicationPackage, BuildJob.defaultBuildNumber + 1, productionUsCentral1); // deployAndNotify doesn't actually deploy if the job fails, so we need to do that manually. - tester.deployAndNotify(instance, false, productionUsCentral1); - tester.deploy(productionUsCentral1, instance, Optional.empty(), false); + tester.deployAndNotify(instance.id(), Optional.empty(), false, productionUsCentral1); + tester.deploy(productionUsCentral1, instance.id(), Optional.empty(), false); ApplicationVersion appVersion1 = ApplicationVersion.from(BuildJob.defaultSourceRevision, BuildJob.defaultBuildNumber + 1); assertEquals(appVersion1, app.get().deployments().get(ZoneId.from("prod.us-central-1")).applicationVersion()); // Verify the application change is not removed when change is cancelled. - tester.deploymentTrigger().cancelChange(instance.id(), PLATFORM); + tester.deploymentTrigger().cancelChange(application.id(), PLATFORM); assertEquals(Change.of(appVersion1), app.get().change()); // Now cancel the change as is done through the web API. - tester.deploymentTrigger().cancelChange(instance.id(), ALL); + tester.deploymentTrigger().cancelChange(application.id(), ALL); assertEquals(Change.empty(), app.get().change()); // A new version is released, which should now deploy the currently deployed application version to avoid downgrades. Version version1 = new Version("6.2"); tester.upgradeSystem(version1); - tester.jobCompletion(productionUsCentral1).application(instance).unsuccessful().submit(); - tester.deployAndNotify(instance, true, systemTest); - tester.deployAndNotify(instance, true, stagingTest); - tester.deployAndNotify(instance, false, productionUsCentral1); + tester.jobCompletion(productionUsCentral1).application(application).unsuccessful().submit(); + tester.deployAndNotify(instance.id(), Optional.empty(), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.empty(), false, productionUsCentral1); // The last job has a different target, and the tests need to run again. // These may now start, since the first job has been triggered once, and thus is verified already. - tester.deployAndNotify(instance, true, systemTest); - tester.deployAndNotify(instance, true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, stagingTest); // Finally, the two production jobs complete, in order. - tester.deployAndNotify(instance, true, productionUsCentral1); - tester.deployAndNotify(instance, true, productionEuWest1); + tester.deployAndNotify(instance.id(), Optional.empty(), true, productionUsCentral1); + tester.deployAndNotify(instance.id(), Optional.empty(), true, productionEuWest1); assertEquals(appVersion1, app.get().deployments().get(ZoneId.from("prod.us-central-1")).applicationVersion()); } @Test public void stepIsCompletePreciselyWhenItShouldBe() { - Instance instance1 = tester.createApplication("app1", "tenant1", 1, 1L); - Instance instance2 = tester.createApplication("app2", "tenant2", 2, 2L); - Supplier<Instance> app1 = () -> tester.application(instance1.id()); + Application application1 = tester.createApplication("app1", "tenant1", 1, 1L); + Application application2 = tester.createApplication("app2", "tenant2", 2, 2L); + Instance instance1 = tester.instance(application1.id()); + Instance instance2 = tester.instance(application2.id()); + Supplier<Instance> app1 = () -> tester.instance(application1.id()); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .region("us-central-1") @@ -663,23 +679,23 @@ public class DeploymentTriggerTest { // System upgrades to version0 and applications deploy on that version Version version0 = Version.fromString("7.0"); tester.upgradeSystem(version0); - tester.deployCompletely(instance1, applicationPackage); - tester.deployCompletely(instance2, applicationPackage); + tester.deployCompletely(application1, applicationPackage); + tester.deployCompletely(application2, applicationPackage); // version1 is released and application1 skips upgrading to that version Version version1 = Version.fromString("7.1"); tester.upgradeSystem(version1); // Deploy application2 to keep this version present in the system - tester.deployCompletely(instance2, applicationPackage); - tester.applications().deploymentTrigger().cancelChange(instance1.id(), ALL); + tester.deployCompletely(application2, applicationPackage); + tester.applications().deploymentTrigger().cancelChange(application1.id(), ALL); tester.buildService().clear(); // Clear stale build jobs for cancelled change // version2 is released and application1 starts upgrading Version version2 = Version.fromString("7.2"); tester.upgradeSystem(version2); - tester.completeUpgradeWithError(instance1, version2, applicationPackage, productionUsCentral1); - tester.deploy(productionUsCentral1, instance1, applicationPackage); - tester.deployAndNotify(instance1, applicationPackage, false, productionUsCentral1); + tester.completeUpgradeWithError(application1, version2, applicationPackage, productionUsCentral1); + tester.deploy(productionUsCentral1, instance1.id(), applicationPackage); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), false, productionUsCentral1); assertEquals(version2, app1.get().deployments().get(productionUsCentral1.zone(main)).version()); // version2 becomes broken and upgrade targets latest non-broken @@ -687,34 +703,34 @@ public class DeploymentTriggerTest { tester.computeVersionStatus(); tester.upgrader().maintain(); // Cancel upgrades to broken version assertEquals("Change becomes latest non-broken version", Change.of(version1), app1.get().change()); - tester.deployAndNotify(instance1, applicationPackage, false, productionUsCentral1); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), false, productionUsCentral1); Instant triggered = app1.get().deploymentJobs().jobStatus().get(productionUsCentral1).lastTriggered().get().at(); tester.clock().advance(Duration.ofHours(1)); // version1 proceeds 'til the last job, where it fails; us-central-1 is skipped, as current change is strictly dominated by what's deployed there. - tester.deployAndNotify(instance1, applicationPackage, true, systemTest); - tester.deployAndNotify(instance1, applicationPackage, true, stagingTest); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, systemTest); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, stagingTest); assertEquals(triggered, app1.get().deploymentJobs().jobStatus().get(productionUsCentral1).lastTriggered().get().at()); - tester.deployAndNotify(instance1, applicationPackage, false, productionEuWest1); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), false, productionEuWest1); //Eagerly triggered system and staging tests complete. - tester.deployAndNotify(instance1, applicationPackage, true, systemTest); - tester.deployAndNotify(instance1, applicationPackage, true, stagingTest); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, systemTest); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, stagingTest); // Roll out a new application version, which gives a dual change -- this should trigger us-central-1, but only as long as it hasn't yet deployed there. - tester.jobCompletion(component).application(instance1).nextBuildNumber().uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(instance1, applicationPackage, false, productionEuWest1); - tester.deployAndNotify(instance1, applicationPackage, true, systemTest); - tester.deployAndNotify(instance1, applicationPackage, true, stagingTest); + tester.jobCompletion(component).application(application1).nextBuildNumber().uploadArtifact(applicationPackage).submit(); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), false, productionEuWest1); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, systemTest); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, stagingTest); - tester.assertRunning(productionUsCentral1, instance1.id()); + tester.assertRunning(productionUsCentral1, application1.id()); assertEquals(version2, app1.get().deployments().get(productionUsCentral1.zone(main)).version()); assertEquals(42, app1.get().deployments().get(productionUsCentral1.zone(main)).applicationVersion().buildNumber().getAsLong()); assertNotEquals(triggered, app1.get().deploymentJobs().jobStatus().get(productionUsCentral1).lastTriggered().get().at()); // Change has a higher application version than what is deployed -- deployment should trigger. - tester.deployAndNotify(instance1, applicationPackage, false, productionUsCentral1); - tester.deploy(productionUsCentral1, instance1, applicationPackage); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), false, productionUsCentral1); + tester.deploy(productionUsCentral1, instance1.id(), applicationPackage); assertEquals(version2, app1.get().deployments().get(productionUsCentral1.zone(main)).version()); assertEquals(43, app1.get().deployments().get(productionUsCentral1.zone(main)).applicationVersion().buildNumber().getAsLong()); @@ -722,67 +738,68 @@ public class DeploymentTriggerTest { tester.clock().advance(Duration.ofHours(2).plus(Duration.ofSeconds(1))); // Enough time for retry tester.readyJobTrigger().maintain(); // Failing job is not retried as change has been deployed - tester.assertNotRunning(productionUsCentral1, instance1.id()); + tester.assertNotRunning(productionUsCentral1, application1.id()); // Last job has a different deployment target, so tests need to run again. - tester.deployAndNotify(instance1, true, systemTest); - tester.deployAndNotify(instance1, true, stagingTest); - tester.deployAndNotify(instance1, applicationPackage, true, productionEuWest1); + tester.deployAndNotify(instance1.id(), Optional.empty(), true, systemTest); + tester.deployAndNotify(instance1.id(), Optional.empty(), true, stagingTest); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, productionEuWest1); assertFalse(app1.get().change().hasTargets()); assertFalse(app1.get().deploymentJobs().jobStatus().get(productionUsCentral1).isSuccess()); } @Test public void eachDeployTargetIsTested() { - Instance instance = tester.createApplication("app1", "tenant1", 1, 1L); - Supplier<Instance> app = () -> tester.application(instance.id()); + Application application = tester.createApplication("app1", "tenant1", 1, 1L); + Instance instance = tester.instance(application.id()); + Supplier<Instance> app = () -> tester.instance(application.id()); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .parallel("eu-west-1", "us-east-3") .build(); // Application version 42 and platform version 6.1. - tester.deployCompletely(instance, applicationPackage); + tester.deployCompletely(application, applicationPackage); // Success in first prod zone, change cancelled between triggering and deployment to two parallel zones. // One of the parallel zones get a deployment, but both fail their jobs. Version v1 = new Version("6.1"); Version v2 = new Version("6.2"); tester.upgradeSystem(v2); - tester.deployAndNotify(instance, true, systemTest); - tester.deployAndNotify(instance, true, stagingTest); - tester.deploymentTrigger().cancelChange(instance.id(), PLATFORM); - tester.deploy(productionEuWest1, instance, applicationPackage); + tester.deployAndNotify(instance.id(), Optional.empty(), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, stagingTest); + tester.deploymentTrigger().cancelChange(application.id(), PLATFORM); + tester.deploy(productionEuWest1, instance.id(), applicationPackage); assertEquals(v2, app.get().deployments().get(productionEuWest1.zone(main)).version()); assertEquals(v1, app.get().deployments().get(productionUsEast3.zone(main)).version()); // New application version should run system and staging tests against both 6.1 and 6.2, in no particular order. - tester.jobCompletion(component).application(instance).nextBuildNumber().uploadArtifact(applicationPackage).submit(); + tester.jobCompletion(component).application(application).nextBuildNumber().uploadArtifact(applicationPackage).submit(); Version firstTested = app.get().deploymentJobs().jobStatus().get(systemTest).lastTriggered().get().platform(); assertEquals(firstTested, app.get().deploymentJobs().jobStatus().get(stagingTest).lastTriggered().get().platform()); - tester.deployAndNotify(instance, true, systemTest); - tester.deployAndNotify(instance, true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, stagingTest); // Tests are not re-triggered, because the deployments that were tested have not yet been triggered on the tested versions. assertEquals(firstTested, app.get().deploymentJobs().jobStatus().get(systemTest).lastTriggered().get().platform()); assertEquals(firstTested, app.get().deploymentJobs().jobStatus().get(stagingTest).lastTriggered().get().platform()); // Finish old runs of the production jobs, which fail. - tester.deployAndNotify(instance, applicationPackage, false, productionEuWest1); - tester.deployAndNotify(instance, applicationPackage, false, productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), false, productionEuWest1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), false, productionUsEast3); tester.triggerUntilQuiescence(); // New upgrade is already tested for one of the jobs, which has now been triggered, and tests may run for the other job. assertNotEquals(firstTested, app.get().deploymentJobs().jobStatus().get(systemTest).lastTriggered().get().platform()); assertNotEquals(firstTested, app.get().deploymentJobs().jobStatus().get(stagingTest).lastTriggered().get().platform()); - tester.deployAndNotify(instance, true, systemTest); - tester.deployAndNotify(instance, true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, stagingTest); // Both jobs fail again, and must be re-triggered -- this is ok, as they are both already triggered on their current targets. - tester.deployAndNotify(instance, false, productionEuWest1); - tester.deployAndNotify(instance, false, productionUsEast3); - tester.deployAndNotify(instance, true, productionUsEast3); - tester.deployAndNotify(instance, true, productionEuWest1); + tester.deployAndNotify(instance.id(), Optional.empty(), false, productionEuWest1); + tester.deployAndNotify(instance.id(), Optional.empty(), false, productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.empty(), true, productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.empty(), true, productionEuWest1); assertFalse(app.get().change().hasTargets()); assertEquals(43, app.get().deploymentJobs().jobStatus().get(productionEuWest1).lastSuccess().get().application().buildNumber().getAsLong()); assertEquals(43, app.get().deploymentJobs().jobStatus().get(productionUsEast3).lastSuccess().get().application().buildNumber().getAsLong()); @@ -790,98 +807,100 @@ public class DeploymentTriggerTest { @Test public void eachDifferentUpgradeCombinationIsTested() { - Instance instance = tester.createApplication("app1", "tenant1", 1, 1L); - Supplier<Instance> app = () -> tester.application(instance.id()); + Application application = tester.createApplication("app1", "tenant1", 1, 1L); + Instance instance = tester.instance(application.id()); + Supplier<Instance> app = () -> tester.instance(application.id()); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .region("us-central-1") .parallel("eu-west-1", "us-east-3") .build(); // Application version 42 and platform version 6.1. - tester.deployCompletely(instance, applicationPackage); + tester.deployCompletely(application, applicationPackage); // Application partially upgrades, then a new version is released. Version v1 = new Version("6.1"); Version v2 = new Version("6.2"); tester.upgradeSystem(v2); - tester.deployAndNotify(instance, true, systemTest); - tester.deployAndNotify(instance, true, stagingTest); - tester.deployAndNotify(instance, true, productionUsCentral1); - tester.deployAndNotify(instance, true, productionEuWest1); - tester.deployAndNotify(instance, false, productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.empty(), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, productionUsCentral1); + tester.deployAndNotify(instance.id(), Optional.empty(), true, productionEuWest1); + tester.deployAndNotify(instance.id(), Optional.empty(), false, productionUsEast3); assertEquals(v2, app.get().deployments().get(ZoneId.from("prod", "us-central-1")).version()); assertEquals(v2, app.get().deployments().get(ZoneId.from("prod", "eu-west-1")).version()); assertEquals(v1, app.get().deployments().get(ZoneId.from("prod", "us-east-3")).version()); Version v3 = new Version("6.3"); tester.upgradeSystem(v3); - tester.deployAndNotify(instance, false, productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.empty(), false, productionUsEast3); // See that sources for staging are: first v2, then v1. - tester.deployAndNotify(instance, true, systemTest); - tester.deployAndNotify(instance, true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, stagingTest); assertEquals(v2, app.get().deploymentJobs().jobStatus().get(stagingTest).lastSuccess().get().sourcePlatform().get()); - tester.deployAndNotify(instance, true, productionUsCentral1); + tester.deployAndNotify(instance.id(), Optional.empty(), true, productionUsCentral1); assertEquals(v1, app.get().deploymentJobs().jobStatus().get(stagingTest).lastTriggered().get().sourcePlatform().get()); - tester.deployAndNotify(instance, true, stagingTest); - tester.deployAndNotify(instance, true, productionEuWest1); - tester.deployAndNotify(instance, true, productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.empty(), true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, productionEuWest1); + tester.deployAndNotify(instance.id(), Optional.empty(), true, productionUsEast3); } @Test public void retriesFailingJobs() { - Instance instance = tester.createApplication("app1", "tenant1", 1, 1L); + Application application = tester.createApplication("app1", "tenant1", 1, 1L); + Instance instance = tester.instance(application.id()); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .region("us-central-1") .build(); // Deploy completely on default application and platform versions - tester.deployCompletely(instance, applicationPackage); + tester.deployCompletely(application, applicationPackage); // New application change is deployed and fails in system-test for a while - tester.jobCompletion(component).application(instance).nextBuildNumber().uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(instance, false, systemTest); - tester.deployAndNotify(instance, true, stagingTest); + tester.jobCompletion(component).application(application).nextBuildNumber().uploadArtifact(applicationPackage).submit(); + tester.deployAndNotify(instance.id(), Optional.empty(), false, systemTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, stagingTest); // Retries immediately in the first minute after failing tester.clock().advance(Duration.ofSeconds(59)); - tester.jobCompletion(systemTest).application(instance).unsuccessful().submit(); + tester.jobCompletion(systemTest).application(application).unsuccessful().submit(); tester.readyJobTrigger().maintain(); - tester.assertRunning(systemTest, instance.id()); + tester.assertRunning(systemTest, application.id()); // Stops immediate retry after failing for 1 minute tester.clock().advance(Duration.ofSeconds(1)); - tester.jobCompletion(systemTest).application(instance).unsuccessful().submit(); + tester.jobCompletion(systemTest).application(application).unsuccessful().submit(); tester.readyJobTrigger().maintain(); - tester.assertNotRunning(systemTest, instance.id()); + tester.assertNotRunning(systemTest, application.id()); // Retries after 10 minutes since previous completion as we failed within the last hour tester.clock().advance(Duration.ofMinutes(10).plus(Duration.ofSeconds(1))); tester.readyJobTrigger().maintain(); - tester.assertRunning(systemTest, instance.id()); + tester.assertRunning(systemTest, application.id()); // Retries less frequently after 1 hour of failure tester.clock().advance(Duration.ofMinutes(50)); - tester.jobCompletion(systemTest).application(instance).unsuccessful().submit(); + tester.jobCompletion(systemTest).application(application).unsuccessful().submit(); tester.readyJobTrigger().maintain(); - tester.assertNotRunning(systemTest, instance.id()); + tester.assertNotRunning(systemTest, application.id()); // Retries after two hours pass since last completion tester.clock().advance(Duration.ofHours(2).plus(Duration.ofSeconds(1))); tester.readyJobTrigger().maintain(); - tester.assertRunning(systemTest, instance.id()); + tester.assertRunning(systemTest, application.id()); // Still fails and is not retried - tester.jobCompletion(systemTest).application(instance).unsuccessful().submit(); + tester.jobCompletion(systemTest).application(application).unsuccessful().submit(); tester.readyJobTrigger().maintain(); - tester.assertNotRunning(systemTest, instance.id()); + tester.assertNotRunning(systemTest, application.id()); // Another application change is deployed and fixes system-test. Change is triggered immediately as target changes - tester.jobCompletion(component).application(instance).nextBuildNumber(2).uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(instance, true, systemTest); - tester.deployAndNotify(instance, true, stagingTest); - tester.deployAndNotify(instance, true, productionUsCentral1); + tester.jobCompletion(component).application(application).nextBuildNumber(2).uploadArtifact(applicationPackage).submit(); + tester.deployAndNotify(instance.id(), Optional.empty(), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, productionUsCentral1); assertTrue("Deployment completed", tester.buildService().jobs().isEmpty()); } @@ -895,11 +914,12 @@ public class DeploymentTriggerTest { Version version = Version.fromString("6.2"); tester.upgradeSystem(version); - Instance app = tester.createApplication("app1", "tenant1", 1, 11L); + Application app = tester.createApplication("app1", "tenant1", 1, 11L); + Instance instance = tester.instance(app.id()); tester.jobCompletion(component).application(app).uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(app, applicationPackage, true, JobType.systemTest); - tester.deployAndNotify(app, applicationPackage, true, JobType.stagingTest); - tester.deployAndNotify(app, applicationPackage, true, JobType.productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.productionUsEast3); // New version is released version = Version.fromString("6.3"); @@ -909,14 +929,14 @@ public class DeploymentTriggerTest { tester.readyJobTrigger().maintain(); // Test environments pass - tester.deployAndNotify(app, applicationPackage, true, JobType.systemTest); - tester.deployAndNotify(app, applicationPackage, true, JobType.stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.stagingTest); // Production job fails and is retried tester.clock().advance(Duration.ofSeconds(1)); // Advance time so that we can detect jobs in progress - tester.deployAndNotify(app, applicationPackage, false, JobType.productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), false, JobType.productionUsEast3); assertEquals("Production job is retried", 1, tester.buildService().jobs().size()); - assertEquals("Application has pending upgrade to " + version, version, tester.application(app.id()).change().platform().get()); + assertEquals("Application has pending upgrade to " + version, version, tester.instance(app.id()).change().platform().get()); // Another version is released, which cancels any pending upgrades to lower versions version = Version.fromString("6.4"); @@ -924,24 +944,24 @@ public class DeploymentTriggerTest { tester.upgrader().maintain(); tester.jobCompletion(JobType.productionUsEast3).application(app).unsuccessful().submit(); assertEquals("Application starts upgrading to new version", 2, tester.buildService().jobs().size()); - assertEquals("Application has pending upgrade to " + version, version, tester.application(app.id()).change().platform().get()); + assertEquals("Application has pending upgrade to " + version, version, tester.instance(app.id()).change().platform().get()); // Failure re-deployer did not retry failing job for prod.us-east-3, since it no longer had an available change assertFalse("Job is not retried", tester.buildService().jobs().stream() .anyMatch(j -> j.jobName().equals(JobType.productionUsEast3.jobName()))); // Test environments pass - tester.deployAndNotify(app, applicationPackage, true, JobType.systemTest); - tester.deployAndNotify(app, applicationPackage, true, JobType.stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.stagingTest); // Production job fails again, and is retried - tester.deployAndNotify(app, applicationPackage, false, JobType.productionUsEast3); - assertEquals("Job is retried", Collections.singletonList(ControllerTester.buildJob(app, productionUsEast3)), tester.buildService().jobs()); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), false, JobType.productionUsEast3); + assertEquals("Job is retried", Collections.singletonList(buildJob(app.id(), productionUsEast3)), tester.buildService().jobs()); // Production job finally succeeds - tester.deployAndNotify(app, applicationPackage, true, JobType.productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.productionUsEast3); assertTrue("All jobs consumed", tester.buildService().jobs().isEmpty()); - assertFalse("No failures", tester.application(app.id()).deploymentJobs().hasFailures()); + assertFalse("No failures", tester.instance(app.id()).deploymentJobs().hasFailures()); } @Test @@ -954,11 +974,12 @@ public class DeploymentTriggerTest { Version version = Version.fromString("6.2"); tester.upgradeSystem(version); - Instance app = tester.createApplication("app1", "tenant1", 1, 11L); + Application app = tester.createApplication("app1", "tenant1", 1, 11L); + Instance instance = tester.instance(app.id()); tester.jobCompletion(component).application(app).uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(app, applicationPackage, true, JobType.systemTest); - tester.deployAndNotify(app, applicationPackage, true, JobType.stagingTest); - tester.deployAndNotify(app, applicationPackage, true, JobType.productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.productionUsEast3); // New version is released version = Version.fromString("6.3"); @@ -966,29 +987,30 @@ public class DeploymentTriggerTest { assertEquals(version, tester.controller().versionStatus().systemVersion().get().versionNumber()); tester.upgrader().maintain(); tester.readyJobTrigger().maintain(); - assertEquals("Application has pending upgrade to " + version, version, tester.application(app.id()).change().platform().get()); + assertEquals("Application has pending upgrade to " + version, version, tester.instance(app.id()).change().platform().get()); // system-test fails and is left with a retry - tester.deployAndNotify(app, applicationPackage, false, JobType.systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), false, JobType.systemTest); // Another version is released version = Version.fromString("6.4"); tester.upgradeSystem(version); assertEquals(version, tester.controller().versionStatus().systemVersion().get().versionNumber()); - tester.buildService().remove(ControllerTester.buildJob(app, systemTest)); + tester.buildService().remove(buildJob(app.id(), systemTest)); tester.upgrader().maintain(); tester.readyJobTrigger().maintain(); - assertEquals("Application has pending upgrade to " + version, version, tester.application(app.id()).change().platform().get()); + assertEquals("Application has pending upgrade to " + version, version, tester.instance(app.id()).change().platform().get()); // Cancellation of outdated version and triggering on a new version is done by the upgrader. - assertEquals(version, tester.application(app.id()).deploymentJobs().jobStatus().get(systemTest).lastTriggered().get().platform()); + assertEquals(version, tester.instance(app.id()).deploymentJobs().jobStatus().get(systemTest).lastTriggered().get().platform()); } @Test public void testUpdatesFailingJobStatus() { // Setup application - Instance app = tester.createApplication("app1", "foo", 1, 1L); + Application app = tester.createApplication("app1", "foo", 1, 1L); + Instance instance = tester.instance(app.id()); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .region("us-west-1") @@ -997,39 +1019,39 @@ public class DeploymentTriggerTest { // Initial failure Instant initialFailure = tester.clock().instant().truncatedTo(MILLIS); tester.jobCompletion(component).application(app).uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(app, applicationPackage, false, systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), false, systemTest); assertEquals("Failure age is right at initial failure", - initialFailure, tester.firstFailing(app, systemTest).get().at()); + initialFailure, tester.firstFailing(instance, systemTest).get().at()); // Failure again -- failingSince should remain the same tester.clock().advance(Duration.ofMillis(1000)); - tester.deployAndNotify(app, applicationPackage, false, systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), false, systemTest); assertEquals("Failure age is right at second consecutive failure", - initialFailure, tester.firstFailing(app, systemTest).get().at()); + initialFailure, tester.firstFailing(instance, systemTest).get().at()); // Success resets failingSince tester.clock().advance(Duration.ofMillis(1000)); - tester.deployAndNotify(app, applicationPackage, true, systemTest); - assertFalse(tester.firstFailing(app, systemTest).isPresent()); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, systemTest); + assertFalse(tester.firstFailing(instance, systemTest).isPresent()); // Complete deployment - tester.deployAndNotify(app, applicationPackage, true, stagingTest); - tester.deployAndNotify(app, applicationPackage, true, productionUsWest1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsWest1); // Two repeated failures again. // Initial failure tester.clock().advance(Duration.ofMillis(1000)); initialFailure = tester.clock().instant().truncatedTo(MILLIS); tester.jobCompletion(component).application(app).nextBuildNumber().uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(app, applicationPackage, false, systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), false, systemTest); assertEquals("Failure age is right at initial failure", - initialFailure, tester.firstFailing(app, systemTest).get().at()); + initialFailure, tester.firstFailing(instance, systemTest).get().at()); // Failure again -- failingSince should remain the same tester.clock().advance(Duration.ofMillis(1000)); - tester.deployAndNotify(app, applicationPackage, false, systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), false, systemTest); assertEquals("Failure age is right at second consecutive failure", - initialFailure, tester.firstFailing(app, systemTest).get().at()); + initialFailure, tester.firstFailing(instance, systemTest).get().at()); } @Test @@ -1058,22 +1080,24 @@ public class DeploymentTriggerTest { .build(); Version version1 = tester.controller().versionStatus().systemVersion().get().versionNumber(); - Instance app1 = tester.createApplication("application1", "tenant1", 1, 1L); + Application app1 = tester.createApplication("application1", "tenant1", 1, 1L); + Instance instance1 = tester.instance(app1.id()); // First deployment: An application change tester.jobCompletion(component).application(app1).uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(app1, applicationPackage, true, systemTest); - tester.deployAndNotify(app1, applicationPackage, true, stagingTest); - tester.deployAndNotify(app1, applicationPackage, true, productionUsWest1); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, systemTest); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, stagingTest); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, productionUsWest1); app1 = tester.application(app1.id()); assertEquals("First deployment gets system version", version1, app1.oldestDeployedPlatform().get()); assertEquals(version1, tester.configServer().lastPrepareVersion().get()); + instance1 = tester.instance(instance1.id()); // Unexpected deployment - tester.deploy(productionUsWest1, app1, applicationPackage); - // applications are immutable, so any change to one, including deployment changes, would give rise to a new instance. - assertEquals("Unexpected deployment is ignored", app1, tester.application(app1.id())); + tester.deploy(productionUsWest1, instance1.id(), applicationPackage); + // instances are immutable, so any change to one, including deployment changes, would give rise to a new instance. + assertEquals("Unexpected deployment is ignored", instance1, tester.instance(app1.id())); // Application change after a new system version, and a region added Version version2 = new Version(version1.getMajor(), version1.getMinor() + 1); @@ -1086,16 +1110,16 @@ public class DeploymentTriggerTest { .region("us-east-3") .build(); tester.jobCompletion(component).application(app1).nextBuildNumber().uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(app1, applicationPackage, true, systemTest); - tester.deployAndNotify(app1, applicationPackage, true, stagingTest); - tester.deployAndNotify(app1, applicationPackage, true, productionUsWest1); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, systemTest); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, stagingTest); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, productionUsWest1); app1 = tester.application(app1.id()); assertEquals("Application change preserves version", version1, app1.oldestDeployedPlatform().get()); assertEquals(version1, tester.configServer().lastPrepareVersion().get()); // A deployment to the new region gets the same version - tester.deployAndNotify(app1, applicationPackage, true, productionUsEast3); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, productionUsEast3); app1 = tester.application(app1.id()); assertEquals("Application change preserves version", version1, app1.oldestDeployedPlatform().get()); assertEquals(version1, tester.configServer().lastPrepareVersion().get()); @@ -1104,10 +1128,10 @@ public class DeploymentTriggerTest { // Version upgrade changes system version tester.deploymentTrigger().triggerChange(app1.id(), Change.of(version2)); tester.deploymentTrigger().triggerReadyJobs(); - tester.deployAndNotify(app1, applicationPackage, true, systemTest); - tester.deployAndNotify(app1, applicationPackage, true, stagingTest); - tester.deployAndNotify(app1, applicationPackage, true, productionUsWest1); - tester.deployAndNotify(app1, applicationPackage, true, productionUsEast3); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, systemTest); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, stagingTest); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, productionUsWest1); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, productionUsEast3); app1 = tester.application(app1.id()); assertEquals("Version upgrade changes version", version2, app1.oldestDeployedPlatform().get()); @@ -1124,22 +1148,25 @@ public class DeploymentTriggerTest { long project1 = 1; long project2 = 2; long project3 = 3; - Instance app1 = tester.createApplication("app1", "tenant1", project1, 1L); - Instance app2 = tester.createApplication("app2", "tenant2", project2, 1L); - Instance app3 = tester.createApplication("app3", "tenant3", project3, 1L); + Application app1 = tester.createApplication("app1", "tenant1", project1, 1L); + Application app2 = tester.createApplication("app2", "tenant2", project2, 1L); + Application app3 = tester.createApplication("app3", "tenant3", project3, 1L); + Instance instance1 = tester.instance(app1.id()); + Instance instance2 = tester.instance(app2.id()); + Instance instance3 = tester.instance(app3.id()); MockBuildService mockBuildService = tester.buildService(); // all applications: system-test completes successfully with some time in between, to determine trigger order. tester.jobCompletion(component).application(app2).uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(app2, applicationPackage, true, systemTest); + tester.deployAndNotify(instance2.id(), Optional.of(applicationPackage), true, systemTest); tester.clock().advance(Duration.ofMinutes(1)); tester.jobCompletion(component).application(app1).uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(app1, applicationPackage, true, systemTest); + tester.deployAndNotify(instance1.id(), Optional.of(applicationPackage), true, systemTest); tester.clock().advance(Duration.ofMinutes(1)); tester.jobCompletion(component).application(app3).uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(app3, applicationPackage, true, systemTest); + tester.deployAndNotify(instance3.id(), Optional.of(applicationPackage), true, systemTest); // all applications: staging test jobs queued assertEquals(3, mockBuildService.jobs().size()); @@ -1151,30 +1178,30 @@ public class DeploymentTriggerTest { assertJobsInOrder(jobs, tester.buildService().jobs()); tester.triggerUntilQuiescence(); - jobs.add(buildJob(app2, stagingTest)); - jobs.add(buildJob(app1, stagingTest)); - jobs.add(buildJob(app3, stagingTest)); + jobs.add(buildJob(app2.id(), stagingTest)); + jobs.add(buildJob(app1.id(), stagingTest)); + jobs.add(buildJob(app3.id(), stagingTest)); assertJobsInOrder(jobs, tester.buildService().jobs()); // Remove the jobs for app1 and app2, and then let app3 fail with outOfCapacity. // All three jobs are now eligible, but the one for app3 should trigger first as an outOfCapacity-retry. - tester.buildService().remove(buildJob(app1, stagingTest)); - tester.buildService().remove(buildJob(app2, stagingTest)); - jobs.remove(buildJob(app1, stagingTest)); - jobs.remove(buildJob(app2, stagingTest)); + tester.buildService().remove(buildJob(app1.id(), stagingTest)); + tester.buildService().remove(buildJob(app2.id(), stagingTest)); + jobs.remove(buildJob(app1.id(), stagingTest)); + jobs.remove(buildJob(app2.id(), stagingTest)); tester.jobCompletion(stagingTest).application(app3).error(DeploymentJobs.JobError.outOfCapacity).submit(); assertJobsInOrder(jobs, tester.buildService().jobs()); tester.triggerUntilQuiescence(); - jobs.add(buildJob(app2, stagingTest)); - jobs.add(buildJob(app1, stagingTest)); + jobs.add(buildJob(app2.id(), stagingTest)); + jobs.add(buildJob(app1.id(), stagingTest)); assertJobsInOrder(jobs, tester.buildService().jobs()); // Finish deployment for apps 2 and 3, then release a new version, leaving only app1 with an application upgrade. - tester.deployAndNotify(app2, applicationPackage, true, stagingTest); - tester.deployAndNotify(app2, applicationPackage, true, productionUsEast3); - tester.deployAndNotify(app3, applicationPackage, true, stagingTest); - tester.deployAndNotify(app3, applicationPackage, true, productionUsEast3); + tester.deployAndNotify(instance2.id(), Optional.of(applicationPackage), true, stagingTest); + tester.deployAndNotify(instance2.id(), Optional.of(applicationPackage), true, productionUsEast3); + tester.deployAndNotify(instance3.id(), Optional.of(applicationPackage), true, stagingTest); + tester.deployAndNotify(instance3.id(), Optional.of(applicationPackage), true, productionUsEast3); tester.upgradeSystem(new Version("6.2")); // app1 also gets a new application change, so its time of availability is after the version upgrade. @@ -1182,29 +1209,29 @@ public class DeploymentTriggerTest { tester.buildService().clear(); tester.jobCompletion(component).application(app1).nextBuildNumber().uploadArtifact(applicationPackage).submit(); jobs.clear(); - jobs.add(buildJob(app1, stagingTest)); - jobs.add(buildJob(app1, systemTest)); + jobs.add(buildJob(app1.id(), stagingTest)); + jobs.add(buildJob(app1.id(), systemTest)); // Tests for app1 trigger before the others since it carries an application upgrade. assertJobsInOrder(jobs, tester.buildService().jobs()); // Let the test jobs start, remove everything expect system test for app3, which fails with outOfCapacity again. tester.triggerUntilQuiescence(); - tester.buildService().remove(buildJob(app1, systemTest)); - tester.buildService().remove(buildJob(app2, systemTest)); - tester.buildService().remove(buildJob(app1, stagingTest)); - tester.buildService().remove(buildJob(app2, stagingTest)); - tester.buildService().remove(buildJob(app3, stagingTest)); + tester.buildService().remove(buildJob(app1.id(), systemTest)); + tester.buildService().remove(buildJob(app2.id(), systemTest)); + tester.buildService().remove(buildJob(app1.id(), stagingTest)); + tester.buildService().remove(buildJob(app2.id(), stagingTest)); + tester.buildService().remove(buildJob(app3.id(), stagingTest)); tester.jobCompletion(systemTest).application(app3).error(DeploymentJobs.JobError.outOfCapacity).submit(); jobs.clear(); - jobs.add(buildJob(app1, stagingTest)); - jobs.add(buildJob(app3, systemTest)); + jobs.add(buildJob(app1.id(), stagingTest)); + jobs.add(buildJob(app3.id(), systemTest)); assertJobsInOrder(jobs, tester.buildService().jobs()); tester.triggerUntilQuiescence(); - jobs.add(buildJob(app2, stagingTest)); - jobs.add(buildJob(app1, systemTest)); - jobs.add(buildJob(app3, stagingTest)); - jobs.add(buildJob(app2, systemTest)); + jobs.add(buildJob(app2.id(), stagingTest)); + jobs.add(buildJob(app1.id(), systemTest)); + jobs.add(buildJob(app3.id(), stagingTest)); + jobs.add(buildJob(app2.id(), systemTest)); assertJobsInOrder(jobs, tester.buildService().jobs()); } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalDeploymentTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalDeploymentTester.java index b6315bc6780..c0618937bdf 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalDeploymentTester.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalDeploymentTester.java @@ -11,6 +11,7 @@ import com.yahoo.security.KeyUtils; import com.yahoo.security.SignatureAlgorithm; import com.yahoo.security.X509CertificateBuilder; import com.yahoo.test.ManualClock; +import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.Instance; import com.yahoo.vespa.hosted.controller.ApplicationController; import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId; @@ -86,7 +87,8 @@ public class InternalDeploymentTester { public ConfigServerMock configServer() { return tester.configServer(); } public ApplicationController applications() { return tester.applications(); } public ManualClock clock() { return tester.clock(); } - public Instance app() { return tester.application(appId); } + public Application application() { return tester.application(appId); } + public Instance instance() { return tester.instance(appId); } public InternalDeploymentTester() { tester = new DeploymentTester(); @@ -145,10 +147,10 @@ public class InternalDeploymentTester { public ApplicationVersion deployNewSubmission() { ApplicationVersion applicationVersion = newSubmission(); - assertFalse(app().deployments().values().stream() - .anyMatch(deployment -> deployment.applicationVersion().equals(applicationVersion))); - assertEquals(applicationVersion, app().change().application().get()); - assertFalse(app().change().platform().isPresent()); + assertFalse(instance().deployments().values().stream() + .anyMatch(deployment -> deployment.applicationVersion().equals(applicationVersion))); + assertEquals(applicationVersion, instance().change().application().get()); + assertFalse(instance().change().platform().isPresent()); runJob(JobType.systemTest); runJob(JobType.stagingTest); @@ -164,18 +166,18 @@ public class InternalDeploymentTester { */ public void deployNewPlatform(Version version) { tester.upgradeSystem(version); - assertFalse(app().deployments().values().stream() - .anyMatch(deployment -> deployment.version().equals(version))); - assertEquals(version, app().change().platform().get()); - assertFalse(app().change().application().isPresent()); + assertFalse(instance().deployments().values().stream() + .anyMatch(deployment -> deployment.version().equals(version))); + assertEquals(version, instance().change().platform().get()); + assertFalse(instance().change().application().isPresent()); runJob(JobType.systemTest); runJob(JobType.stagingTest); runJob(JobType.productionUsCentral1); runJob(JobType.productionUsWest1); runJob(JobType.productionUsEast3); - assertTrue(app().productionDeployments().values().stream() - .allMatch(deployment -> deployment.version().equals(version))); + assertTrue(instance().productionDeployments().values().stream() + .allMatch(deployment -> deployment.version().equals(version))); assertTrue(tester.configServer().nodeRepository() .list(JobType.productionAwsUsEast1a.zone(tester.controller().system()), appId).stream() .allMatch(node -> node.currentVersion().equals(version))); @@ -185,7 +187,7 @@ public class InternalDeploymentTester { assertTrue(tester.configServer().nodeRepository() .list(JobType.productionUsEast3.zone(tester.controller().system()), appId).stream() .allMatch(node -> node.currentVersion().equals(version))); - assertFalse(app().change().hasTargets()); + assertFalse(instance().change().hasTargets()); } /** @@ -253,10 +255,10 @@ public class InternalDeploymentTester { runner.run(); assertTrue(jobs.run(run.id()).get().hasEnded()); assertFalse(jobs.run(run.id()).get().hasFailed()); - assertEquals(type.isProduction(), app().deployments().containsKey(zone)); + assertEquals(type.isProduction(), instance().deployments().containsKey(zone)); assertTrue(tester.configServer().nodeRepository().list(zone, testerId.id()).isEmpty()); - if ( ! app().deployments().containsKey(zone)) + if ( ! instance().deployments().containsKey(zone)) routing.removeEndpoints(deployment); routing.removeEndpoints(new DeploymentId(testerId.id(), zone)); } @@ -277,7 +279,7 @@ public class InternalDeploymentTester { * Creates and submits a new application, and then starts the job of the given type. */ public RunId newRun(JobType type) { - assertFalse(app().deploymentJobs().deployedInternally()); // Use this only once per test. + assertFalse(instance().deploymentJobs().deployedInternally()); // Use this only once per test. newSubmission(); tester.readyJobTrigger().maintain(); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java index 9dcfdb00036..6813e7f1206 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java @@ -90,7 +90,7 @@ public class InternalStepRunnerTest { @Test public void canSwitchFromScrewdriverAndBackAgain() { // Deploys a default application package with default build number. - tester.tester().deployCompletely(tester.app(), InternalDeploymentTester.applicationPackage); + tester.tester().deployCompletely(tester.application(), InternalDeploymentTester.applicationPackage); tester.setEndpoints(appId, JobType.productionUsCentral1.zone(system())); tester.setEndpoints(appId, JobType.productionUsWest1.zone(system())); tester.setEndpoints(appId, JobType.productionUsEast3.zone(system())); @@ -106,11 +106,11 @@ public class InternalStepRunnerTest { tester.jobs().unregister(appId); try { - tester.tester().deployCompletely(tester.app(), InternalDeploymentTester.applicationPackage, BuildJob.defaultBuildNumber + 1); + tester.tester().deployCompletely(tester.application(), InternalDeploymentTester.applicationPackage, BuildJob.defaultBuildNumber + 1); throw new IllegalStateException("Component job should get even again with build numbers to produce a change."); } catch (AssertionError expected) { } - tester.tester().deployCompletely(tester.app(), InternalDeploymentTester.applicationPackage, BuildJob.defaultBuildNumber + 2); + tester.tester().deployCompletely(tester.application(), InternalDeploymentTester.applicationPackage, BuildJob.defaultBuildNumber + 2); } @Test @@ -362,7 +362,7 @@ public class InternalStepRunnerTest { tester.configServer().setVersion(appId, zone, version); tester.runner().run(); assertEquals(1, tester.jobs().active().size()); - assertEquals(version, tester.tester().application(appId).deployments().get(zone).version()); + assertEquals(version, tester.tester().instance(appId).deployments().get(zone).version()); try { tester.jobs().deploy(appId, JobType.productionApNortheast1, Optional.empty(), applicationPackage); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ClusterInfoMaintainerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ClusterInfoMaintainerTest.java index 72b16d76864..1f5cc100fac 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ClusterInfoMaintainerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ClusterInfoMaintainerTest.java @@ -7,10 +7,13 @@ import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.HostName; import com.yahoo.config.provision.NodeType; +import com.yahoo.config.provision.TenantName; import com.yahoo.config.provision.zone.ZoneId; +import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.ControllerTester; import com.yahoo.vespa.hosted.controller.api.integration.configserver.Node; import com.yahoo.vespa.hosted.controller.application.Deployment; +import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester; import com.yahoo.vespa.hosted.controller.persistence.MockCuratorDb; import org.junit.Test; @@ -29,8 +32,10 @@ public class ClusterInfoMaintainerTest { @Test public void maintain() { - ApplicationId app = tester.createAndDeploy("tenant1", "domain1", "app1", - Environment.dev, 123).id(); + tester.createTenant("tenant1", "domain123", 321L); + ApplicationId app = tester.createApplication(TenantName.from("tenant1"), "app1", "default", 123).id(); + ZoneId zone = ZoneId.from("dev", "us-east-1"); + tester.deploy(app, zone); // Precondition: no cluster info attached to the deployments Deployment deployment = tester.controller().applications().get(app).get().deployments().values().stream() @@ -38,7 +43,7 @@ public class ClusterInfoMaintainerTest { .get(); assertEquals(0, deployment.clusterInfo().size()); - addNodes(ZoneId.from("dev", "us-east-1")); + addNodes(zone); ClusterInfoMaintainer maintainer = new ClusterInfoMaintainer(tester.controller(), Duration.ofHours(1), new JobControl(new MockCuratorDb())); maintainer.maintain(); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentExpirerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentExpirerTest.java index b2ac44bf23b..f3c387eca1b 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentExpirerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentExpirerTest.java @@ -4,6 +4,7 @@ package com.yahoo.vespa.hosted.controller.maintenance; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.RegionName; import com.yahoo.config.provision.zone.ZoneId; +import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.Instance; import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.application.Deployment; @@ -33,11 +34,14 @@ public class DeploymentExpirerTest { ); DeploymentExpirer expirer = new DeploymentExpirer(tester.controller(), Duration.ofDays(10), new JobControl(new MockCuratorDb())); - Instance devApp = tester.createApplication("app1", "tenant1", 123L, 1L); - Instance prodApp = tester.createApplication("app2", "tenant2", 456L, 2L); + Application devApp = tester.createApplication("app1", "tenant1", 123L, 1L); + Application prodApp = tester.createApplication("app2", "tenant2", 456L, 2L); + + Instance devInstance = tester.instance(devApp.id()); + Instance prodInstance = tester.instance(prodApp.id()); // Deploy dev - tester.controllerTester().deploy(devApp, tester.controllerTester().toZone(Environment.dev)); + tester.controllerTester().deploy(devInstance.id(), tester.controllerTester().toZone(Environment.dev)); // Deploy prod ApplicationPackage prodAppPackage = new ApplicationPackageBuilder() @@ -45,19 +49,19 @@ public class DeploymentExpirerTest { .build(); tester.deployCompletely(prodApp, prodAppPackage); - assertEquals(1, permanentDeployments(devApp).size()); - assertEquals(1, permanentDeployments(prodApp).size()); + assertEquals(1, permanentDeployments(devInstance).size()); + assertEquals(1, permanentDeployments(prodInstance).size()); // Not expired at first expirer.maintain(); - assertEquals(1, permanentDeployments(devApp).size()); - assertEquals(1, permanentDeployments(prodApp).size()); + assertEquals(1, permanentDeployments(devInstance).size()); + assertEquals(1, permanentDeployments(prodInstance).size()); // The dev application is removed tester.clock().advance(Duration.ofDays(15)); expirer.maintain(); - assertEquals(0, permanentDeployments(devApp).size()); - assertEquals(1, permanentDeployments(prodApp).size()); + assertEquals(0, permanentDeployments(devInstance).size()); + assertEquals(1, permanentDeployments(prodInstance).size()); } private List<Deployment> permanentDeployments(Instance instance) { diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporterTest.java index d20ccdf5963..7a4d6821637 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporterTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporterTest.java @@ -4,6 +4,7 @@ package com.yahoo.vespa.hosted.controller.maintenance; import com.yahoo.component.Version; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.Environment; +import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.Instance; import com.yahoo.vespa.hosted.controller.api.integration.organization.Contact; import com.yahoo.vespa.hosted.controller.api.integration.organization.IssueId; @@ -78,24 +79,24 @@ public class DeploymentIssueReporterTest { tester.controllerTester().createTenant("tenant3", "domain3", 1L, contact); // Create and deploy one application for each of three tenants. - Instance app1 = tester.createApplication("application1", "tenant1", projectId1, propertyId1); - Instance app2 = tester.createApplication("application2", "tenant2", projectId2, propertyId2); - Instance app3 = tester.createApplication("application3", "tenant3", projectId3, propertyId3); + Application app1 = tester.createApplication("application1", "tenant1", projectId1, propertyId1); + Application app2 = tester.createApplication("application2", "tenant2", projectId2, propertyId2); + Application app3 = tester.createApplication("application3", "tenant3", projectId3, propertyId3); // NOTE: All maintenance should be idempotent within a small enough time interval, so maintain is called twice in succession throughout. // apps 1 and 3 have one failure each. tester.jobCompletion(component).application(app1).uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(app1, applicationPackage, true, systemTest); - tester.deployAndNotify(app1, applicationPackage, false, stagingTest); + tester.deployAndNotify(app1.id(), applicationPackage, true, systemTest); + tester.deployAndNotify(app1.id(), applicationPackage, false, stagingTest); // app2 is successful, but will fail later. tester.deployCompletely(app2, canaryPackage); tester.jobCompletion(component).application(app3).uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(app3, applicationPackage, true, systemTest); - tester.deployAndNotify(app3, applicationPackage, true, stagingTest); - tester.deployAndNotify(app3, applicationPackage, false, productionUsWest1); + tester.deployAndNotify(app3.id(), applicationPackage, true, systemTest); + tester.deployAndNotify(app3.id(), applicationPackage, true, stagingTest); + tester.deployAndNotify(app3.id(), applicationPackage, false, productionUsWest1); reporter.maintain(); reporter.maintain(); @@ -130,7 +131,7 @@ public class DeploymentIssueReporterTest { // app3 fixes their problems, but the ticket for app3 is left open; see the resolved ticket is not escalated when another escalation period has passed. - tester.deployAndNotify(app3, applicationPackage, true, productionUsWest1); + tester.deployAndNotify(app3.id(), applicationPackage, true, productionUsWest1); tester.clock().advance(maxInactivity.plus(Duration.ofDays(1))); reporter.maintain(); @@ -142,7 +143,7 @@ public class DeploymentIssueReporterTest { // app3 now has a new failure past max failure age; see that a new issue is filed. tester.jobCompletion(component).application(app3).nextBuildNumber().uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(app3, applicationPackage, false, systemTest); + tester.deployAndNotify(app3.id(), applicationPackage, false, systemTest); tester.clock().advance(maxInactivity.plus(maxFailureAge)); reporter.maintain(); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentMetricsMaintainerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentMetricsMaintainerTest.java index c4a835cd7e7..7f537c2e4bb 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentMetricsMaintainerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentMetricsMaintainerTest.java @@ -37,10 +37,10 @@ public class DeploymentMetricsMaintainerTest { @Test public void updates_metrics() { var application = tester.createApplication("app1", "tenant1", 123L, 1L); - deploy(application, Version.fromString("7.1")); + deploy(application.id(), Version.fromString("7.1")); DeploymentMetricsMaintainer maintainer = maintainer(tester.controller()); - Supplier<Instance> app = () -> tester.application(application.id()); + Supplier<Instance> app = () -> tester.instance(application.id()); Supplier<Deployment> deployment = () -> app.get().deployments().values().stream().findFirst().get(); // No metrics gathered yet @@ -51,7 +51,7 @@ public class DeploymentMetricsMaintainerTest { assertFalse("Never received any writes", deployment.get().activity().lastWritten().isPresent()); // Only get application metrics for old version - deploy(app.get(), Version.fromString("6.3.3")); + deploy(application.id(), Version.fromString("6.3.3")); maintainer.maintain(); assertEquals(0, app.get().metrics().queryServiceQuality(), 0); assertEquals(0, deployment.get().metrics().documentCount(), 0); @@ -60,7 +60,7 @@ public class DeploymentMetricsMaintainerTest { assertFalse("Never received any writes", deployment.get().activity().lastWritten().isPresent()); // Metrics are gathered and saved to application - deploy(app.get(), Version.fromString("7.5.5")); + deploy(application.id(), Version.fromString("7.5.5")); var metrics0 = Map.of(ClusterMetrics.QUERIES_PER_SECOND, 1D, ClusterMetrics.FEED_PER_SECOND, 2D, ClusterMetrics.DOCUMENT_COUNT, 3D, @@ -127,8 +127,8 @@ public class DeploymentMetricsMaintainerTest { return new DeploymentMetricsMaintainer(controller, Duration.ofDays(1), new JobControl(controller.curator())); } - private void deploy(Instance instance, Version version) { - tester.controllerTester().deploy(instance, + private void deploy(ApplicationId id, Version version) { + tester.controllerTester().deploy(id, ZoneId.from(Environment.dev, RegionName.from("us-east-1")), Optional.of(new ApplicationPackage(new byte[0])), false, diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporterTest.java index 46e6d9c3f50..11749afb6ed 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporterTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporterTest.java @@ -2,8 +2,10 @@ package com.yahoo.vespa.hosted.controller.maintenance; import com.yahoo.component.Version; +import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.zone.ZoneId; +import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.Instance; import com.yahoo.vespa.hosted.controller.Controller; import com.yahoo.vespa.hosted.controller.ControllerTester; @@ -18,6 +20,7 @@ import com.yahoo.vespa.hosted.controller.persistence.MockCuratorDb; import org.junit.Test; import java.time.Duration; +import java.util.Optional; import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.component; import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.productionUsWest1; @@ -46,10 +49,10 @@ public class MetricsReporterTest { assertEquals(0.0, metrics.getMetric(MetricsReporter.DEPLOYMENT_FAIL_METRIC)); // Deploy all apps successfully - Instance app1 = tester.createApplication("app1", "tenant1", 1, 11L); - Instance app2 = tester.createApplication("app2", "tenant1", 2, 22L); - Instance app3 = tester.createApplication("app3", "tenant1", 3, 33L); - Instance app4 = tester.createApplication("app4", "tenant1", 4, 44L); + Application app1 = tester.createApplication("app1", "tenant1", 1, 11L); + Application app2 = tester.createApplication("app2", "tenant1", 2, 22L); + Application app3 = tester.createApplication("app3", "tenant1", 3, 33L); + Application app4 = tester.createApplication("app4", "tenant1", 4, 44L); tester.deployCompletely(app1, applicationPackage); tester.deployCompletely(app2, applicationPackage); tester.deployCompletely(app3, applicationPackage); @@ -60,7 +63,7 @@ public class MetricsReporterTest { // 1 app fails system-test tester.jobCompletion(component).application(app4).nextBuildNumber().uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(app4, applicationPackage, false, systemTest); + tester.deployAndNotify(app4.id(), Optional.of(applicationPackage), false, systemTest); metricsReporter.maintain(); assertEquals(25.0, metrics.getMetric(MetricsReporter.DEPLOYMENT_FAIL_METRIC)); @@ -76,25 +79,25 @@ public class MetricsReporterTest { MetricsReporter reporter = createReporter(tester.controller()); - Instance app = tester.createApplication("app1", "tenant1", 1, 11L); + Application app = tester.createApplication("app1", "tenant1", 1, 11L); tester.deployCompletely(app, applicationPackage); reporter.maintain(); - assertEquals(Duration.ZERO, getAverageDeploymentDuration(app)); // An exceptionally fast deployment :-) + assertEquals(Duration.ZERO, getAverageDeploymentDuration(app.id())); // An exceptionally fast deployment :-) // App spends 3 hours deploying tester.jobCompletion(component).application(app).nextBuildNumber().uploadArtifact(applicationPackage).submit(); tester.clock().advance(Duration.ofHours(1)); - tester.deployAndNotify(app, applicationPackage, true, systemTest); + tester.deployAndNotify(app.id(), Optional.of(applicationPackage), true, systemTest); tester.clock().advance(Duration.ofMinutes(30)); - tester.deployAndNotify(app, applicationPackage, true, stagingTest); + tester.deployAndNotify(app.id(), Optional.of(applicationPackage), true, stagingTest); tester.clock().advance(Duration.ofMinutes(90)); - tester.deployAndNotify(app, applicationPackage, true, productionUsWest1); + tester.deployAndNotify(app.id(), Optional.of(applicationPackage), true, productionUsWest1); reporter.maintain(); // Average time is 1 hour (system-test) + 90 minutes (staging-test runs in parallel with system-test) + 90 minutes (production) / 3 jobs - assertEquals(Duration.ofMinutes(80), getAverageDeploymentDuration(app)); + assertEquals(Duration.ofMinutes(80), getAverageDeploymentDuration(app.id())); // Another deployment starts and stalls for 12 hours tester.jobCompletion(component).application(app).nextBuildNumber(2).uploadArtifact(applicationPackage).submit(); @@ -105,7 +108,7 @@ public class MetricsReporterTest { .plus(Duration.ofHours(12)) // hanging staging-test .plus(Duration.ofMinutes(90)) // previous production job .dividedBy(3), // Total number of orchestrated jobs - getAverageDeploymentDuration(app)); + getAverageDeploymentDuration(app.id())); } @Test @@ -117,46 +120,46 @@ public class MetricsReporterTest { .build(); MetricsReporter reporter = createReporter(tester.controller()); - Instance app = tester.createApplication("app1", "tenant1", 1, 11L); + Application app = tester.createApplication("app1", "tenant1", 1, 11L); // Initial deployment without failures tester.deployCompletely(app, applicationPackage); reporter.maintain(); - assertEquals(0, getDeploymentsFailingUpgrade(app)); + assertEquals(0, getDeploymentsFailingUpgrade(app.id())); // Failing application change is not counted tester.jobCompletion(component).application(app).nextBuildNumber().uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(app, applicationPackage, false, systemTest); + tester.deployAndNotify(app.id(), Optional.of(applicationPackage), false, systemTest); reporter.maintain(); - assertEquals(0, getDeploymentsFailingUpgrade(app)); + assertEquals(0, getDeploymentsFailingUpgrade(app.id())); // Application change completes - tester.deployAndNotify(app, applicationPackage, true, systemTest); - tester.deployAndNotify(app, applicationPackage, true, stagingTest); - tester.deployAndNotify(app, applicationPackage, true, productionUsWest1); + tester.deployAndNotify(app.id(), Optional.of(applicationPackage), true, systemTest); + tester.deployAndNotify(app.id(), Optional.of(applicationPackage), true, stagingTest); + tester.deployAndNotify(app.id(), Optional.of(applicationPackage), true, productionUsWest1); assertFalse("Change deployed", tester.controller().applications().require(app.id()).change().hasTargets()); // New versions is released and upgrade fails in test environments Version version = Version.fromString("7.1"); tester.upgradeSystem(version); tester.upgrader().maintain(); - tester.deployAndNotify(app, applicationPackage, false, systemTest); - tester.deployAndNotify(app, applicationPackage, false, stagingTest); + tester.deployAndNotify(app.id(), Optional.of(applicationPackage), false, systemTest); + tester.deployAndNotify(app.id(), Optional.of(applicationPackage), false, stagingTest); reporter.maintain(); - assertEquals(2, getDeploymentsFailingUpgrade(app)); + assertEquals(2, getDeploymentsFailingUpgrade(app.id())); // Test and staging pass and upgrade fails in production - tester.deployAndNotify(app, applicationPackage, true, systemTest); - tester.deployAndNotify(app, applicationPackage, true, stagingTest); - tester.deployAndNotify(app, applicationPackage, false, productionUsWest1); + tester.deployAndNotify(app.id(), Optional.of(applicationPackage), true, systemTest); + tester.deployAndNotify(app.id(), Optional.of(applicationPackage), true, stagingTest); + tester.deployAndNotify(app.id(), Optional.of(applicationPackage), false, productionUsWest1); reporter.maintain(); - assertEquals(1, getDeploymentsFailingUpgrade(app)); + assertEquals(1, getDeploymentsFailingUpgrade(app.id())); // Upgrade eventually succeeds - tester.deployAndNotify(app, applicationPackage, true, productionUsWest1); + tester.deployAndNotify(app.id(), Optional.of(applicationPackage), true, productionUsWest1); assertFalse("Upgrade deployed", tester.controller().applications().require(app.id()).change().hasTargets()); reporter.maintain(); - assertEquals(0, getDeploymentsFailingUpgrade(app)); + assertEquals(0, getDeploymentsFailingUpgrade(app.id())); } @Test @@ -168,12 +171,12 @@ public class MetricsReporterTest { .region("us-east-3") .build(); MetricsReporter reporter = createReporter(tester.controller()); - Instance instance = tester.createApplication("app1", "tenant1", 1, 11L); - tester.configServer().generateWarnings(new DeploymentId(instance.id(), ZoneId.from("prod", "us-west-1")), 3); - tester.configServer().generateWarnings(new DeploymentId(instance.id(), ZoneId.from("prod", "us-east-3")), 4); - tester.deployCompletely(instance, applicationPackage); + Application application = tester.createApplication("app1", "tenant1", 1, 11L); + tester.configServer().generateWarnings(new DeploymentId(application.id(), ZoneId.from("prod", "us-west-1")), 3); + tester.configServer().generateWarnings(new DeploymentId(application.id(), ZoneId.from("prod", "us-east-3")), 4); + tester.deployCompletely(application, applicationPackage); reporter.maintain(); - assertEquals(4, getDeploymentWarnings(instance)); + assertEquals(4, getDeploymentWarnings(application.id())); } @Test @@ -185,7 +188,7 @@ public class MetricsReporterTest { MetricsReporter reporter = createReporter(tester.tester().controller()); reporter.maintain(); assertEquals(tester.clock().instant().getEpochSecond() - 1, - getMetric(MetricsReporter.DEPLOYMENT_BUILD_AGE_SECONDS, tester.app())); + getMetric(MetricsReporter.DEPLOYMENT_BUILD_AGE_SECONDS, tester.instance().id())); } @Test @@ -198,11 +201,11 @@ public class MetricsReporterTest { .region("us-east-3") .build(); MetricsReporter reporter = createReporter(tester.controller()); - Instance instance = tester.createApplication("app1", "tenant1", 1, 11L); + Application application = tester.createApplication("app1", "tenant1", 1, 11L); reporter.maintain(); assertEquals("Queue is empty initially", 0, metrics.getMetric(MetricsReporter.NAME_SERVICE_REQUESTS_QUEUED).intValue()); - tester.deployCompletely(instance, applicationPackage); + tester.deployCompletely(application, applicationPackage); reporter.maintain(); assertEquals("Deployment queues name services requests", 6, metrics.getMetric(MetricsReporter.NAME_SERVICE_REQUESTS_QUEUED).intValue()); @@ -211,31 +214,31 @@ public class MetricsReporterTest { assertEquals("Queue consumed", 0, metrics.getMetric(MetricsReporter.NAME_SERVICE_REQUESTS_QUEUED).intValue()); } - private Duration getAverageDeploymentDuration(Instance instance) { - return Duration.ofSeconds(getMetric(MetricsReporter.DEPLOYMENT_AVERAGE_DURATION, instance).longValue()); + private Duration getAverageDeploymentDuration(ApplicationId id) { + return Duration.ofSeconds(getMetric(MetricsReporter.DEPLOYMENT_AVERAGE_DURATION, id).longValue()); } - private int getDeploymentsFailingUpgrade(Instance instance) { - return getMetric(MetricsReporter.DEPLOYMENT_FAILING_UPGRADES, instance).intValue(); + private int getDeploymentsFailingUpgrade(ApplicationId id) { + return getMetric(MetricsReporter.DEPLOYMENT_FAILING_UPGRADES, id).intValue(); } - private int getDeploymentWarnings(Instance instance) { - return getMetric(MetricsReporter.DEPLOYMENT_WARNINGS, instance).intValue(); + private int getDeploymentWarnings(ApplicationId id) { + return getMetric(MetricsReporter.DEPLOYMENT_WARNINGS, id).intValue(); } - private Number getMetric(String name, Instance instance) { - return metrics.getMetric((dimensions) -> instance.id().tenant().value().equals(dimensions.get("tenant")) && - appDimension(instance).equals(dimensions.get("app")), + private Number getMetric(String name, ApplicationId id) { + return metrics.getMetric((dimensions) -> id.tenant().value().equals(dimensions.get("tenant")) && + appDimension(id).equals(dimensions.get("app")), name) - .orElseThrow(() -> new RuntimeException("Expected metric to exist for " + instance.id())); + .orElseThrow(() -> new RuntimeException("Expected metric to exist for " + id)); } private MetricsReporter createReporter(Controller controller) { return new MetricsReporter(controller, metrics, new JobControl(new MockCuratorDb())); } - private static String appDimension(Instance instance) { - return instance.id().application().value() + "." + instance.id().instance().value(); + private static String appDimension(ApplicationId id) { + return id.application().value() + "." + id.instance().value(); } } 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 4bd1bfcffae..e438aab007f 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployerTest.java @@ -3,6 +3,7 @@ package com.yahoo.vespa.hosted.controller.maintenance; import com.yahoo.component.Version; import com.yahoo.config.provision.Environment; +import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.Instance; import com.yahoo.vespa.hosted.controller.api.integration.BuildService; import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; @@ -16,6 +17,7 @@ import org.junit.Test; import java.time.Duration; import java.util.List; +import java.util.Optional; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -36,49 +38,49 @@ public class OutstandingChangeDeployerTest { .region("us-west-1") .build(); - tester.createAndDeploy("app1", 11, applicationPackage); - tester.createAndDeploy("app2", 22, applicationPackage); + Application app1 = tester.createAndDeploy("app1", 11, applicationPackage); + Application app2 = tester.createAndDeploy("app2", 22, applicationPackage); Version version = new Version(6, 2); - tester.deploymentTrigger().triggerChange(tester.application("app1").id(), Change.of(version)); + tester.deploymentTrigger().triggerChange(tester.instance("app1").id(), Change.of(version)); tester.deploymentTrigger().triggerReadyJobs(); - assertEquals(Change.of(version), tester.application("app1").change()); - assertFalse(tester.application("app1").outstandingChange().hasTargets()); + assertEquals(Change.of(version), tester.instance("app1").change()); + assertFalse(tester.instance("app1").outstandingChange().hasTargets()); tester.jobCompletion(JobType.component) - .application(tester.application("app1")) + .application(app1) .sourceRevision(new SourceRevision("repository1","master", "cafed00d")) .nextBuildNumber() .uploadArtifact(applicationPackage) .submit(); - Instance app = tester.application("app1"); - assertTrue(app.outstandingChange().hasTargets()); - assertEquals("1.0.43-cafed00d", app.outstandingChange().application().get().id()); + Instance instance = tester.instance("app1"); + assertTrue(instance.outstandingChange().hasTargets()); + assertEquals("1.0.43-cafed00d", instance.outstandingChange().application().get().id()); assertEquals(2, tester.buildService().jobs().size()); deployer.maintain(); tester.deploymentTrigger().triggerReadyJobs(); assertEquals("No effect as job is in progress", 2, tester.buildService().jobs().size()); - assertEquals("1.0.43-cafed00d", app.outstandingChange().application().get().id()); + assertEquals("1.0.43-cafed00d", instance.outstandingChange().application().get().id()); - tester.deployAndNotify(app, applicationPackage, true, JobType.systemTest); - tester.deployAndNotify(app, applicationPackage, true, JobType.stagingTest); - tester.deployAndNotify(app, applicationPackage, true, JobType.productionUsWest1); - tester.deployAndNotify(app, applicationPackage, true, JobType.systemTest); - tester.deployAndNotify(app, applicationPackage, true, JobType.stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.productionUsWest1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, JobType.stagingTest); assertEquals("Upgrade done", 0, tester.buildService().jobs().size()); deployer.maintain(); tester.deploymentTrigger().triggerReadyJobs(); - app = tester.application("app1"); - assertEquals("1.0.43-cafed00d", app.change().application().get().id()); + instance = tester.instance("app1"); + assertEquals("1.0.43-cafed00d", instance.change().application().get().id()); List<BuildService.BuildJob> jobs = tester.buildService().jobs(); assertEquals(1, jobs.size()); assertEquals(JobType.productionUsWest1.jobName(), jobs.get(0).jobName()); assertEquals(11, jobs.get(0).projectId()); - assertFalse(tester.application("app1").outstandingChange().hasTargets()); + assertFalse(tester.instance("app1").outstandingChange().hasTargets()); } } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RotationStatusUpdaterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RotationStatusUpdaterTest.java index 7f97f1bc4a9..0eaa3e19927 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RotationStatusUpdaterTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RotationStatusUpdaterTest.java @@ -42,7 +42,7 @@ public class RotationStatusUpdaterTest { .build(); tester.deployCompletely(application, applicationPackage); - Supplier<Instance> app = () -> tester.application(application.id()); + Supplier<Instance> app = () -> tester.instance(application.id()); Supplier<Deployment> deployment1 = () -> app.get().deployments().get(zone1); Supplier<Deployment> deployment2 = () -> app.get().deployments().get(zone2); Supplier<Deployment> deployment3 = () -> app.get().deployments().get(zone3); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPoliciesTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPoliciesTest.java index 1763ff74fb0..c1e1f0d0607 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPoliciesTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPoliciesTest.java @@ -5,6 +5,7 @@ import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.HostName; import com.yahoo.config.provision.zone.ZoneId; +import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.Instance; import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId; import com.yahoo.vespa.hosted.controller.api.integration.configserver.LoadBalancer; @@ -38,8 +39,10 @@ public class RoutingPoliciesTest { private final DeploymentTester tester = new DeploymentTester(); - private final Instance app1 = tester.createApplication("app1", "tenant1", 1, 1L); - private final Instance app2 = tester.createApplication("app2", "tenant1", 1, 1L); + private final Application app1 = tester.createApplication("app1", "tenant1", 1, 1L); + private final Application app2 = tester.createApplication("app2", "tenant1", 1, 1L); + private final Instance instance1 = tester.instance(app1.id()); + private final Instance instance2 = tester.instance(app2.id()); private final ZoneId zone1 = ZoneId.from("prod", "us-west-1"); private final ZoneId zone2 = ZoneId.from("prod", "us-central-1"); @@ -152,12 +155,12 @@ public class RoutingPoliciesTest { "c1.app1.tenant1.us-central-1.vespa.oath.cloud" ); assertEquals(expectedRecords, recordNames()); - assertEquals(4, policies(app1).size()); + assertEquals(4, policies(instance1).size()); // Next deploy does nothing tester.deployCompletely(app1, applicationPackage, ++buildNumber); assertEquals(expectedRecords, recordNames()); - assertEquals(4, policies(app1).size()); + assertEquals(4, policies(instance1).size()); // Add 1 cluster in each zone and deploy provisionLoadBalancers(clustersPerZone + 1, app1.id(), zone1, zone2); @@ -171,7 +174,7 @@ public class RoutingPoliciesTest { "c2.app1.tenant1.us-central-1.vespa.oath.cloud" ); assertEquals(expectedRecords, recordNames()); - assertEquals(6, policies(app1).size()); + assertEquals(6, policies(instance1).size()); // Deploy another application provisionLoadBalancers(clustersPerZone, app2.id(), zone1, zone2); @@ -189,7 +192,7 @@ public class RoutingPoliciesTest { "c1.app2.tenant1.us-west-1.vespa.oath.cloud" ); assertEquals(expectedRecords, recordNames()); - assertEquals(4, policies(app2).size()); + assertEquals(4, policies(instance2).size()); // Deploy removes cluster from app1 provisionLoadBalancers(clustersPerZone, app1.id(), zone1, zone2); 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 a54d6f3ece7..498c20e69c5 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java @@ -5,6 +5,7 @@ import com.yahoo.component.Version; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.RegionName; import com.yahoo.config.provision.zone.ZoneId; +import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.Instance; import com.yahoo.vespa.hosted.controller.ControllerTester; import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; @@ -54,12 +55,19 @@ public class UpgraderTest { assertEquals("No applications: Nothing to do", 0, tester.buildService().jobs().size()); // Setup applications - Instance canary0 = tester.createAndDeploy("canary0", 1, "canary"); - Instance canary1 = tester.createAndDeploy("canary1", 2, "canary"); - Instance default0 = tester.createAndDeploy("default0", 3, "default"); - Instance default1 = tester.createAndDeploy("default1", 4, "default"); - Instance default2 = tester.createAndDeploy("default2", 5, "default"); - Instance conservative0 = tester.createAndDeploy("conservative0", 6, "conservative"); + Application canary0 = tester.createAndDeploy("canary0", 1, "canary"); + Application canary1 = tester.createAndDeploy("canary1", 2, "canary"); + Application default0 = tester.createAndDeploy("default0", 3, "default"); + Application default1 = tester.createAndDeploy("default1", 4, "default"); + Application default2 = tester.createAndDeploy("default2", 5, "default"); + Application conservative0 = tester.createAndDeploy("conservative0", 6, "conservative"); + + Instance canary0default = tester.instance(canary0.id()); + Instance canary1default = tester.instance(canary1.id()); + Instance default0default = tester.instance(default0.id()); + Instance default1default = tester.instance(default1.id()); + Instance default2default = tester.instance(default2.id()); + Instance conservative0default = tester.instance(conservative0.id()); tester.upgrader().maintain(); tester.triggerUntilQuiescence(); @@ -126,9 +134,9 @@ public class UpgraderTest { tester.upgradeSystem(version3); assertEquals(version3, tester.controller().versionStatus().systemVersion().get().versionNumber()); tester.upgrader().maintain(); - tester.buildService().remove(ControllerTester.buildJob(canary0, stagingTest)); - tester.buildService().remove(ControllerTester.buildJob(canary1, systemTest)); - tester.buildService().remove(ControllerTester.buildJob(canary1, stagingTest)); + tester.buildService().remove(ControllerTester.buildJob(canary0.id(), stagingTest)); + tester.buildService().remove(ControllerTester.buildJob(canary1.id(), systemTest)); + tester.buildService().remove(ControllerTester.buildJob(canary1.id(), stagingTest)); tester.triggerUntilQuiescence(); assertEquals("New system version: Should upgrade Canaries", 4, tester.buildService().jobs().size()); @@ -164,10 +172,10 @@ public class UpgraderTest { // Deploy application change tester.jobCompletion(component).application(default0).nextBuildNumber().uploadArtifact(DeploymentTester.applicationPackage("default")).submit(); tester.jobCompletion(stagingTest).application(default0).unsuccessful().submit(); - tester.deployAndNotify(default0, "default", true, systemTest); - tester.deployAndNotify(default0, "default", true, stagingTest); - tester.deployAndNotify(default0, "default", true, productionUsWest1); - tester.deployAndNotify(default0, "default", true, productionUsEast3); + tester.deployAndNotify(default0default.id(), DeploymentTester.applicationPackage("default"), true, systemTest); + tester.deployAndNotify(default0default.id(), DeploymentTester.applicationPackage("default"), true, stagingTest); + tester.deployAndNotify(default0default.id(), DeploymentTester.applicationPackage("default"), true, productionUsWest1); + tester.deployAndNotify(default0default.id(), DeploymentTester.applicationPackage("default"), true, productionUsEast3); tester.upgradeSystem(version3); assertEquals(VespaVersion.Confidence.high, tester.controller().versionStatus().systemVersion().get().confidence()); @@ -183,8 +191,8 @@ public class UpgraderTest { // --- Starting upgrading to a new version which breaks, causing upgrades to commence on the previous version Version version4 = Version.fromString("6.6"); - Instance default3 = tester.createAndDeploy("default3", 7, "default"); // need 4 to break a version - Instance default4 = tester.createAndDeploy("default4", 8, "default"); + Application default3 = tester.createAndDeploy("default3", 7, "default"); // need 4 to break a version + Application default4 = tester.createAndDeploy("default4", 8, "default"); tester.upgradeSystem(version4); tester.upgrader().maintain(); // cause canary upgrades to new version tester.triggerUntilQuiescence(); @@ -196,11 +204,11 @@ public class UpgraderTest { tester.triggerUntilQuiescence(); assertEquals("Upgrade of defaults are scheduled", 10, tester.buildService().jobs().size()); - assertEquals(version4, tester.application(default0.id()).change().platform().get()); - assertEquals(version4, tester.application(default1.id()).change().platform().get()); - assertEquals(version4, tester.application(default2.id()).change().platform().get()); - assertEquals(version4, tester.application(default3.id()).change().platform().get()); - assertEquals(version4, tester.application(default4.id()).change().platform().get()); + assertEquals(version4, tester.instance(default0.id()).change().platform().get()); + assertEquals(version4, tester.instance(default1.id()).change().platform().get()); + assertEquals(version4, tester.instance(default2.id()).change().platform().get()); + assertEquals(version4, tester.instance(default3.id()).change().platform().get()); + assertEquals(version4, tester.instance(default4.id()).change().platform().get()); tester.completeUpgrade(default0, version4, "default"); // State: Default applications started upgrading to version4 (and one completed) @@ -216,11 +224,11 @@ public class UpgraderTest { tester.triggerUntilQuiescence(); assertEquals("Upgrade of defaults are scheduled", 10, tester.buildService().jobs().size()); - assertEquals(version5, tester.application(default0.id()).change().platform().get()); - assertEquals(version4, tester.application(default1.id()).change().platform().get()); - assertEquals(version4, tester.application(default2.id()).change().platform().get()); - assertEquals(version4, tester.application(default3.id()).change().platform().get()); - assertEquals(version4, tester.application(default4.id()).change().platform().get()); + assertEquals(version5, tester.instance(default0.id()).change().platform().get()); + assertEquals(version4, tester.instance(default1.id()).change().platform().get()); + assertEquals(version4, tester.instance(default2.id()).change().platform().get()); + assertEquals(version4, tester.instance(default3.id()).change().platform().get()); + assertEquals(version4, tester.instance(default4.id()).change().platform().get()); tester.completeUpgrade(default1, version4, "default"); tester.completeUpgrade(default2, version4, "default"); @@ -252,7 +260,7 @@ public class UpgraderTest { assertEquals("Upgrade of defaults are scheduled on " + version4 + " instead, since " + version5 + " is broken: " + "This is default3 since it failed upgrade on both " + version4 + " and " + version5, 2, tester.buildService().jobs().size()); - assertEquals(version4, tester.application(default3.id()).change().platform().get()); + assertEquals(version4, tester.instance(default3.id()).change().platform().get()); } @Test @@ -271,18 +279,18 @@ public class UpgraderTest { assertEquals("No applications: Nothing to do", 0, tester.buildService().jobs().size()); // Setup applications - Instance canary0 = tester.createAndDeploy("canary0", 1, "canary"); - Instance canary1 = tester.createAndDeploy("canary1", 2, "canary"); - Instance default0 = tester.createAndDeploy("default0", 3, "default"); - Instance default1 = tester.createAndDeploy("default1", 4, "default"); - Instance default2 = tester.createAndDeploy("default2", 5, "default"); - Instance default3 = tester.createAndDeploy("default3", 6, "default"); - Instance default4 = tester.createAndDeploy("default4", 7, "default"); - Instance default5 = tester.createAndDeploy("default5", 8, "default"); - Instance default6 = tester.createAndDeploy("default6", 9, "default"); - Instance default7 = tester.createAndDeploy("default7", 10, "default"); - Instance default8 = tester.createAndDeploy("default8", 11, "default"); - Instance default9 = tester.createAndDeploy("default9", 12, "default"); + Application canary0 = tester.createAndDeploy("canary0", 1, "canary"); + Application canary1 = tester.createAndDeploy("canary1", 2, "canary"); + Application default0 = tester.createAndDeploy("default0", 3, "default"); + Application default1 = tester.createAndDeploy("default1", 4, "default"); + Application default2 = tester.createAndDeploy("default2", 5, "default"); + Application default3 = tester.createAndDeploy("default3", 6, "default"); + Application default4 = tester.createAndDeploy("default4", 7, "default"); + Application default5 = tester.createAndDeploy("default5", 8, "default"); + Application default6 = tester.createAndDeploy("default6", 9, "default"); + Application default7 = tester.createAndDeploy("default7", 10, "default"); + Application default8 = tester.createAndDeploy("default8", 11, "default"); + Application default9 = tester.createAndDeploy("default9", 12, "default"); tester.upgrader().maintain(); tester.triggerUntilQuiescence(); @@ -338,11 +346,12 @@ public class UpgraderTest { Version version = Version.fromString("6.2"); tester.upgradeSystem(version); - Instance app = tester.createApplication("app1", "tenant1", 1, 11L); + Application app = tester.createApplication("app1", "tenant1", 1, 11L); + Instance instance = tester.instance(app.id()); tester.jobCompletion(component).application(app).uploadArtifact(applicationPackage).submit(); - tester.deployAndNotify(app, applicationPackage, true, systemTest); - tester.deployAndNotify(app, applicationPackage, true, stagingTest); - tester.deployAndNotify(app, applicationPackage, true, productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsEast3); tester.upgrader().maintain(); tester.triggerUntilQuiescence(); @@ -357,12 +366,12 @@ public class UpgraderTest { tester.triggerUntilQuiescence(); // system-test completes successfully - tester.deployAndNotify(app, applicationPackage, true, systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, systemTest); // staging-test fails and failure is recorded - tester.deployAndNotify(app, applicationPackage, false, stagingTest); - assertTrue("Failure is recorded", tester.application(app.id()).deploymentJobs().hasFailures()); - assertTrue("Application has pending change", tester.application(app.id()).change().hasTargets()); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), false, stagingTest); + assertTrue("Failure is recorded", tester.instance(app.id()).deploymentJobs().hasFailures()); + assertTrue("Application has pending change", tester.instance(app.id()).change().hasTargets()); // New version is released version = Version.fromString("6.4"); @@ -373,7 +382,7 @@ public class UpgraderTest { tester.upgrader().maintain(); tester.triggerUntilQuiescence(); tester.jobCompletion(stagingTest).application(app).unsuccessful().submit(); - assertTrue("Application still has failures", tester.application(app.id()).deploymentJobs().hasFailures()); + assertTrue("Application still has failures", tester.instance(app.id()).deploymentJobs().hasFailures()); assertEquals(2, tester.buildService().jobs().size()); // Upgrader runs again, nothing happens as test jobs are already running. @@ -389,13 +398,13 @@ public class UpgraderTest { tester.upgradeSystem(version); // Setup applications - Instance canary0 = tester.createAndDeploy("canary0", 1, "canary"); - Instance canary1 = tester.createAndDeploy("canary1", 2, "canary"); - Instance default0 = tester.createAndDeploy("default0", 3, "default"); - Instance default1 = tester.createAndDeploy("default1", 4, "default"); - Instance default2 = tester.createAndDeploy("default2", 5, "default"); - Instance default3 = tester.createAndDeploy("default3", 6, "default"); - Instance default4 = tester.createAndDeploy("default4", 7, "default"); + Application canary0 = tester.createAndDeploy("canary0", 1, "canary"); + Application canary1 = tester.createAndDeploy("canary1", 2, "canary"); + Application default0 = tester.createAndDeploy("default0", 3, "default"); + Application default1 = tester.createAndDeploy("default1", 4, "default"); + Application default2 = tester.createAndDeploy("default2", 5, "default"); + Application default3 = tester.createAndDeploy("default3", 6, "default"); + Application default4 = tester.createAndDeploy("default4", 7, "default"); // New version is released version = Version.fromString("6.3"); @@ -455,13 +464,13 @@ public class UpgraderTest { tester.upgradeSystem(v0); // Setup applications on V0 - Instance canary0 = tester.createAndDeploy("canary0", 1, "canary"); - Instance canary1 = tester.createAndDeploy("canary1", 2, "canary"); - Instance default0 = tester.createAndDeploy("default0", 3, "default"); - Instance default1 = tester.createAndDeploy("default1", 4, "default"); - Instance default2 = tester.createAndDeploy("default2", 5, "default"); - Instance default3 = tester.createAndDeploy("default3", 6, "default"); - Instance default4 = tester.createAndDeploy("default4", 7, "default"); + Application canary0 = tester.createAndDeploy("canary0", 1, "canary"); + Application canary1 = tester.createAndDeploy("canary1", 2, "canary"); + Application default0 = tester.createAndDeploy("default0", 3, "default"); + Application default1 = tester.createAndDeploy("default1", 4, "default"); + Application default2 = tester.createAndDeploy("default2", 5, "default"); + Application default3 = tester.createAndDeploy("default3", 6, "default"); + Application default4 = tester.createAndDeploy("default4", 7, "default"); // V1 is released Version v1 = Version.fromString("6.3"); @@ -501,7 +510,7 @@ public class UpgraderTest { tester.upgrader().maintain(); tester.triggerUntilQuiescence(); assertEquals("Upgrade scheduled for remaining apps", 10, tester.buildService().jobs().size()); - assertEquals("default4 is still upgrading to 5.1", v1, tester.application(default4.id()).change().platform().get()); + assertEquals("default4 is still upgrading to 5.1", v1, tester.instance(default4.id()).change().platform().get()); // 4/5 applications fail (in the last prod zone) and lowers confidence tester.completeUpgradeWithError(default0, v2, "default", productionUsEast3); @@ -511,8 +520,8 @@ public class UpgraderTest { tester.upgradeSystem(v2); assertEquals(VespaVersion.Confidence.broken, tester.controller().versionStatus().systemVersion().get().confidence()); - assertEquals(v2, tester.application("default0").deployments().get(ZoneId.from("prod.us-west-1")).version()); - assertEquals(v0, tester.application("default0").deployments().get(ZoneId.from("prod.us-east-3")).version()); + assertEquals(v2, tester.instance("default0").deployments().get(ZoneId.from("prod.us-west-1")).version()); + assertEquals(v0, tester.instance("default0").deployments().get(ZoneId.from("prod.us-east-3")).version()); tester.upgrader().maintain(); tester.buildService().clear(); tester.triggerUntilQuiescence(); @@ -520,16 +529,16 @@ public class UpgraderTest { assertEquals("Upgrade to 5.1 scheduled for apps not completely on 5.1 or 5.2", 10, tester.buildService().jobs().size()); // The tester code for completing upgrades does not handle this scenario, so we trigger each step manually (for one app) - tester.deployAndNotify(tester.application("default0"), "default", true, systemTest); - tester.deployAndNotify(tester.application("default0"), "default", true, stagingTest); + tester.deployAndNotify(tester.instance("default0").id(), DeploymentTester.applicationPackage("default"), true, systemTest); + tester.deployAndNotify(tester.instance("default0").id(), DeploymentTester.applicationPackage("default"), true, stagingTest); // prod zone on 5.2 (usWest1) is skipped, but we still trigger the next zone from triggerReadyJobs: - tester.deployAndNotify(tester.application("default0"), "default", true, productionUsEast3); + tester.deployAndNotify(tester.instance("default0").id(), DeploymentTester.applicationPackage("default"), true, productionUsEast3); // Resulting state: - assertEquals(v2, tester.application("default0").deployments().get(ZoneId.from("prod.us-west-1")).version()); + assertEquals(v2, tester.instance("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").change().hasTargets()); + v1, tester.instance("default0").deployments().get(ZoneId.from("prod.us-east-3")).version()); + assertFalse(tester.instance("default0").change().hasTargets()); } @Test @@ -542,13 +551,13 @@ public class UpgraderTest { ApplicationPackage defaultPolicy = DeploymentTester.applicationPackage("default"); // Setup applications - Instance canary0 = tester.createAndDeploy("canary0", 1, canaryPolicy); - Instance canary1 = tester.createAndDeploy("canary1", 2, canaryPolicy); - Instance default0 = tester.createAndDeploy("default0", 3, defaultPolicy); - Instance default1 = tester.createAndDeploy("default1", 4, defaultPolicy); - Instance default2 = tester.createAndDeploy("default2", 5, defaultPolicy); - Instance default3 = tester.createAndDeploy("default3", 6, defaultPolicy); - Instance default4 = tester.createAndDeploy("default4", 7, defaultPolicy); + Application canary0 = tester.createAndDeploy("canary0", 1, canaryPolicy); + Application canary1 = tester.createAndDeploy("canary1", 2, canaryPolicy); + Application default0 = tester.createAndDeploy("default0", 3, defaultPolicy); + Application default1 = tester.createAndDeploy("default1", 4, defaultPolicy); + Application default2 = tester.createAndDeploy("default2", 5, defaultPolicy); + Application default3 = tester.createAndDeploy("default3", 6, defaultPolicy); + Application default4 = tester.createAndDeploy("default4", 7, defaultPolicy); // New version is released version = Version.fromString("6.3"); @@ -600,7 +609,7 @@ public class UpgraderTest { .region("us-west-1") .build(); - Instance app = tester.createAndDeploy("app1", 1, applicationPackage); + Application app = tester.createAndDeploy("app1", 1, applicationPackage); // New version is released version = Version.fromString("6.3"); @@ -643,7 +652,8 @@ public class UpgraderTest { .region("us-east-3") .build(); - Instance app = tester.createAndDeploy("app1", 1, applicationPackage); + Application app = tester.createAndDeploy("app1", 1, applicationPackage); + Instance instance = tester.instance(app.id()); // New version is released version = Version.fromString("6.3"); @@ -652,14 +662,14 @@ public class UpgraderTest { // Application upgrade starts tester.upgrader().maintain(); tester.triggerUntilQuiescence(); - tester.deployAndNotify(app, applicationPackage, true, systemTest); - tester.deployAndNotify(app, applicationPackage, true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, stagingTest); tester.clock().advance(Duration.ofHours(1)); // Entering block window after prod job is triggered - tester.deployAndNotify(app, applicationPackage, true, productionUsWest1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsWest1); assertEquals(1, tester.buildService().jobs().size()); // Next job triggered because upgrade is already rolling out. - tester.deployAndNotify(app, applicationPackage, true, productionUsCentral1); - tester.deployAndNotify(app, applicationPackage, true, productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsCentral1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsEast3); assertTrue("All jobs consumed", tester.buildService().jobs().isEmpty()); } @@ -680,7 +690,8 @@ public class UpgraderTest { .region("us-east-3") .build(); - Instance app = tester.createAndDeploy("app1", 1, applicationPackage); + Application app = tester.createAndDeploy("app1", 1, applicationPackage); + Instance instance = tester.instance(app.id()); // New version is released version = Version.fromString("6.3"); @@ -689,24 +700,25 @@ public class UpgraderTest { // Application upgrade starts tester.upgrader().maintain(); tester.triggerUntilQuiescence(); - tester.deployAndNotify(app, applicationPackage, true, systemTest); - tester.deployAndNotify(app, applicationPackage, true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, stagingTest); tester.clock().advance(Duration.ofHours(1)); // Entering block window after prod job is triggered - tester.deployAndNotify(app, applicationPackage, true, productionUsWest1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsWest1); assertEquals(1, tester.buildService().jobs().size()); // Next job triggered, as upgrade is already in progress. - tester.deployAndNotify(app, applicationPackage, false, productionUsCentral1); // us-central-1 fails, permitting a new revision. + // us-central-1 fails, permitting a new revision. + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), false, productionUsCentral1); // A new revision is submitted and starts rolling out. tester.jobCompletion(component).application(app).nextBuildNumber().uploadArtifact(applicationPackage).submit(); // us-central-1 fails again, and isn't re-triggered, because the target is now a revision instead. - tester.deployAndNotify(app, applicationPackage, false, productionUsCentral1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), false, productionUsCentral1); assertEquals(2, tester.buildService().jobs().size()); - tester.deployAndNotify(app, applicationPackage, true, systemTest); - tester.deployAndNotify(app, applicationPackage, true, stagingTest); - tester.deployAndNotify(app, applicationPackage, true, productionUsWest1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsWest1); // us-central-1 has an older version, and needs a new staging test to begin. - tester.deployAndNotify(app, applicationPackage, true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, stagingTest); // A new version is also released, cancelling the upgrade, since it is failing on a now outdated version. tester.clock().advance(Duration.ofDays(1)); @@ -716,10 +728,10 @@ public class UpgraderTest { tester.triggerUntilQuiescence(); // us-central-1 succeeds upgrade to 5.1, with the revision, but us-east-3 wants to proceed with only the revision change. - tester.deployAndNotify(app, applicationPackage, true, productionUsCentral1); - tester.deployAndNotify(app, applicationPackage, true, systemTest); - tester.deployAndNotify(app, applicationPackage, true, stagingTest); - tester.deployAndNotify(app, applicationPackage, true, productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsCentral1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsEast3); assertEquals(Collections.emptyList(), tester.buildService().jobs()); // Monday morning: We are not blocked, and the new version rolls out to all zones. @@ -727,12 +739,12 @@ public class UpgraderTest { tester.clock().advance(Duration.ofHours(17)); // Monday, 10:00 tester.upgrader().maintain(); tester.triggerUntilQuiescence(); - tester.deployAndNotify(app, applicationPackage, true, systemTest); - tester.deployAndNotify(app, applicationPackage, true, stagingTest); - tester.deployAndNotify(app, applicationPackage, true, productionUsWest1); - tester.deployAndNotify(app, applicationPackage, true, productionUsCentral1); - tester.deployAndNotify(app, applicationPackage, true, stagingTest); - tester.deployAndNotify(app, applicationPackage, true, productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsWest1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsCentral1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsEast3); assertTrue("All jobs consumed", tester.buildService().jobs().isEmpty()); // App is completely upgraded to the latest version @@ -758,13 +770,13 @@ public class UpgraderTest { .build(); // Setup applications - Instance canary0 = tester.createAndDeploy("canary0", 1, canaryApplicationPackage); - Instance canary1 = tester.createAndDeploy("canary1", 2, canaryApplicationPackage); - Instance default0 = tester.createAndDeploy("default0", 3, defaultApplicationPackage); - Instance default1 = tester.createAndDeploy("default1", 4, defaultApplicationPackage); - Instance default2 = tester.createAndDeploy("default2", 5, defaultApplicationPackage); - Instance default3 = tester.createAndDeploy("default3", 6, defaultApplicationPackage); - Instance default4 = tester.createAndDeploy("default4", 7, defaultApplicationPackage); + Application canary0 = tester.createAndDeploy("canary0", 1, canaryApplicationPackage); + Application canary1 = tester.createAndDeploy("canary1", 2, canaryApplicationPackage); + Application default0 = tester.createAndDeploy("default0", 3, defaultApplicationPackage); + Application default1 = tester.createAndDeploy("default1", 4, defaultApplicationPackage); + Application default2 = tester.createAndDeploy("default2", 5, defaultApplicationPackage); + Application default3 = tester.createAndDeploy("default3", 6, defaultApplicationPackage); + Application default4 = tester.createAndDeploy("default4", 7, defaultApplicationPackage); assertEquals(version, default0.oldestDeployedPlatform().get()); @@ -838,10 +850,10 @@ public class UpgraderTest { tester.completeUpgrade(default2, version, defaultApplicationPackageV2); tester.completeUpgrade(default3, version, defaultApplicationPackageV2); - assertEquals(version, tester.application(default0.id()).oldestDeployedPlatform().get()); - assertEquals(version, tester.application(default1.id()).oldestDeployedPlatform().get()); - assertEquals(version, tester.application(default2.id()).oldestDeployedPlatform().get()); - assertEquals(version, tester.application(default3.id()).oldestDeployedPlatform().get()); + assertEquals(version, tester.instance(default0.id()).oldestDeployedPlatform().get()); + assertEquals(version, tester.instance(default1.id()).oldestDeployedPlatform().get()); + assertEquals(version, tester.instance(default2.id()).oldestDeployedPlatform().get()); + assertEquals(version, tester.instance(default3.id()).oldestDeployedPlatform().get()); } @Test @@ -857,16 +869,16 @@ public class UpgraderTest { upgrader.setUpgradesPerMinute(0.2); // Setup applications - Instance canary0 = tester.createAndDeploy("canary0", 1, "canary"); - Instance canary1 = tester.createAndDeploy("canary1", 2, "canary"); - Instance default0 = tester.createAndDeploy("default0", 3, "default"); - Instance default1 = tester.createAndDeploy("default1", 4, "default"); - Instance default2 = tester.createAndDeploy("default2", 5, "default"); - Instance default3 = tester.createAndDeploy("default3", 6, "default"); + Application canary0 = tester.createAndDeploy("canary0", 1, "canary"); + Application canary1 = tester.createAndDeploy("canary1", 2, "canary"); + Application default0 = tester.createAndDeploy("default0", 3, "default"); + Application default1 = tester.createAndDeploy("default1", 4, "default"); + Application default2 = tester.createAndDeploy("default2", 5, "default"); + Application default3 = tester.createAndDeploy("default3", 6, "default"); // Dev deployment which should be ignored - Instance dev0 = tester.createApplication("dev0", "tenant1", 7, 1L); - tester.controllerTester().deploy(dev0, ZoneId.from(Environment.dev, RegionName.from("dev-region"))); + Application dev0 = tester.createApplication("dev0", "tenant1", 7, 1L); + tester.controllerTester().deploy(dev0.id(), ZoneId.from(Environment.dev, RegionName.from("dev-region"))); // New version is released and canaries upgrade version = Version.fromString("6.3"); @@ -910,8 +922,8 @@ public class UpgraderTest { .build(); // Setup applications - Instance canary0 = tester.createAndDeploy("canary0", 1, "canary"); - Instance default0 = tester.createAndDeploy("default0", 2, version6ApplicationPackage); + Application canary0 = tester.createAndDeploy("canary0", 1, "canary"); + Application default0 = tester.createAndDeploy("default0", 2, version6ApplicationPackage); // New major version is released version = Version.fromString("7.0"); @@ -944,8 +956,8 @@ public class UpgraderTest { .build(); // Setup applications - Instance canary0 = tester.createAndDeploy("canary0", 1, "canary"); - Instance default0 = tester.createAndDeploy("default0", 2, default0ApplicationPackage); + Application canary0 = tester.createAndDeploy("canary0", 1, "canary"); + Application default0 = tester.createAndDeploy("default0", 2, default0ApplicationPackage); tester.applications().lockOrThrow(default0.id(), a -> tester.applications().store(a.withMajorVersion(6))); assertEquals(OptionalInt.of(6), tester.applications().get(default0.id()).get().majorVersion()); @@ -987,9 +999,9 @@ public class UpgraderTest { .build(); // Setup applications - Instance canary0 = tester.createAndDeploy("canary", 1, version7CanaryApplicationPackage); - Instance default0 = tester.createAndDeploy("default0", 2, version7DefaultApplicationPackage); - Instance default1 = tester.createAndDeploy("default1", 3, "default"); + Application canary0 = tester.createAndDeploy("canary", 1, version7CanaryApplicationPackage); + Application default0 = tester.createAndDeploy("default0", 2, version7DefaultApplicationPackage); + Application default1 = tester.createAndDeploy("default1", 3, "default"); // New major version is released, but we don't want to upgrade to it yet tester.upgrader().setTargetMajorVersion(Optional.of(6)); @@ -1034,7 +1046,8 @@ public class UpgraderTest { .region("us-west-1") .build(); - Instance app = tester.createAndDeploy("app1", 1, applicationPackage); + Application app = tester.createAndDeploy("app1", 1, applicationPackage); + Instance instance = tester.instance(app.id()); // New version is released version = Version.fromString("6.3"); @@ -1042,9 +1055,9 @@ public class UpgraderTest { tester.upgrader().maintain(); tester.triggerUntilQuiescence(); - tester.deployAndNotify(app, applicationPackage, true, systemTest); - tester.deployAndNotify(app, applicationPackage, true, stagingTest); - tester.deployAndNotify(app, applicationPackage, false, productionUsWest1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), false, productionUsWest1); // New application change tester.jobCompletion(component).application(app).nextBuildNumber().uploadArtifact(applicationPackage).submit(); @@ -1057,14 +1070,14 @@ public class UpgraderTest { app.change().application().get().id().equals(applicationVersion)); // Deployment completes - tester.deployAndNotify(app, applicationPackage, true, systemTest); - tester.deployAndNotify(app, applicationPackage, true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, stagingTest); tester.jobCompletion(productionUsWest1).application(app).unsuccessful().submit(); - tester.deployAndNotify(app, applicationPackage, true, productionUsWest1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsWest1); assertTrue("All jobs consumed", tester.buildService().jobs().isEmpty()); - app = tester.application(app.id()); - for (Deployment deployment : app.deployments().values()) { + instance = tester.instance(app.id()); + for (Deployment deployment : instance.deployments().values()) { assertEquals(version, deployment.version()); assertEquals(applicationVersion, deployment.applicationVersion().id()); } @@ -1087,17 +1100,18 @@ public class UpgraderTest { .region("us-east-3") .build(); - Instance app = tester.createAndDeploy("app1", 1, applicationPackage); + Application app = tester.createAndDeploy("app1", 1, applicationPackage); + Instance instance = tester.instance(app.id()); tester.jobCompletion(component).application(app).nextBuildNumber().uploadArtifact(applicationPackage).submit(); // Application upgrade starts. tester.upgrader().maintain(); tester.triggerUntilQuiescence(); - tester.deployAndNotify(app, applicationPackage, true, systemTest); - tester.deployAndNotify(app, applicationPackage, true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, stagingTest); tester.clock().advance(Duration.ofHours(1)); // Entering block window after prod job is triggered. - tester.deployAndNotify(app, applicationPackage, true, productionUsWest1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsWest1); assertEquals(1, tester.buildService().jobs().size()); // Next job triggered in spite of block, because it is already rolling out. // New version is released, but upgrades won't start since there's already a revision rolling out. @@ -1106,18 +1120,18 @@ public class UpgraderTest { tester.triggerUntilQuiescence(); assertEquals(1, tester.buildService().jobs().size()); // Still just the revision upgrade. - tester.deployAndNotify(app, applicationPackage, true, productionUsCentral1); - tester.deployAndNotify(app, applicationPackage, true, productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsCentral1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsEast3); assertEquals(Collections.emptyList(), tester.buildService().jobs()); // No jobs left. // Upgrade may start, now that revision is rolled out. tester.upgrader().maintain(); tester.readyJobTrigger().maintain(); - tester.deployAndNotify(app, applicationPackage, true, systemTest); - tester.deployAndNotify(app, applicationPackage, true, stagingTest); - tester.deployAndNotify(app, applicationPackage, true, productionUsWest1); - tester.deployAndNotify(app, applicationPackage, true, productionUsCentral1); - tester.deployAndNotify(app, applicationPackage, true, productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsWest1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsCentral1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsEast3); assertTrue("All jobs consumed", tester.buildService().jobs().isEmpty()); } @@ -1139,17 +1153,18 @@ public class UpgraderTest { .region("us-east-3") .build(); - Instance app = tester.createAndDeploy("app1", 1, applicationPackage); + Application app = tester.createAndDeploy("app1", 1, applicationPackage); + Instance instance = tester.instance(app.id()); tester.jobCompletion(component).application(app).nextBuildNumber().uploadArtifact(applicationPackage).submit(); // Application revision starts rolling out. tester.upgrader().maintain(); tester.triggerUntilQuiescence(); - tester.deployAndNotify(app, applicationPackage, true, systemTest); - tester.deployAndNotify(app, applicationPackage, true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, stagingTest); tester.clock().advance(Duration.ofHours(1)); // Entering block window after prod job is triggered. - tester.deployAndNotify(app, applicationPackage, true, productionUsWest1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsWest1); assertEquals(1, tester.buildService().jobs().size()); // New revision is submitted, but is stored as outstanding, since the upgrade is proceeding in good fashion. @@ -1157,23 +1172,23 @@ public class UpgraderTest { tester.triggerUntilQuiescence(); assertEquals(3, tester.buildService().jobs().size()); // Just the running upgrade, and tests for the new revision. - tester.deployAndNotify(app, applicationPackage, true, systemTest); - tester.deployAndNotify(app, applicationPackage, true, stagingTest); - tester.deployAndNotify(app, applicationPackage, true, productionUsCentral1); - tester.deployAndNotify(app, applicationPackage, true, productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsCentral1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsEast3); assertEquals(Collections.emptyList(), tester.buildService().jobs()); // No jobs left. tester.outstandingChangeDeployer().run(); - assertFalse(tester.application(app.id()).change().hasTargets()); + assertFalse(tester.instance(app.id()).change().hasTargets()); tester.clock().advance(Duration.ofHours(2)); tester.outstandingChangeDeployer().run(); - assertTrue(tester.application(app.id()).change().hasTargets()); + assertTrue(tester.instance(app.id()).change().hasTargets()); tester.readyJobTrigger().run(); - tester.deployAndNotify(app, applicationPackage, true, productionUsWest1); - tester.deployAndNotify(app, applicationPackage, true, productionUsCentral1); - tester.deployAndNotify(app, applicationPackage, true, productionUsEast3); - assertFalse(tester.application(app.id()).change().hasTargets()); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsWest1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsCentral1); + tester.deployAndNotify(instance.id(), Optional.of(applicationPackage), true, productionUsEast3); + assertFalse(tester.instance(app.id()).change().hasTargets()); } @Test @@ -1183,61 +1198,62 @@ public class UpgraderTest { tester.upgradeSystem(version0); // Create an application with pinned platform version. - Instance instance = tester.createApplication("application", "tenant", 2, 3); + Application application = tester.createApplication("application", "tenant", 2, 3); + Instance instance = tester.instance(application.id()); ApplicationPackage applicationPackage = new ApplicationPackageBuilder().environment(Environment.prod) .region("us-east-3") .region("us-west-1") .build(); - tester.deploymentTrigger().forceChange(instance.id(), Change.empty().withPin()); + tester.deploymentTrigger().forceChange(application.id(), Change.empty().withPin()); - tester.deployCompletely(instance, applicationPackage); - assertFalse(tester.application(instance.id()).change().hasTargets()); - assertTrue(tester.application(instance.id()).change().isPinned()); - assertEquals(2, tester.application(instance.id()).deployments().size()); + tester.deployCompletely(application, applicationPackage); + assertFalse(tester.instance(application.id()).change().hasTargets()); + assertTrue(tester.instance(application.id()).change().isPinned()); + assertEquals(2, tester.instance(application.id()).deployments().size()); // Application does not upgrade. Version version1 = Version.fromString("6.3"); tester.upgradeSystem(version1); tester.upgrader().maintain(); - assertFalse(tester.application(instance.id()).change().hasTargets()); - assertTrue(tester.application(instance.id()).change().isPinned()); + assertFalse(tester.instance(application.id()).change().hasTargets()); + assertTrue(tester.instance(application.id()).change().isPinned()); // New application package is deployed. - tester.deployCompletely(instance, applicationPackage, BuildJob.defaultBuildNumber + 1); - assertFalse(tester.application(instance.id()).change().hasTargets()); - assertTrue(tester.application(instance.id()).change().isPinned()); + tester.deployCompletely(application, applicationPackage, BuildJob.defaultBuildNumber + 1); + assertFalse(tester.instance(application.id()).change().hasTargets()); + assertTrue(tester.instance(application.id()).change().isPinned()); // Application upgrades to new version when pin is removed. - tester.deploymentTrigger().cancelChange(instance.id(), PIN); + tester.deploymentTrigger().cancelChange(application.id(), PIN); tester.upgrader().maintain(); - assertTrue(tester.application(instance.id()).change().hasTargets()); - assertFalse(tester.application(instance.id()).change().isPinned()); + assertTrue(tester.instance(application.id()).change().hasTargets()); + assertFalse(tester.instance(application.id()).change().isPinned()); // Application is pinned to new version, and upgrade is therefore not cancelled, even though confidence is broken. - tester.deploymentTrigger().forceChange(instance.id(), Change.empty().withPin()); + tester.deploymentTrigger().forceChange(application.id(), Change.empty().withPin()); tester.upgrader().maintain(); tester.readyJobTrigger().maintain(); - assertEquals(version1, tester.application(instance.id()).change().platform().get()); + assertEquals(version1, tester.instance(application.id()).change().platform().get()); // Application fails upgrade after one zone is complete, and is pinned again to the old version. - tester.deployAndNotify(instance, true, systemTest); - tester.deployAndNotify(instance, true, stagingTest); - tester.deployAndNotify(instance, true, productionUsEast3); - tester.deploy(productionUsWest1, instance, Optional.empty(), false); - tester.deployAndNotify(instance, false, productionUsWest1); - tester.deploymentTrigger().cancelChange(instance.id(), ALL); - tester.deploymentTrigger().forceChange(instance.id(), Change.of(version0).withPin()); + tester.deployAndNotify(instance.id(), Optional.empty(), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, productionUsEast3); + tester.deploy(productionUsWest1, instance.id(), Optional.empty(), false); + tester.deployAndNotify(instance.id(), Optional.empty(), false, productionUsWest1); + tester.deploymentTrigger().cancelChange(application.id(), ALL); + tester.deploymentTrigger().forceChange(application.id(), Change.of(version0).withPin()); tester.buildService().clear(); - assertEquals(version0, tester.application(instance.id()).change().platform().get()); + assertEquals(version0, tester.instance(application.id()).change().platform().get()); // Application downgrades to pinned version. tester.readyJobTrigger().maintain(); - tester.deployAndNotify(instance, true, systemTest); - tester.deployAndNotify(instance, true, stagingTest); - tester.deployAndNotify(instance, true, productionUsEast3); - assertTrue(tester.application(instance.id()).change().hasTargets()); - tester.deployAndNotify(instance, true, productionUsWest1); - assertFalse(tester.application(instance.id()).change().hasTargets()); + tester.deployAndNotify(instance.id(), Optional.empty(), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, productionUsEast3); + assertTrue(tester.instance(application.id()).change().hasTargets()); + tester.deployAndNotify(instance.id(), Optional.empty(), true, productionUsWest1); + assertFalse(tester.instance(application.id()).change().hasTargets()); } @Test @@ -1250,8 +1266,8 @@ public class UpgraderTest { tester.upgrader().setTargetMajorVersion(Optional.of(6)); // All applications deploy on current version - Instance app1 = tester.createAndDeploy("app1", 1, "default"); - Instance app2 = tester.createAndDeploy("app2", 1, "default"); + Application app1 = tester.createAndDeploy("app1", 1, "default"); + Application app2 = tester.createAndDeploy("app2", 1, "default"); // Keep app 1 on current version tester.controller().applications().lockIfPresent(app1.id(), app -> tester.controller().applications().store(app.withChange(app.get().change().withPin()))); @@ -1283,8 +1299,9 @@ public class UpgraderTest { @Test public void testsEachUpgradeCombinationWithFailingDeployments() { DeploymentTester tester = new DeploymentTester(); - Instance instance = tester.createApplication("app1", "tenant1", 1, 1L); - Supplier<Instance> app = () -> tester.application(instance.id()); + Application application = tester.createApplication("app1", "tenant1", 1, 1L); + Instance instance = tester.instance(application.id()); + Supplier<Instance> app = () -> tester.instance(application.id()); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .region("us-central-1") @@ -1294,22 +1311,22 @@ public class UpgraderTest { // Application deploys on system version Version v1 = Version.fromString("6.1"); - tester.deployCompletely(instance, applicationPackage); + tester.deployCompletely(application, applicationPackage); // Next version is released and 2/3 deployments upgrade Version v2 = Version.fromString("6.2"); tester.upgradeSystem(v2); tester.upgrader().maintain(); assertEquals(Change.of(v2), app.get().change()); - tester.deployAndNotify(instance, true, systemTest); - tester.deployAndNotify(instance, true, stagingTest); - tester.deployAndNotify(instance, true, productionUsCentral1); + tester.deployAndNotify(instance.id(), Optional.empty(), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, productionUsCentral1); // While second deployment completes upgrade, version confidence becomes broken and upgrade is cancelled tester.upgrader().overrideConfidence(v2, VespaVersion.Confidence.broken); tester.computeVersionStatus(); tester.upgrader().maintain(); - tester.deployAndNotify(instance, true, productionUsWest1); + tester.deployAndNotify(instance.id(), Optional.empty(), true, productionUsWest1); assertTrue(app.get().change().isEmpty()); // Next version is released @@ -1317,21 +1334,21 @@ public class UpgraderTest { tester.upgradeSystem(v3); tester.upgrader().maintain(); assertEquals(Change.of(v3), app.get().change()); - tester.deployAndNotify(instance, true, systemTest); - tester.deployAndNotify(instance, true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, systemTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, stagingTest); // First deployment starts upgrading - tester.deploy(productionUsCentral1, instance, applicationPackage); + tester.deploy(productionUsCentral1, instance.id(), applicationPackage); // Before deployment completes, v1->v3 combination is tested as us-east-3 is still on v1 tester.readyJobTrigger().maintain(); - tester.deployAndNotify(instance, true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, stagingTest); assertEquals(v1, app.get().deploymentJobs().jobStatus().get(stagingTest).lastSuccess().get().sourcePlatform().get()); assertEquals(v3, app.get().deploymentJobs().jobStatus().get(stagingTest).lastSuccess().get().platform()); // First deployment fails and then successfully upgrades to v3 - tester.jobCompletion(productionUsCentral1).application(instance).unsuccessful().submit(); - tester.jobCompletion(productionUsCentral1).application(instance).submit(); + tester.jobCompletion(productionUsCentral1).application(application).unsuccessful().submit(); + tester.jobCompletion(productionUsCentral1).application(application).submit(); // Deployments are now on 3 versions assertEquals(v3, app.get().deployments().get(productionUsCentral1.zone(main)).version()); @@ -1342,19 +1359,19 @@ public class UpgraderTest { tester.readyJobTrigger().maintain(); assertEquals(v2, app.get().deploymentJobs().jobStatus().get(stagingTest).lastTriggered().get().sourcePlatform().get()); assertEquals(v3, app.get().deploymentJobs().jobStatus().get(stagingTest).lastTriggered().get().platform()); - tester.deployAndNotify(instance, true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, stagingTest); // Second deployment upgrades - tester.deployAndNotify(instance, true, productionUsWest1); + tester.deployAndNotify(instance.id(), Optional.empty(), true, productionUsWest1); // ... now we have to test v1->v3 again :( tester.readyJobTrigger().maintain(); assertEquals(v1, app.get().deploymentJobs().jobStatus().get(stagingTest).lastTriggered().get().sourcePlatform().get()); assertEquals(v3, app.get().deploymentJobs().jobStatus().get(stagingTest).lastTriggered().get().platform()); - tester.deployAndNotify(instance, true, stagingTest); + tester.deployAndNotify(instance.id(), Optional.empty(), true, stagingTest); // Upgrade completes - tester.deployAndNotify(instance, true, productionUsEast3); + tester.deployAndNotify(instance.id(), Optional.empty(), true, productionUsEast3); assertTrue("Upgrade complete", app.get().change().isEmpty()); } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerControllerTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerControllerTester.java index b8a0610bedd..290969623d8 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerControllerTester.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerControllerTester.java @@ -11,7 +11,7 @@ import com.yahoo.vespa.athenz.api.AthenzDomain; import com.yahoo.vespa.athenz.api.AthenzPrincipal; import com.yahoo.vespa.athenz.api.AthenzUser; import com.yahoo.vespa.athenz.api.OktaAccessToken; -import com.yahoo.vespa.hosted.controller.Instance; +import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.Controller; import com.yahoo.vespa.hosted.controller.api.application.v4.model.DeployOptions; import com.yahoo.vespa.hosted.controller.api.identifiers.Property; @@ -64,11 +64,11 @@ public class ContainerControllerTester { /** Returns the wrapped generic container tester */ public ContainerTester containerTester() { return containerTester; } - public Instance createApplication() { + public Application createApplication() { return createApplication("domain1","tenant1", "application1", "default"); } - public Instance createApplication(String athensDomain, String tenant, String application, String instance) { + public Application createApplication(String athensDomain, String tenant, String application, String instance) { AthenzDomain domain1 = addTenantAthenzDomain(athensDomain, "user"); AthenzPrincipal user = new AthenzPrincipal(new AthenzUser("user")); AthenzCredentials credentials = new AthenzCredentials(user, domain1, new OktaAccessToken("okta-token")); @@ -82,15 +82,14 @@ public class ContainerControllerTester { return controller().applications().createApplication(app, Optional.of(credentials)); } - public Instance deploy(Instance instance, ApplicationPackage applicationPackage, ZoneId zone) { - controller().applications().deploy(instance.id(), zone, Optional.of(applicationPackage), + public void deploy(ApplicationId id, ApplicationPackage applicationPackage, ZoneId zone) { + controller().applications().deploy(id, zone, Optional.of(applicationPackage), new DeployOptions(false, Optional.empty(), false, false)); - return instance; } - public void deployCompletely(Instance instance, ApplicationPackage applicationPackage, long projectId, + public void deployCompletely(Application application, ApplicationPackage applicationPackage, long projectId, boolean failStaging) { - jobCompletion(JobType.component).application(instance) + jobCompletion(JobType.component).application(application) .projectId(projectId) .uploadArtifact(applicationPackage) .submit(); @@ -99,14 +98,14 @@ public class ContainerControllerTester { for (var job : steps.jobs()) { if (!succeeding) return; var zone = job.zone(controller().system()); - deploy(instance, applicationPackage, zone); + deploy(application.id(), applicationPackage, zone); if (failStaging && zone.environment() == Environment.staging) { succeeding = false; } if (zone.environment().isTest()) { - controller().applications().deactivate(instance.id(), zone); + controller().applications().deactivate(application.id(), zone); } - jobCompletion(job).application(instance).success(succeeding).projectId(projectId).submit(); + jobCompletion(job).application(application).success(succeeding).projectId(projectId).submit(); } } @@ -128,13 +127,13 @@ public class ContainerControllerTester { /* * Authorize action on tenantDomain/application for a given screwdriverId */ - public void authorize(AthenzDomain tenantDomain, ScrewdriverId screwdriverId, ApplicationAction action, Instance instance) { + public void authorize(AthenzDomain tenantDomain, ScrewdriverId screwdriverId, ApplicationAction action, ApplicationId id) { AthenzClientFactoryMock mock = (AthenzClientFactoryMock) containerTester.container().components() .getComponent(AthenzClientFactoryMock.class.getName()); mock.getSetup() .domains.get(tenantDomain) - .applications.get(new com.yahoo.vespa.hosted.controller.api.identifiers.ApplicationId(instance.id().application().value())) + .applications.get(new com.yahoo.vespa.hosted.controller.api.identifiers.ApplicationId(id.application().value())) .addRoleMember(action, HostedAthenzIdentities.from(screwdriverId)); } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java index b2494be65b1..474944432fb 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java @@ -21,6 +21,7 @@ import com.yahoo.vespa.athenz.api.AthenzIdentity; import com.yahoo.vespa.athenz.api.AthenzUser; import com.yahoo.vespa.athenz.api.OktaAccessToken; import com.yahoo.vespa.config.SlimeUtils; +import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.Instance; import com.yahoo.vespa.hosted.controller.LockedTenant; import com.yahoo.vespa.hosted.controller.api.application.v4.EnvironmentResource; @@ -1238,12 +1239,12 @@ public class ApplicationApiTest extends ControllerContainerTest { createAthenzDomainWithAdmin(ATHENZ_TENANT_DOMAIN, USER_ID); configureAthenzIdentity(new com.yahoo.vespa.athenz.api.AthenzService(new AthenzDomain("another.domain"), "service"), true); - Instance instance = controllerTester.createApplication(ATHENZ_TENANT_DOMAIN.getName(), "tenant1", "application1", "default"); + Application application = controllerTester.createApplication(ATHENZ_TENANT_DOMAIN.getName(), "tenant1", "application1", "default"); ScrewdriverId screwdriverId = new ScrewdriverId(Long.toString(screwdriverProjectId)); - controllerTester.authorize(ATHENZ_TENANT_DOMAIN, screwdriverId, ApplicationAction.deploy, instance); + controllerTester.authorize(ATHENZ_TENANT_DOMAIN, screwdriverId, ApplicationAction.deploy, application.id()); controllerTester.jobCompletion(JobType.component) - .application(instance.id()) + .application(application.id()) .projectId(screwdriverProjectId) .uploadArtifact(applicationPackage) .submit(); @@ -1270,12 +1271,12 @@ public class ApplicationApiTest extends ControllerContainerTest { createAthenzDomainWithAdmin(ATHENZ_TENANT_DOMAIN, USER_ID); configureAthenzIdentity(new com.yahoo.vespa.athenz.api.AthenzService(ATHENZ_TENANT_DOMAIN, "service"), true); - Instance instance = controllerTester.createApplication(ATHENZ_TENANT_DOMAIN.getName(), "tenant1", "application1", "default"); - controllerTester.authorize(ATHENZ_TENANT_DOMAIN, screwdriverId, ApplicationAction.deploy, instance); + Application application = controllerTester.createApplication(ATHENZ_TENANT_DOMAIN.getName(), "tenant1", "application1", "default"); + controllerTester.authorize(ATHENZ_TENANT_DOMAIN, screwdriverId, ApplicationAction.deploy, application.id()); // Allow systemtest to succeed by notifying completion of system test controllerTester.jobCompletion(JobType.component) - .application(instance.id()) + .application(application.id()) .projectId(screwdriverProjectId) .uploadArtifact(applicationPackage) .submit(); @@ -1367,12 +1368,12 @@ public class ApplicationApiTest extends ControllerContainerTest { createAthenzDomainWithAdmin(ATHENZ_TENANT_DOMAIN, USER_ID); configureAthenzIdentity(new com.yahoo.vespa.athenz.api.AthenzService(ATHENZ_TENANT_DOMAIN, "service"), false); - Instance instance = controllerTester.createApplication(ATHENZ_TENANT_DOMAIN.getName(), "tenant1", "application1", "default"); - controllerTester.authorize(ATHENZ_TENANT_DOMAIN, screwdriverId, ApplicationAction.deploy, instance); + Application application = controllerTester.createApplication(ATHENZ_TENANT_DOMAIN.getName(), "tenant1", "application1", "default"); + controllerTester.authorize(ATHENZ_TENANT_DOMAIN, screwdriverId, ApplicationAction.deploy, application.id()); // Allow systemtest to succeed by notifying completion of system test controllerTester.jobCompletion(JobType.component) - .application(instance.id()) + .application(application.id()) .projectId(screwdriverProjectId) .uploadArtifact(applicationPackage) .submit(); @@ -1404,12 +1405,12 @@ public class ApplicationApiTest extends ControllerContainerTest { createAthenzDomainWithAdmin(ATHENZ_TENANT_DOMAIN, USER_ID); configureAthenzIdentity(new com.yahoo.vespa.athenz.api.AthenzService(ATHENZ_TENANT_DOMAIN, "service"), true); - Instance instance = controllerTester.createApplication(ATHENZ_TENANT_DOMAIN.getName(), "tenant1", "application1", "default"); - controllerTester.authorize(ATHENZ_TENANT_DOMAIN, screwdriverId, ApplicationAction.deploy, instance); + Application application = controllerTester.createApplication(ATHENZ_TENANT_DOMAIN.getName(), "tenant1", "application1", "default"); + controllerTester.authorize(ATHENZ_TENANT_DOMAIN, screwdriverId, ApplicationAction.deploy, application.id()); // Allow systemtest to succeed by notifying completion of system test controllerTester.jobCompletion(JobType.component) - .application(instance.id()) + .application(application.id()) .projectId(screwdriverProjectId) .uploadArtifact(applicationPackage) .submit(); @@ -1430,7 +1431,7 @@ public class ApplicationApiTest extends ControllerContainerTest { addUserToHostedOperatorRole(HostedAthenzIdentities.from(HOSTED_VESPA_OPERATOR)); tester.computeVersionStatus(); long projectId = 1; - Instance app = controllerTester.createApplication(); + Application app = controllerTester.createApplication(); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .region("us-central-1") @@ -1442,7 +1443,7 @@ public class ApplicationApiTest extends ControllerContainerTest { .application(app) .projectId(projectId); job.type(JobType.component).uploadArtifact(applicationPackage).submit(); - controllerTester.deploy(app, applicationPackage, TEST_ZONE); + controllerTester.deploy(app.id(), applicationPackage, TEST_ZONE); job.type(JobType.systemTest).submit(); // Notifying about job started not by the controller fails @@ -1482,7 +1483,7 @@ public class ApplicationApiTest extends ControllerContainerTest { controllerTester.containerTester().computeVersionStatus(); long projectId = 1; - Instance app = controllerTester.createApplication(); + Application app = controllerTester.createApplication(); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .region("us-central-1") @@ -1494,9 +1495,9 @@ public class ApplicationApiTest extends ControllerContainerTest { .projectId(projectId); job.type(JobType.component).uploadArtifact(applicationPackage).submit(); - controllerTester.deploy(app, applicationPackage, TEST_ZONE); + controllerTester.deploy(app.id(), applicationPackage, TEST_ZONE); job.type(JobType.systemTest).submit(); - controllerTester.deploy(app, applicationPackage, STAGING_ZONE); + controllerTester.deploy(app.id(), applicationPackage, STAGING_ZONE); job.type(JobType.stagingTest).error(DeploymentJobs.JobError.outOfCapacity).submit(); // Appropriate error is recorded @@ -1511,7 +1512,7 @@ public class ApplicationApiTest extends ControllerContainerTest { @Test public void applicationWithRoutingPolicy() { - Instance app = controllerTester.createApplication(); + Application app = controllerTester.createApplication(); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .region("us-west-1") diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java index 043ce712636..2f009d16254 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java @@ -55,7 +55,7 @@ public class JobControllerApiHandlerHelperTest { // Revision 1 gets deployed everywhere. ApplicationVersion revision1 = tester.deployNewSubmission(); - assertEquals(2, tester.app().deploymentJobs().projectId().getAsLong()); + assertEquals(2, tester.instance().deploymentJobs().projectId().getAsLong()); tester.clock().advance(Duration.ofMillis(1000)); // Revision 2 gets deployed everywhere except in us-east-3. @@ -80,9 +80,9 @@ public class JobControllerApiHandlerHelperTest { tester.cloud().set(FAILURE); tester.runner().run(); assertEquals(testFailure, tester.jobs().last(appId, productionUsWest1).get().status()); - assertEquals(revision2, tester.app().deployments().get(productionUsCentral1.zone(tester.tester().controller().system())).applicationVersion()); - assertEquals(revision1, tester.app().deployments().get(productionUsEast3.zone(tester.tester().controller().system())).applicationVersion()); - assertEquals(revision2, tester.app().deployments().get(productionUsWest1.zone(tester.tester().controller().system())).applicationVersion()); + assertEquals(revision2, tester.instance().deployments().get(productionUsCentral1.zone(tester.tester().controller().system())).applicationVersion()); + assertEquals(revision1, tester.instance().deployments().get(productionUsEast3.zone(tester.tester().controller().system())).applicationVersion()); + assertEquals(revision2, tester.instance().deployments().get(productionUsWest1.zone(tester.tester().controller().system())).applicationVersion()); tester.clock().advance(Duration.ofMillis(1000)); @@ -149,7 +149,7 @@ public class JobControllerApiHandlerHelperTest { var region = "us-west-1"; var applicationPackage = new ApplicationPackageBuilder().region(region).build(); // Deploy directly to production zone, like integration tests. - tester.tester().controller().applications().deploy(tester.app().id(), ZoneId.from("prod", region), + tester.tester().controller().applications().deploy(tester.instance().id(), ZoneId.from("prod", region), Optional.of(applicationPackage), new DeployOptions(true, Optional.empty(), false, false)); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/BadgeApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/BadgeApiTest.java index 09555dd9f2e..35ec5b0e37e 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/BadgeApiTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/BadgeApiTest.java @@ -2,7 +2,7 @@ package com.yahoo.vespa.hosted.controller.restapi.deployment; import com.yahoo.config.provision.AthenzService; import com.yahoo.config.provision.Environment; -import com.yahoo.vespa.hosted.controller.Instance; +import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.api.integration.deployment.SourceRevision; import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder; @@ -20,13 +20,13 @@ public class BadgeApiTest extends ControllerContainerTest { @Test public void testBadgeApi() { ContainerControllerTester tester = new ContainerControllerTester(container, responseFiles); - Instance instance = tester.createApplication("domain", "tenant", "application", "default"); + Application application = tester.createApplication("domain", "tenant", "application", "default"); ApplicationPackage packageWithService = new ApplicationPackageBuilder() .environment(Environment.prod) .athenzIdentity(com.yahoo.config.provision.AthenzDomain.from("domain"), AthenzService.from("service")) .region("us-west-1") .build(); - tester.controller().jobController().submit(instance.id(), + tester.controller().jobController().submit(application.id(), new SourceRevision("repository", "branch", "commit"), "foo@bar", 123, diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/DeploymentApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/DeploymentApiTest.java index adf48ea37cb..128ea0e6f7e 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/DeploymentApiTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/DeploymentApiTest.java @@ -6,6 +6,7 @@ import com.yahoo.component.Version; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.HostName; import com.yahoo.config.provision.zone.ZoneId; +import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.Instance; import com.yahoo.vespa.hosted.controller.Controller; import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; @@ -39,9 +40,9 @@ public class DeploymentApiTest extends ControllerContainerTest { .build(); // 3 applications deploy on current system version - Instance failingInstance = tester.createApplication("domain1", "tenant1", "application1", "default"); - Instance productionInstance = tester.createApplication("domain2", "tenant2", "application2", "default"); - Instance instanceWithoutDeployment = tester.createApplication("domain3", "tenant3", "application3", "default"); + Application failingInstance = tester.createApplication("domain1", "tenant1", "application1", "default"); + Application productionInstance = tester.createApplication("domain2", "tenant2", "application2", "default"); + Application instanceWithoutDeployment = tester.createApplication("domain3", "tenant3", "application3", "default"); tester.deployCompletely(failingInstance, applicationPackage, 1L, false); tester.deployCompletely(productionInstance, applicationPackage, 2L, false); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/rotation/RotationRepositoryTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/rotation/RotationRepositoryTest.java index 78f36fdf4a3..c563a4950de 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/rotation/RotationRepositoryTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/rotation/RotationRepositoryTest.java @@ -2,6 +2,7 @@ package com.yahoo.vespa.hosted.controller.rotation; import com.yahoo.config.provision.SystemName; +import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.Instance; import com.yahoo.vespa.hosted.controller.ControllerTester; import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; @@ -50,19 +51,21 @@ public class RotationRepositoryTest { private DeploymentTester tester; private RotationRepository repository; + private Application application; private Instance instance; @Before public void before() { tester = new DeploymentTester(new ControllerTester(rotationsConfig)); repository = tester.controller().applications().rotationRepository(); - instance = tester.createApplication("app1", "tenant1", 11L, 1L); + application = tester.createApplication("app1", "tenant1", 11L, 1L); + instance = tester.instance(application.id()); } @Test public void assigns_and_reuses_rotation() { // Deploying assigns a rotation - tester.deployCompletely(instance, applicationPackage); + tester.deployCompletely(application, applicationPackage); Rotation expected = new Rotation(new RotationId("foo-1"), "foo-1.com"); instance = tester.applications().require(instance.id()); @@ -81,7 +84,7 @@ public class RotationRepositoryTest { .region("us-west-1") .searchDefinition("search foo { }") // Update application package so there is something to deploy .build(); - tester.deployCompletely(instance, applicationPackage, 43); + tester.deployCompletely(application, applicationPackage, 43); assertEquals(List.of(expected.id()), rotationIds(tester.applications().require(instance.id()).rotations())); } @@ -89,13 +92,13 @@ public class RotationRepositoryTest { public void strips_whitespace_in_rotation_fqdn() { DeploymentTester tester = new DeploymentTester(new ControllerTester(rotationsConfigWhitespaces)); RotationRepository repository = tester.controller().applications().rotationRepository(); - Instance instance = tester.createApplication("app2", "tenant2", 22L, - 2L); - tester.deployCompletely(instance, applicationPackage); - instance = tester.applications().require(instance.id()); + Application application2 = tester.createApplication("app2", "tenant2", 22L, 2L); + + tester.deployCompletely(application2, applicationPackage); + Instance instance2 = tester.applications().require(application2.id()); try (RotationLock lock = repository.lock()) { - Rotation rotation = repository.getOrAssignRotation(instance, lock); + Rotation rotation = repository.getOrAssignRotation(instance2, lock); Rotation assignedRotation = new Rotation(new RotationId("foo-1"), "foo-1.com"); assertEquals(assignedRotation, rotation); } @@ -104,19 +107,17 @@ public class RotationRepositoryTest { @Test public void out_of_rotations() { // Assigns 1 rotation - tester.deployCompletely(instance, applicationPackage); + tester.deployCompletely(application, applicationPackage); // Assigns 1 more - Instance instance2 = tester.createApplication("app2", "tenant2", 22L, - 2L); - tester.deployCompletely(instance2, applicationPackage); + Application application2 = tester.createApplication("app2", "tenant2", 22L, 2L); + tester.deployCompletely(application2, applicationPackage); // We're now out of rotations thrown.expect(IllegalStateException.class); thrown.expectMessage("no rotations available"); - Instance instance3 = tester.createApplication("app3", "tenant3", 33L, - 3L); - tester.deployCompletely(instance3, applicationPackage); + Application application3 = tester.createApplication("app3", "tenant3", 33L, 3L); + tester.deployCompletely(application3, applicationPackage); } @Test @@ -125,11 +126,10 @@ public class RotationRepositoryTest { .globalServiceId("foo") .region("us-east-3") .build(); - Instance instance = tester.createApplication("app2", "tenant2", 22L, - 2L); + Application application2 = tester.createApplication("app2", "tenant2", 22L, 2L); thrown.expect(RuntimeException.class); thrown.expectMessage("less than 2 prod zones are defined"); - tester.deployCompletely(instance, applicationPackage); + tester.deployCompletely(application2, applicationPackage); } @Test @@ -138,9 +138,8 @@ public class RotationRepositoryTest { .region("us-east-3") .region("us-west-1") .build(); - tester.deployCompletely(instance, applicationPackage); - Instance app = tester.applications().require(instance.id()); - assertTrue(app.rotations().isEmpty()); + tester.deployCompletely(application, applicationPackage); + assertTrue(tester.instance(application.id()).rotations().isEmpty()); } @Test @@ -150,11 +149,10 @@ public class RotationRepositoryTest { .region("us-east-3") .region("us-west-1") .build(); - Instance instance = tester.createApplication("app2", "tenant2", 22L, - 2L); - tester.deployCompletely(instance, applicationPackage); - assertEquals(List.of(new RotationId("foo-1")), rotationIds(tester.applications().require(instance.id()).rotations())); - assertEquals("https://cd--app2--tenant2.global.vespa.oath.cloud:4443/", tester.applications().require(instance.id()) + Application application2 = tester.createApplication("app2", "tenant2", 22L, 2L); + tester.deployCompletely(application2, applicationPackage); + assertEquals(List.of(new RotationId("foo-1")), rotationIds(tester.instance(application2.id()).rotations())); + assertEquals("https://cd--app2--tenant2.global.vespa.oath.cloud:4443/", tester.instance(application2.id()) .endpointsIn(SystemName.cd).main().get().url().toString()); } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java index 3d12fe382ce..3aae5b9b2ae 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java @@ -7,6 +7,7 @@ import com.yahoo.component.Vtag; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.HostName; import com.yahoo.config.provision.zone.ZoneApi; +import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.Instance; import com.yahoo.vespa.hosted.controller.Controller; import com.yahoo.vespa.hosted.controller.ControllerTester; @@ -135,9 +136,9 @@ public class VersionStatusTest { tester.upgradeSystem(version1); // Setup applications - Instance app1 = tester.createAndDeploy("app1", 11, applicationPackage); - Instance app2 = tester.createAndDeploy("app2", 22, applicationPackage); - Instance app3 = tester.createAndDeploy("app3", 33, applicationPackage); + Application app1 = tester.createAndDeploy("app1", 11, applicationPackage); + Application app2 = tester.createAndDeploy("app2", 22, applicationPackage); + Application app3 = tester.createAndDeploy("app3", 33, applicationPackage); // version2 is released tester.upgradeSystem(version2); @@ -175,25 +176,25 @@ public class VersionStatusTest { tester.upgradeSystem(version0); // Setup applications - all running on version0 - Instance canary0 = tester.createAndDeploy("canary0", 1, "canary"); - Instance canary1 = tester.createAndDeploy("canary1", 2, "canary"); - Instance canary2 = tester.createAndDeploy("canary2", 3, "canary"); - Instance default0 = tester.createAndDeploy("default0", 4, "default"); - Instance default1 = tester.createAndDeploy("default1", 5, "default"); - Instance default2 = tester.createAndDeploy("default2", 6, "default"); - Instance default3 = tester.createAndDeploy("default3", 7, "default"); - Instance default4 = tester.createAndDeploy("default4", 8, "default"); - Instance default5 = tester.createAndDeploy("default5", 9, "default"); - Instance default6 = tester.createAndDeploy("default6", 10, "default"); - Instance default7 = tester.createAndDeploy("default7", 11, "default"); - Instance default8 = tester.createAndDeploy("default8", 12, "default"); - Instance default9 = tester.createAndDeploy("default9", 13, "default"); - Instance conservative0 = tester.createAndDeploy("conservative1", 14, "conservative"); + Application canary0 = tester.createAndDeploy("canary0", 1, "canary"); + Application canary1 = tester.createAndDeploy("canary1", 2, "canary"); + Application canary2 = tester.createAndDeploy("canary2", 3, "canary"); + Application default0 = tester.createAndDeploy("default0", 4, "default"); + Application default1 = tester.createAndDeploy("default1", 5, "default"); + Application default2 = tester.createAndDeploy("default2", 6, "default"); + Application default3 = tester.createAndDeploy("default3", 7, "default"); + Application default4 = tester.createAndDeploy("default4", 8, "default"); + Application default5 = tester.createAndDeploy("default5", 9, "default"); + Application default6 = tester.createAndDeploy("default6", 10, "default"); + Application default7 = tester.createAndDeploy("default7", 11, "default"); + Application default8 = tester.createAndDeploy("default8", 12, "default"); + Application default9 = tester.createAndDeploy("default9", 13, "default"); + Application conservative0 = tester.createAndDeploy("conservative1", 14, "conservative"); // Applications that do not affect confidence calculation: // Application without deployment - Instance ignored0 = tester.createApplication("ignored0", "tenant1", 1000, 1000L); + Application ignored0 = tester.createApplication("ignored0", "tenant1", 1000, 1000L); assertEquals("All applications running on this version: High", Confidence.high, confidence(tester.controller(), version0)); @@ -310,7 +311,7 @@ public class VersionStatusTest { tester.upgradeSystem(version0); // Create and deploy application on current version - Instance app = tester.createAndDeploy("app", 1, "canary"); + Application app = tester.createAndDeploy("app", 1, "canary"); tester.computeVersionStatus(); assertEquals(Confidence.high, confidence(tester.controller(), version0)); @@ -368,9 +369,9 @@ public class VersionStatusTest { assertEquals(5, tester.hourOfDayAfter(Duration.ZERO)); Version version0 = Version.fromString("7.1"); tester.upgradeSystem(version0); - Instance canary0 = tester.createAndDeploy("canary0", 1, "canary"); - Instance canary1 = tester.createAndDeploy("canary1", 1, "canary"); - Instance default0 = tester.createAndDeploy("default0", 1, "default"); + Application canary0 = tester.createAndDeploy("canary0", 1, "canary"); + Application canary1 = tester.createAndDeploy("canary1", 1, "canary"); + Application default0 = tester.createAndDeploy("default0", 1, "default"); tester.computeVersionStatus(); assertSame(Confidence.high, tester.controller().versionStatus().version(version0).confidence()); |