use of com.yahoo.vespa.hosted.controller.deployment.DeploymentTester in project vespa by vespa-engine.
the class ControllerTest method testDeployUntestedChangeFails.
@Test
public void testDeployUntestedChangeFails() {
DeploymentTester tester = new DeploymentTester();
ApplicationController applications = tester.controller().applications();
TenantId tenant = tester.controllerTester().createTenant("tenant1", "domain1", 11L);
Application app = tester.controllerTester().createApplication(tenant, "app1", "default", 1);
tester.deployCompletely(app, applicationPackage);
tester.controller().applications().lockOrThrow(app.id(), application -> {
application = application.withChange(Change.of(Version.fromString("6.3")));
applications.store(application);
try {
tester.controllerTester().deploy(app, ZoneId.from("prod", "corp-us-east-1"), applicationPackage);
fail("Expected exception");
} catch (IllegalArgumentException e) {
assertEquals("Rejecting deployment of application 'tenant1.app1' to zone prod.corp-us-east-1 as upgrade to 6.3 is not tested", e.getMessage());
}
});
}
use of com.yahoo.vespa.hosted.controller.deployment.DeploymentTester in project vespa by vespa-engine.
the class ControllerTest method testDeployment.
@Test
public void testDeployment() {
// Setup system
DeploymentTester tester = new DeploymentTester();
ApplicationController applications = tester.controller().applications();
ApplicationPackage applicationPackage = new ApplicationPackageBuilder().environment(Environment.prod).region("corp-us-east-1").region("us-east-3").build();
// staging job - succeeding
Version version1 = tester.defaultVespaVersion();
Application app1 = tester.createApplication("app1", "tenant1", 1, 11L);
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);
assertEquals(4, applications.require(app1.id()).deploymentJobs().jobStatus().size());
ApplicationVersion applicationVersion = tester.controller().applications().require(app1.id()).change().application().get();
assertTrue("Application version has been set during deployment", applicationVersion != ApplicationVersion.unknown);
assertStatus(JobStatus.initial(stagingTest).withTriggering(version1, applicationVersion, "", tester.clock().instant().minus(Duration.ofMillis(1))).withCompletion(42, Optional.empty(), tester.clock().instant(), tester.controller()), app1.id(), tester.controller());
// Causes first deployment job to be triggered
assertStatus(JobStatus.initial(productionCorpUsEast1).withTriggering(version1, applicationVersion, "", tester.clock().instant()), app1.id(), tester.controller());
tester.clock().advance(Duration.ofSeconds(1));
// production job (failing)
tester.deployAndNotify(app1, applicationPackage, false, productionCorpUsEast1);
assertEquals(4, applications.require(app1.id()).deploymentJobs().jobStatus().size());
JobStatus expectedJobStatus = JobStatus.initial(productionCorpUsEast1).withTriggering(version1, applicationVersion, "", // Triggered first without application version info
tester.clock().instant()).withCompletion(42, Optional.of(JobError.unknown), tester.clock().instant(), tester.controller()).withTriggering(version1, applicationVersion, "", // Re-triggering (due to failure) has application version info
tester.clock().instant());
assertStatus(expectedJobStatus, app1.id(), tester.controller());
// Simulate restart
tester.restartController();
applications = tester.controller().applications();
assertNotNull(tester.controller().tenants().tenant(new TenantId("tenant1")));
assertNotNull(applications.get(ApplicationId.from(TenantName.from("tenant1"), ApplicationName.from("application1"), InstanceName.from("default"))));
assertEquals(4, applications.require(app1.id()).deploymentJobs().jobStatus().size());
tester.clock().advance(Duration.ofHours(1));
// 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, false, systemTest);
assertStatus(JobStatus.initial(systemTest).withTriggering(version1, applicationVersion, "", tester.clock().instant().minus(Duration.ofMillis(1))).withCompletion(42, Optional.empty(), tester.clock().instant(), tester.controller()), app1.id(), tester.controller());
tester.deployAndNotify(app1, applicationPackage, true, stagingTest);
// production job succeeding now
tester.jobCompletion(productionCorpUsEast1).application(app1).unsuccessful().submit();
tester.deployAndNotify(app1, applicationPackage, true, productionCorpUsEast1);
expectedJobStatus = expectedJobStatus.withTriggering(version1, applicationVersion, "", tester.clock().instant().minus(Duration.ofMillis(1))).withCompletion(42, Optional.empty(), tester.clock().instant(), tester.controller());
assertStatus(expectedJobStatus, app1.id(), tester.controller());
// causes triggering of next production job
assertStatus(JobStatus.initial(productionUsEast3).withTriggering(version1, applicationVersion, "", tester.clock().instant()), app1.id(), tester.controller());
tester.deployAndNotify(app1, applicationPackage, true, productionUsEast3);
assertEquals(5, applications.get(app1.id()).get().deploymentJobs().jobStatus().size());
// prod zone removal is not allowed
applicationPackage = new ApplicationPackageBuilder().environment(Environment.prod).region("us-east-3").build();
tester.jobCompletion(component).application(app1).nextBuildNumber().uploadArtifact(applicationPackage).submit();
try {
tester.deploy(systemTest, app1, applicationPackage);
fail("Expected exception due to unallowed production deployment removal");
} catch (IllegalArgumentException e) {
assertEquals("deployment-removal: application 'tenant1.app1' is deployed in corp-us-east-1, but does not include this zone in deployment.xml", e.getMessage());
}
assertNotNull("Zone was not removed", applications.require(app1.id()).deployments().get(productionCorpUsEast1.zone(SystemName.main).get()));
JobStatus jobStatus = applications.require(app1.id()).deploymentJobs().jobStatus().get(productionCorpUsEast1);
assertNotNull("Deployment job was not removed", jobStatus);
assertEquals(42, jobStatus.lastCompleted().get().id());
assertEquals("Available change in staging-test", jobStatus.lastCompleted().get().reason());
// prod zone removal is allowed with override
applicationPackage = new ApplicationPackageBuilder().allow(ValidationId.deploymentRemoval).upgradePolicy("default").environment(Environment.prod).region("us-east-3").build();
tester.jobCompletion(component).application(app1).nextBuildNumber(2).uploadArtifact(applicationPackage).submit();
tester.deployAndNotify(app1, applicationPackage, true, systemTest);
assertNull("Zone was removed", applications.require(app1.id()).deployments().get(productionCorpUsEast1.zone(SystemName.main).get()));
assertNull("Deployment job was removed", applications.require(app1.id()).deploymentJobs().jobStatus().get(productionCorpUsEast1));
}
use of com.yahoo.vespa.hosted.controller.deployment.DeploymentTester in project vespa by vespa-engine.
the class ControllerTest method testDnsAliasRegistration.
@Test
public void testDnsAliasRegistration() {
DeploymentTester tester = new DeploymentTester();
Application application = tester.createApplication("app1", "tenant1", 1, 1L);
ApplicationPackage applicationPackage = new ApplicationPackageBuilder().environment(Environment.prod).globalServiceId("foo").region("us-west-1").region(// Two deployments should result in each DNS alias being registered once
"us-central-1").build();
tester.deployCompletely(application, applicationPackage);
assertEquals(2, tester.controllerTester().nameService().records().size());
Optional<Record> record = tester.controllerTester().nameService().findRecord(Record.Type.CNAME, RecordName.from("app1--tenant1.global.vespa.yahooapis.com"));
assertTrue(record.isPresent());
assertEquals("app1--tenant1.global.vespa.yahooapis.com", record.get().name().asString());
assertEquals("rotation-fqdn-01.", record.get().data().asString());
record = tester.controllerTester().nameService().findRecord(Record.Type.CNAME, RecordName.from("app1.tenant1.global.vespa.yahooapis.com"));
assertTrue(record.isPresent());
assertEquals("app1.tenant1.global.vespa.yahooapis.com", record.get().name().asString());
assertEquals("rotation-fqdn-01.", record.get().data().asString());
}
use of com.yahoo.vespa.hosted.controller.deployment.DeploymentTester in project vespa by vespa-engine.
the class ControllerTest method testCleanupOfStaleDeploymentData.
@Test
public void testCleanupOfStaleDeploymentData() throws IOException {
DeploymentTester tester = new DeploymentTester();
tester.controllerTester().zoneRegistry().setSystem(SystemName.cd);
tester.controllerTester().zoneRegistry().setZones(ZoneId.from("prod", "cd-us-central-1"));
Supplier<Map<JobType, JobStatus>> statuses = () -> tester.application(ApplicationId.from("vespa", "canary", "default")).deploymentJobs().jobStatus();
// Current system version, matches version in test data
Version version = Version.fromString("6.141.117");
tester.configServer().setDefaultVersion(version);
tester.updateVersionStatus(version);
assertEquals(version, tester.controller().versionStatus().systemVersion().get().versionNumber());
// Load test data data
byte[] json = Files.readAllBytes(Paths.get("src/test/java/com/yahoo/vespa/hosted/controller/maintenance/testdata/canary-with-stale-data.json"));
Application application = tester.controllerTester().createApplication(SlimeUtils.jsonToSlime(json));
ApplicationPackage applicationPackage = new ApplicationPackageBuilder().upgradePolicy("canary").region("cd-us-central-1").build();
tester.jobCompletion(component).application(application).uploadArtifact(applicationPackage).submit();
long cdJobsCount = statuses.get().keySet().stream().filter(type -> type.zone(SystemName.cd).isPresent()).count();
long mainJobsCount = statuses.get().keySet().stream().filter(type -> type.zone(SystemName.main).isPresent() && !type.zone(SystemName.cd).isPresent()).count();
assertEquals("Irrelevant (main) data is present.", 8, mainJobsCount);
// New version is released
version = Version.fromString("6.142.1");
tester.configServer().setDefaultVersion(version);
tester.updateVersionStatus(version);
assertEquals(version, tester.controller().versionStatus().systemVersion().get().versionNumber());
tester.upgrader().maintain();
tester.readyJobTrigger().maintain();
// Test environments pass
tester.deploy(DeploymentJobs.JobType.systemTest, application, applicationPackage);
tester.deploymentQueue().takeJobsToRun();
tester.clock().advance(Duration.ofMinutes(10));
tester.jobCompletion(systemTest).application(application).submit();
long newCdJobsCount = statuses.get().keySet().stream().filter(type -> type.zone(SystemName.cd).isPresent()).count();
long newMainJobsCount = statuses.get().keySet().stream().filter(type -> type.zone(SystemName.main).isPresent() && !type.zone(SystemName.cd).isPresent()).count();
assertEquals("Irrelevant (main) job data is removed.", 0, newMainJobsCount);
assertEquals("Relevant (cd) data is not removed.", cdJobsCount, newCdJobsCount);
}
use of com.yahoo.vespa.hosted.controller.deployment.DeploymentTester in project vespa by vespa-engine.
the class ControllerTest method testFailingSinceUpdates.
@Test
public void testFailingSinceUpdates() {
// Setup system
DeploymentTester tester = new DeploymentTester();
// Setup application
Application app = tester.createApplication("app1", "foo", 1, 1L);
// Initial failure
Instant initialFailure = tester.clock().instant();
tester.jobCompletion(component).application(app).uploadArtifact(applicationPackage).submit();
tester.deployAndNotify(app, applicationPackage, false, systemTest);
assertEquals("Failure age is right at initial failure", initialFailure.plus(Duration.ofMillis(2)), firstFailing(app, tester).get().at());
// Failure again -- failingSince should remain the same
tester.clock().advance(Duration.ofMillis(1000));
tester.deployAndNotify(app, applicationPackage, false, systemTest);
assertEquals("Failure age is right at second consecutive failure", initialFailure.plus(Duration.ofMillis(2)), firstFailing(app, tester).get().at());
// Success resets failingSince
tester.clock().advance(Duration.ofMillis(1000));
tester.deployAndNotify(app, applicationPackage, true, systemTest);
assertFalse(firstFailing(app, tester).isPresent());
// Complete deployment
tester.deployAndNotify(app, applicationPackage, true, stagingTest);
tester.deployAndNotify(app, applicationPackage, true, productionCorpUsEast1);
// Two repeated failures again.
// Initial failure
tester.clock().advance(Duration.ofMillis(1000));
initialFailure = tester.clock().instant();
tester.jobCompletion(component).application(app).nextBuildNumber().uploadArtifact(applicationPackage).submit();
tester.deployAndNotify(app, applicationPackage, false, systemTest);
assertEquals("Failure age is right at initial failure", initialFailure.plus(Duration.ofMillis(2)), firstFailing(app, tester).get().at());
// Failure again -- failingSince should remain the same
tester.clock().advance(Duration.ofMillis(1000));
tester.deployAndNotify(app, applicationPackage, false, systemTest);
assertEquals("Failure age is right at second consecutive failure", initialFailure.plus(Duration.ofMillis(2)), firstFailing(app, tester).get().at());
}
Aggregations