SessionPreparer { public PrepareResult prepare(HostValidator<ApplicationId> hostValidator, DeployLogger logger, PrepareParams params, Optional<ApplicationSet> currentActiveApplicationSet, Path tenantPath, Instant now, File serverDbSessionDir, ApplicationPackage applicationPackage, SessionZooKeeperClient sessionZooKeeperClient) { Preparation preparation = new Preparation(hostValidator, logger, params, currentActiveApplicationSet, tenantPath, serverDbSessionDir, applicationPackage, sessionZooKeeperClient); preparation.preprocess(); var distributedApplicationPackage = preparation.distributeApplicationPackage(); try { AllocatedHosts allocatedHosts = preparation.buildModels(now); preparation.makeResult(allocatedHosts); if ( ! params.isDryRun()) { preparation.writeStateZK(distributedApplicationPackage); preparation.writeEndpointCertificateMetadataZK(); preparation.writeContainerEndpointsZK(); preparation.writeApplicationRoles(); preparation.distribute(); } log.log(Level.FINE, () -> "time used " + params.getTimeoutBudget().timesUsed() + " : " + params.getApplicationId()); return preparation.result(); } catch (IllegalArgumentException e) { throw new InvalidApplicationException("Invalid application package", e); } } @Inject  SessionPreparer(ModelFactoryRegistry modelFactoryRegistry,
                           FileDistributionFactory fileDistributionFactory,
                           HostProvisionerProvider hostProvisionerProvider,
                           PermanentApplicationPackage permanentApplicationPackage,
                           ConfigserverConfig configserverConfig,
                           ConfigDefinitionRepo configDefinitionRepo,
                           Curator curator,
                           Zone zone,
                           FlagSource flagSource,
                           SecretStore secretStore); PrepareResult prepare(HostValidator<ApplicationId> hostValidator, DeployLogger logger, PrepareParams params,
                                 Optional<ApplicationSet> currentActiveApplicationSet, Path tenantPath,
                                 Instant now, File serverDbSessionDir, ApplicationPackage applicationPackage,
                                 SessionZooKeeperClient sessionZooKeeperClient);  }
@Test(expected = InvalidApplicationException.class) public void require_that_application_validation_exception_is_not_caught() throws IOException { prepare(invalidTestApp); }
@Test public void require_that_application_validation_exception_is_ignored_if_forced() throws IOException { prepare(invalidTestApp, new PrepareParams.Builder() .applicationId(applicationId()) .ignoreValidationErrors(true) .timeoutBudget(TimeoutBudgetTest.day()) .build(), 1); }
@Test public void require_that_zookeeper_is_not_written_to_if_dryrun() throws IOException { long sessionId = 1; prepare(testApp, new PrepareParams.Builder() .applicationId(applicationId()) .dryRun(true) .timeoutBudget(TimeoutBudgetTest.day()) .build(), 1); Path sessionPath = sessionPath(sessionId); assertFalse(configCurator.exists(sessionPath.append(ConfigCurator.USERAPP_ZK_SUBPATH).append("services.xml").getAbsolute())); }
@Test public void require_that_filedistribution_is_ignored_on_dryrun() throws IOException { PrepareResult result = prepare(testApp, new PrepareParams.Builder() .applicationId(applicationId()) .dryRun(true) .build(), 1); Map<Version, FileRegistry> fileRegistries = result.getFileRegistries(); System.out.println(fileRegistries); assertEquals(1, fileRegistries.get(version321).export().size()); assertEquals("./", fileRegistries.get(version321).export().get(0).reference.value()); }
@Test public void require_that_application_is_prepared() throws Exception { prepare(testApp); assertTrue(configCurator.exists(sessionPath(1).append(ConfigCurator.USERAPP_ZK_SUBPATH).append("services.xml").getAbsolute())); }
@Test(expected = InvalidApplicationException.class) public void require_exception_for_overlapping_host() throws IOException { FilesApplicationPackage app = getApplicationPackage(testApp); HostRegistry<ApplicationId> hostValidator = new HostRegistry<>(); hostValidator.update(applicationId("foo"), Collections.singletonList("mytesthost")); preparer.prepare(hostValidator, new BaseDeployLogger(), new PrepareParams.Builder().applicationId(applicationId("default")).build(), Optional.empty(), tenantPath, Instant.now(), app.getAppDir(), app, createSessionZooKeeperClient()); }
@Test public void require_no_warning_for_overlapping_host_for_same_appid() throws IOException { final StringBuilder logged = new StringBuilder(); DeployLogger logger = (level, message) -> { if (level.equals(Level.WARNING) && message.contains("The host mytesthost is already in use")) logged.append("ok"); }; FilesApplicationPackage app = getApplicationPackage(testApp); HostRegistry<ApplicationId> hostValidator = new HostRegistry<>(); ApplicationId applicationId = applicationId(); hostValidator.update(applicationId, Collections.singletonList("mytesthost")); preparer.prepare(hostValidator, logger, new PrepareParams.Builder().applicationId(applicationId).build(), Optional.empty(), tenantPath, Instant.now(), app.getAppDir(), app, createSessionZooKeeperClient()); assertEquals(logged.toString(), ""); }
@Test public void require_that_application_id_is_written_in_prepare() throws IOException { PrepareParams params = new PrepareParams.Builder().applicationId(applicationId()).build(); int sessionId = 1; prepare(testApp, params); assertThat(createSessionZooKeeperClient(sessionId).readApplicationId().get(), is(applicationId())); }
@Test public void require_that_writing_wrong_application_id_fails() throws IOException { TenantName tenant = TenantName.from("tenant"); ApplicationId origId = new ApplicationId.Builder() .tenant(tenant) .applicationName("foo") .instanceName("quux") .build(); PrepareParams params = new PrepareParams.Builder().applicationId(origId).build(); expectedException.expect(RuntimeException.class); expectedException.expectMessage("Error preparing session"); prepare(testApp, params); }
@Test public void require_that_file_reference_of_application_package_is_written_to_zk() throws Exception { prepare(testApp); assertTrue(configCurator.exists(sessionPath(1).append(APPLICATION_PACKAGE_REFERENCE_PATH).getAbsolute())); }
@Test public void require_that_container_endpoints_are_written_and_used() throws Exception { var modelFactory = new TestModelFactory(version123); preparer = createPreparer(new ModelFactoryRegistry(List.of(modelFactory)), HostProvisionerProvider.empty()); var endpoints = "[\n" + " {\n" + " \"clusterId\": \"foo\",\n" + " \"names\": [\n" + " \"foo.app1.tenant1.global.vespa.example.com\",\n" + " \"rotation-042.vespa.global.routing\"\n" + " ]\n" + " },\n" + " {\n" + " \"clusterId\": \"bar\",\n" + " \"names\": [\n" + " \"bar.app1.tenant1.global.vespa.example.com\",\n" + " \"rotation-043.vespa.global.routing\"\n" + " ]\n" + " }\n" + "]"; var applicationId = applicationId("test"); var params = new PrepareParams.Builder().applicationId(applicationId) .containerEndpoints(endpoints) .build(); prepare(new File("src/test/resources/deploy/hosted-app"), params); var expected = List.of(new ContainerEndpoint("foo", List.of("foo.app1.tenant1.global.vespa.example.com", "rotation-042.vespa.global.routing")), new ContainerEndpoint("bar", List.of("bar.app1.tenant1.global.vespa.example.com", "rotation-043.vespa.global.routing"))); assertEquals(expected, readContainerEndpoints(applicationId)); var modelContext = modelFactory.getModelContext(); var containerEndpointsFromModel = modelContext.properties().endpoints(); assertEquals(Set.copyOf(expected), containerEndpointsFromModel); params = new PrepareParams.Builder().applicationId(applicationId).build(); prepare(new File("src/test/resources/deploy/hosted-app"), params); assertEquals(expected, readContainerEndpoints(applicationId)); params = new PrepareParams.Builder().applicationId(applicationId).containerEndpoints("[]").build(); prepare(new File("src/test/resources/deploy/hosted-app"), params); assertEquals(List.of(), readContainerEndpoints(applicationId)); }
@Test public void require_that_tlssecretkey_is_written() throws IOException { var tlskey = "vespa.tlskeys.tenant1--app1"; var applicationId = applicationId("test"); var params = new PrepareParams.Builder().applicationId(applicationId).tlsSecretsKeyName(tlskey).build(); secretStore.put("vespa.tlskeys.tenant1--app1-cert", X509CertificateUtils.toPem(certificate)); secretStore.put("vespa.tlskeys.tenant1--app1-key", KeyUtils.toPem(keyPair.getPrivate())); prepare(new File("src/test/resources/deploy/hosted-app"), params); Optional<EndpointCertificateSecrets> endpointCertificateSecrets = new EndpointCertificateMetadataStore(curator, tenantPath) .readEndpointCertificateMetadata(applicationId) .flatMap(p -> new EndpointCertificateRetriever(secretStore).readEndpointCertificateSecrets(p)); assertTrue(endpointCertificateSecrets.isPresent()); assertTrue(endpointCertificateSecrets.get().key().startsWith("-----BEGIN EC PRIVATE KEY")); assertTrue(endpointCertificateSecrets.get().certificate().startsWith("-----BEGIN CERTIFICATE")); }
@Test public void require_that_endpoint_certificate_metadata_is_written() throws IOException { var applicationId = applicationId("test"); var params = new PrepareParams.Builder().applicationId(applicationId).endpointCertificateMetadata("{\"keyName\": \"vespa.tlskeys.tenant1--app1-key\", \"certName\":\"vespa.tlskeys.tenant1--app1-cert\", \"version\": 7}").build(); secretStore.put("vespa.tlskeys.tenant1--app1-cert", 7, X509CertificateUtils.toPem(certificate)); secretStore.put("vespa.tlskeys.tenant1--app1-key", 7, KeyUtils.toPem(keyPair.getPrivate())); prepare(new File("src/test/resources/deploy/hosted-app"), params); Optional<EndpointCertificateSecrets> endpointCertificateSecrets = new EndpointCertificateMetadataStore(curator, tenantPath) .readEndpointCertificateMetadata(applicationId) .flatMap(p -> new EndpointCertificateRetriever(secretStore).readEndpointCertificateSecrets(p)); assertTrue(endpointCertificateSecrets.isPresent()); assertTrue(endpointCertificateSecrets.get().key().startsWith("-----BEGIN EC PRIVATE KEY")); assertTrue(endpointCertificateSecrets.get().certificate().startsWith("-----BEGIN CERTIFICATE")); }
@Test(expected = CertificateNotReadyException.class) public void require_that_tlssecretkey_is_missing_when_not_in_secretstore() throws IOException { var tlskey = "vespa.tlskeys.tenant1--app1"; var applicationId = applicationId("test"); var params = new PrepareParams.Builder().applicationId(applicationId).tlsSecretsKeyName(tlskey).build(); prepare(new File("src/test/resources/deploy/hosted-app"), params); }
@Test(expected = CertificateNotReadyException.class) public void require_that_tlssecretkey_is_missing_when_certificate_not_in_secretstore() throws IOException { var tlskey = "vespa.tlskeys.tenant1--app1"; var applicationId = applicationId("test"); var params = new PrepareParams.Builder().applicationId(applicationId).tlsSecretsKeyName(tlskey).build(); secretStore.put(tlskey+"-key", "KEY"); prepare(new File("src/test/resources/deploy/hosted-app"), params); }
@Test(expected = LoadBalancerServiceException.class) public void require_that_conflict_is_returned_when_creating_load_balancer_fails() throws IOException { preparer = createPreparer(HostProvisionerProvider.withProvisioner(new FailWithTransientExceptionProvisioner())); var params = new PrepareParams.Builder().applicationId(applicationId("test")).build(); prepare(new File("src/test/resources/deploy/hosted-app"), params); }