aboutsummaryrefslogtreecommitdiffstats
path: root/controller-server/src/test/java
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2023-10-12 09:46:05 +0200
committerGitHub <noreply@github.com>2023-10-12 09:46:05 +0200
commit0f14059f373b486987f82b1d161ff89b01f03204 (patch)
treead68405fffdc92e9af68739ebef593f5fd363f95 /controller-server/src/test/java
parente9562b0af56cf1163e41c99f30c2c836aa1720f1 (diff)
parent2f6bcf34688f229529e25e2f09d0552c3214318d (diff)
Merge pull request #28842 from vespa-engine/mpolden/cert-assignment
Refactor certificate assignment and migration
Diffstat (limited to 'controller-server/src/test/java')
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java30
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java14
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/EndpointTest.java18
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/certificate/EndpointCertificatesTest.java331
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/EndpointCertificateMaintainerTest.java77
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java8
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/RoutingPoliciesTest.java108
7 files changed, 314 insertions, 272 deletions
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 f456b6e12dc..eb86f23fbfb 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
@@ -73,7 +73,6 @@ import java.util.Set;
import java.util.TreeSet;
import java.util.function.Function;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
import static com.yahoo.config.provision.SystemName.main;
import static com.yahoo.vespa.hosted.controller.deployment.DeploymentContext.devAwsUsEast2a;
@@ -952,8 +951,6 @@ public class ControllerTest {
// Create app1
var context1 = tester.newDeploymentContext("tenant1", "app1", "default");
var prodZone = ZoneId.from("prod", "us-west-1");
- var stagingZone = ZoneId.from("staging", "us-east-3");
- var testZone = ZoneId.from("test", "us-east-1");
tester.controllerTester().zoneRegistry().exclusiveRoutingIn(ZoneApiMock.from(prodZone));
var applicationPackage = new ApplicationPackageBuilder().athenzIdentity(AthenzDomain.from("domain"), AthenzService.from("service"))
.region(prodZone.region())
@@ -962,16 +959,23 @@ public class ControllerTest {
context1.submit(applicationPackage).deploy();
var cert = certificate.apply(context1.instance());
assertTrue(cert.isPresent(), "Provisions certificate in " + Environment.prod);
- assertEquals(Stream.concat(Stream.of("vznqtz7a5ygwjkbhhj7ymxvlrekgt4l6g.vespa.oath.cloud",
- "app1.tenant1.global.vespa.oath.cloud",
- "*.app1.tenant1.global.vespa.oath.cloud"),
- Stream.of(prodZone, testZone, stagingZone)
- .flatMap(zone -> Stream.of("", "*.")
- .map(prefix -> prefix + "app1.tenant1." + zone.region().value() +
- (zone.environment() == Environment.prod ? "" : "." + zone.environment().value()) +
- ".vespa.oath.cloud")))
- .collect(Collectors.toUnmodifiableSet()),
- Set.copyOf(tester.controllerTester().serviceRegistry().endpointCertificateMock().dnsNamesOf(cert.get().rootRequestId())));
+ assertEquals(List.of("*.app1.tenant1.global.vespa.oath.cloud",
+ "*.app1.tenant1.us-east-1.test.vespa.oath.cloud",
+ "*.app1.tenant1.us-east-3.staging.vespa.oath.cloud",
+ "*.app1.tenant1.us-west-1.vespa.oath.cloud",
+ "*.f5549014.a.vespa.oath.cloud",
+ "*.f5549014.g.vespa.oath.cloud",
+ "*.f5549014.z.vespa.oath.cloud",
+ "app1.tenant1.global.vespa.oath.cloud",
+ "app1.tenant1.us-east-1.test.vespa.oath.cloud",
+ "app1.tenant1.us-east-3.staging.vespa.oath.cloud",
+ "app1.tenant1.us-west-1.vespa.oath.cloud",
+ "vznqtz7a5ygwjkbhhj7ymxvlrekgt4l6g.vespa.oath.cloud"),
+ tester.controllerTester().serviceRegistry().endpointCertificateMock()
+ .dnsNamesOf(cert.get().rootRequestId())
+ .stream()
+ .sorted()
+ .toList());
// Next deployment reuses certificate
context1.submit(applicationPackage).deploy();
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 40162186066..7bdecca11c0 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
@@ -3,9 +3,7 @@ package com.yahoo.vespa.hosted.controller;
import com.yahoo.component.Version;
import com.yahoo.config.provision.ApplicationId;
-import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.HostName;
-import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.TenantName;
import com.yahoo.config.provision.zone.RoutingMethod;
@@ -20,6 +18,7 @@ import com.yahoo.vespa.athenz.api.OAuthCredentials;
import com.yahoo.vespa.flags.FlagSource;
import com.yahoo.vespa.flags.InMemoryFlagSource;
import com.yahoo.vespa.flags.PermanentFlags;
+import com.yahoo.vespa.hosted.controller.api.identifiers.ControllerVersion;
import com.yahoo.vespa.hosted.controller.api.identifiers.Property;
import com.yahoo.vespa.hosted.controller.api.identifiers.PropertyId;
import com.yahoo.vespa.hosted.controller.api.integration.athenz.AthenzClientFactoryMock;
@@ -54,7 +53,6 @@ import com.yahoo.vespa.hosted.controller.security.Credentials;
import com.yahoo.vespa.hosted.controller.security.TenantSpec;
import com.yahoo.vespa.hosted.controller.tenant.AthenzTenant;
import com.yahoo.vespa.hosted.controller.tenant.Tenant;
-import com.yahoo.vespa.hosted.controller.api.identifiers.ControllerVersion;
import com.yahoo.vespa.hosted.controller.versions.VersionStatus;
import com.yahoo.vespa.hosted.rotation.config.RotationsConfig;
import com.yahoo.yolean.concurrent.Sleeper;
@@ -289,14 +287,6 @@ public final class ControllerTester {
return controller().clock().instant().atOffset(ZoneOffset.UTC).getHour();
}
- public ZoneId toZone(Environment environment) {
- return switch (environment) {
- case dev, test -> ZoneId.from(environment, RegionName.from("us-east-1"));
- case staging -> ZoneId.from(environment, RegionName.from("us-east-3"));
- default -> ZoneId.from(environment, RegionName.from("us-west-1"));
- };
- }
-
public AthenzDomain createDomainWithAdmin(String domainName, AthenzUser user) {
AthenzDomain domain = new AthenzDomain(domainName);
athenzDb.getOrCreateDomain(domain).admin(user);
@@ -405,7 +395,7 @@ public final class ControllerTester {
RotationsConfig.Builder builder = new RotationsConfig.Builder();
for (int i = 1; i <= availableRotations; i++) {
String id = Text.format("%02d", i);
- builder = builder.rotations("rotation-id-" + id, "rotation-fqdn-" + id);
+ builder.rotations("rotation-id-" + id, "rotation-fqdn-" + id);
}
return new RotationsConfig(builder);
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/EndpointTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/EndpointTest.java
index 23481cb324e..cec48dd1598 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/EndpointTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/EndpointTest.java
@@ -370,6 +370,24 @@ public class EndpointTest {
"dead2bad.deadbeef.a.vespa-app.cloud",
Endpoint.of(TenantAndApplicationId.from(instance1)).targetApplication(EndpointId.of("foo"), deployment)
.generatedFrom(ge2)
+ .routingMethod(RoutingMethod.exclusive).on(Port.tls()).in(SystemName.Public),
+ // Wildcard endpoint for zone
+ "*.deadbeef.z.vespa-app.cloud",
+ Endpoint.of(instance1)
+ .wildcardGenerated(ge1.applicationPart(), Endpoint.Scope.zone)
+ .certificateName()
+ .routingMethod(RoutingMethod.exclusive).on(Port.tls()).in(SystemName.Public),
+ // Wildcard endpoint for global
+ "*.deadbeef.g.vespa-app.cloud",
+ Endpoint.of(instance1)
+ .wildcardGenerated(ge1.applicationPart(), Endpoint.Scope.global)
+ .certificateName()
+ .routingMethod(RoutingMethod.exclusive).on(Port.tls()).in(SystemName.Public),
+ // Wildcard endpoint for application
+ "*.deadbeef.a.vespa-app.cloud",
+ Endpoint.of(instance1)
+ .wildcardGenerated(ge1.applicationPart(), Endpoint.Scope.application)
+ .certificateName()
.routingMethod(RoutingMethod.exclusive).on(Port.tls()).in(SystemName.Public)
);
tests.forEach((expected, endpoint) -> assertEquals(expected, endpoint.dnsName()));
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/certificate/EndpointCertificatesTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/certificate/EndpointCertificatesTest.java
index 78748cd2cd8..7faaee95abb 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/certificate/EndpointCertificatesTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/certificate/EndpointCertificatesTest.java
@@ -17,18 +17,21 @@ import com.yahoo.security.SignatureAlgorithm;
import com.yahoo.security.X509CertificateBuilder;
import com.yahoo.security.X509CertificateUtils;
import com.yahoo.test.ManualClock;
+import com.yahoo.transaction.Mutex;
import com.yahoo.vespa.flags.Flags;
import com.yahoo.vespa.hosted.controller.ControllerTester;
-import com.yahoo.vespa.hosted.controller.Instance;
+import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
import com.yahoo.vespa.hosted.controller.api.integration.certificates.EndpointCertificate;
import com.yahoo.vespa.hosted.controller.api.integration.certificates.EndpointCertificateProviderMock;
import com.yahoo.vespa.hosted.controller.api.integration.certificates.EndpointCertificateValidatorImpl;
+import com.yahoo.vespa.hosted.controller.api.integration.certificates.EndpointCertificateValidatorMock;
import com.yahoo.vespa.hosted.controller.application.TenantAndApplicationId;
import com.yahoo.vespa.hosted.controller.application.pkg.ApplicationPackage;
import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder;
import com.yahoo.vespa.hosted.controller.integration.SecretStoreMock;
import com.yahoo.vespa.hosted.controller.integration.ZoneApiMock;
import com.yahoo.vespa.hosted.controller.persistence.CuratorDb;
+import com.yahoo.vespa.hosted.controller.routing.EndpointConfig;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -58,12 +61,13 @@ public class EndpointCertificatesTest {
private final ControllerTester tester = new ControllerTester();
private final SecretStoreMock secretStore = new SecretStoreMock();
- private final CuratorDb mockCuratorDb = tester.curator();
+ private final CuratorDb curator = tester.curator();
private final ManualClock clock = tester.clock();
private final EndpointCertificateProviderMock endpointCertificateProviderMock = new EndpointCertificateProviderMock();
private final EndpointCertificateValidatorImpl endpointCertificateValidator = new EndpointCertificateValidatorImpl(secretStore, clock);
private final EndpointCertificates endpointCertificates = new EndpointCertificates(tester.controller(), endpointCertificateProviderMock, endpointCertificateValidator);
private final KeyPair testKeyPair = KeyUtils.generateKeypair(KeyAlgorithm.EC, 192);
+ private final Mutex lock = () -> {};
private X509Certificate testCertificate;
private X509Certificate testCertificate2;
@@ -74,6 +78,9 @@ public class EndpointCertificatesTest {
"*.default.default.global.vespa.oath.cloud",
"default.default.aws-us-east-1a.vespa.oath.cloud",
"*.default.default.aws-us-east-1a.vespa.oath.cloud",
+ "*.f5549014.z.vespa.oath.cloud",
+ "*.f5549014.g.vespa.oath.cloud",
+ "*.f5549014.a.vespa.oath.cloud",
"default.default.us-east-1.test.vespa.oath.cloud",
"*.default.default.us-east-1.test.vespa.oath.cloud",
"default.default.us-east-3.staging.vespa.oath.cloud",
@@ -93,7 +100,10 @@ public class EndpointCertificatesTest {
private static final List<String> expectedDevSans = List.of(
"vt2ktgkqme5zlnp4tj4ttyor7fj3v7q5o.vespa.oath.cloud",
"default.default.us-east-1.dev.vespa.oath.cloud",
- "*.default.default.us-east-1.dev.vespa.oath.cloud"
+ "*.default.default.us-east-1.dev.vespa.oath.cloud",
+ "*.f5549014.z.vespa.oath.cloud",
+ "*.f5549014.g.vespa.oath.cloud",
+ "*.f5549014.a.vespa.oath.cloud"
);
private X509Certificate makeTestCert(List<String> sans) {
@@ -108,7 +118,7 @@ public class EndpointCertificatesTest {
return x509CertificateBuilder.build();
}
- private final Instance instance = new Instance(ApplicationId.defaultId());
+ private final ApplicationId instance = ApplicationId.defaultId();
private final String testKeyName = "testKeyName";
private final String testCertName = "testCertName";
private ZoneId prodZone;
@@ -125,22 +135,20 @@ public class EndpointCertificatesTest {
@Test
void provisions_new_certificate_in_dev() {
ZoneId testZone = tester.zoneRegistry().zones().all().routingMethod(RoutingMethod.exclusive).in(Environment.dev).zones().stream().findFirst().orElseThrow().getId();
- Optional<EndpointCertificate> cert = endpointCertificates.get(instance, testZone, DeploymentSpec.empty);
- assertTrue(cert.isPresent());
- assertTrue(cert.get().keyName().matches("vespa.tls.default.default.*-key"));
- assertTrue(cert.get().certName().matches("vespa.tls.default.default.*-cert"));
- assertEquals(0, cert.get().version());
- assertEquals(expectedDevSans, cert.get().requestedDnsSans());
+ EndpointCertificate cert = endpointCertificates.get(new DeploymentId(instance, testZone), DeploymentSpec.empty, lock);
+ assertTrue(cert.keyName().matches("vespa.tls.default.default.*-key"));
+ assertTrue(cert.certName().matches("vespa.tls.default.default.*-cert"));
+ assertEquals(0, cert.version());
+ assertEquals(expectedDevSans, cert.requestedDnsSans());
}
@Test
void provisions_new_certificate_in_prod() {
- Optional<EndpointCertificate> cert = endpointCertificates.get(instance, prodZone, DeploymentSpec.empty);
- assertTrue(cert.isPresent());
- assertTrue(cert.get().keyName().matches("vespa.tls.default.default.*-key"));
- assertTrue(cert.get().certName().matches("vespa.tls.default.default.*-cert"));
- assertEquals(0, cert.get().version());
- assertEquals(expectedSans, cert.get().requestedDnsSans());
+ EndpointCertificate cert = endpointCertificates.get(new DeploymentId(instance, prodZone), DeploymentSpec.empty, lock);
+ assertTrue(cert.keyName().matches("vespa.tls.default.default.*-key"));
+ assertTrue(cert.certName().matches("vespa.tls.default.default.*-cert"));
+ assertEquals(0, cert.version());
+ assertEquals(expectedSans, cert.requestedDnsSans());
}
private ControllerTester publicTester() {
@@ -160,66 +168,68 @@ public class EndpointCertificatesTest {
"*.default.default.g.vespa-app.cloud",
"default.default.aws-us-east-1a.z.vespa-app.cloud",
"*.default.default.aws-us-east-1a.z.vespa-app.cloud",
+ "*.f5549014.z.vespa-app.cloud",
+ "*.f5549014.g.vespa-app.cloud",
+ "*.f5549014.a.vespa-app.cloud",
"default.default.us-east-1.test.z.vespa-app.cloud",
"*.default.default.us-east-1.test.z.vespa-app.cloud",
"default.default.us-east-3.staging.z.vespa-app.cloud",
"*.default.default.us-east-3.staging.z.vespa-app.cloud"
);
- Optional<EndpointCertificate> cert = endpointCertificates.get(instance, prodZone, DeploymentSpec.empty);
- assertTrue(cert.isPresent());
- assertTrue(cert.get().keyName().matches("vespa.tls.default.default.*-key"));
- assertTrue(cert.get().certName().matches("vespa.tls.default.default.*-cert"));
- assertEquals(0, cert.get().version());
- assertEquals(expectedSans, cert.get().requestedDnsSans());
+ EndpointCertificate cert = endpointCertificates.get(new DeploymentId(instance, prodZone), DeploymentSpec.empty, lock);
+ assertTrue(cert.keyName().matches("vespa.tls.default.default.*-key"));
+ assertTrue(cert.certName().matches("vespa.tls.default.default.*-cert"));
+ assertEquals(0, cert.version());
+ assertEquals(expectedSans, cert.requestedDnsSans());
}
@Test
void reuses_stored_certificate() {
- mockCuratorDb.writeAssignedCertificate(assignedCertificate(instance.id(), new EndpointCertificate(testKeyName, testCertName, 7, 0, "request_id", Optional.of("leaf-request-uuid"),
- List.of("vt2ktgkqme5zlnp4tj4ttyor7fj3v7q5o.vespa.oath.cloud",
+ curator.writeAssignedCertificate(assignedCertificate(instance, new EndpointCertificate(testKeyName, testCertName, 7, 0, "request_id", Optional.of("leaf-request-uuid"),
+ List.of("vt2ktgkqme5zlnp4tj4ttyor7fj3v7q5o.vespa.oath.cloud",
"default.default.global.vespa.oath.cloud",
"*.default.default.global.vespa.oath.cloud",
"default.default.aws-us-east-1a.vespa.oath.cloud",
- "*.default.default.aws-us-east-1a.vespa.oath.cloud"),
- "", Optional.empty(), Optional.empty(), Optional.empty())));
+ "*.default.default.aws-us-east-1a.vespa.oath.cloud",
+ "*.f5549014.z.vespa.oath.cloud",
+ "*.f5549014.g.vespa.oath.cloud",
+ "*.f5549014.a.vespa.oath.cloud"),
+ "", Optional.empty(), Optional.empty(), Optional.empty())));
secretStore.setSecret(testKeyName, KeyUtils.toPem(testKeyPair.getPrivate()), 7);
secretStore.setSecret(testCertName, X509CertificateUtils.toPem(testCertificate) + X509CertificateUtils.toPem(testCertificate), 7);
- Optional<EndpointCertificate> cert = endpointCertificates.get(instance, prodZone, DeploymentSpec.empty);
- assertTrue(cert.isPresent());
- assertEquals(testKeyName, cert.get().keyName());
- assertEquals(testCertName, cert.get().certName());
- assertEquals(7, cert.get().version());
+ EndpointCertificate cert = endpointCertificates.get(new DeploymentId(instance, prodZone), DeploymentSpec.empty, lock);
+ assertEquals(testKeyName, cert.keyName());
+ assertEquals(testCertName, cert.certName());
+ assertEquals(7, cert.version());
}
@Test
void reprovisions_certificate_when_necessary() {
- mockCuratorDb.writeAssignedCertificate(assignedCertificate(instance.id(), new EndpointCertificate(testKeyName, testCertName, -1, 0, "root-request-uuid", Optional.of("leaf-request-uuid"), List.of(), "issuer", Optional.empty(), Optional.empty(), Optional.empty())));
+ curator.writeAssignedCertificate(assignedCertificate(instance, new EndpointCertificate(testKeyName, testCertName, -1, 0, "root-request-uuid", Optional.of("leaf-request-uuid"), List.of(), "issuer", Optional.empty(), Optional.empty(), Optional.empty())));
secretStore.setSecret("vespa.tls.default.default.default-key", KeyUtils.toPem(testKeyPair.getPrivate()), 0);
secretStore.setSecret("vespa.tls.default.default.default-cert", X509CertificateUtils.toPem(testCertificate) + X509CertificateUtils.toPem(testCertificate), 0);
- Optional<EndpointCertificate> cert = endpointCertificates.get(instance, prodZone, DeploymentSpec.empty);
- assertTrue(cert.isPresent());
- assertEquals(0, cert.get().version());
- assertEquals(cert, mockCuratorDb.readAssignedCertificate(instance.id()).map(AssignedCertificate::certificate));
+ EndpointCertificate cert = endpointCertificates.get(new DeploymentId(instance, prodZone), DeploymentSpec.empty, lock);
+ assertEquals(0, cert.version());
+ assertEquals(cert, curator.readAssignedCertificate(instance).map(AssignedCertificate::certificate).get());
}
@Test
void reprovisions_certificate_with_added_sans_when_deploying_to_new_zone() {
ZoneId testZone = ZoneId.from("prod.ap-northeast-1");
- mockCuratorDb.writeAssignedCertificate(assignedCertificate(instance.id(), new EndpointCertificate(testKeyName, testCertName, -1, 0, "original-request-uuid", Optional.of("leaf-request-uuid"), expectedSans, "mockCa", Optional.empty(), Optional.empty(), Optional.empty())));
+ curator.writeAssignedCertificate(assignedCertificate(instance, new EndpointCertificate(testKeyName, testCertName, -1, 0, "original-request-uuid", Optional.of("leaf-request-uuid"), expectedSans, "mockCa", Optional.empty(), Optional.empty(), Optional.empty())));
secretStore.setSecret("vespa.tls.default.default.default-key", KeyUtils.toPem(testKeyPair.getPrivate()), -1);
secretStore.setSecret("vespa.tls.default.default.default-cert", X509CertificateUtils.toPem(testCertificate) + X509CertificateUtils.toPem(testCertificate), -1);
secretStore.setSecret("vespa.tls.default.default.default-key", KeyUtils.toPem(testKeyPair.getPrivate()), 0);
secretStore.setSecret("vespa.tls.default.default.default-cert", X509CertificateUtils.toPem(testCertificate2) + X509CertificateUtils.toPem(testCertificate2), 0);
- Optional<EndpointCertificate> cert = endpointCertificates.get(instance, testZone, DeploymentSpec.empty);
- assertTrue(cert.isPresent());
- assertEquals(0, cert.get().version());
- assertEquals(cert, mockCuratorDb.readAssignedCertificate(instance.id()).map(AssignedCertificate::certificate));
- assertEquals("original-request-uuid", cert.get().rootRequestId());
- assertNotEquals(Optional.of("leaf-request-uuid"), cert.get().leafRequestId());
- assertEquals(Set.copyOf(expectedCombinedSans), Set.copyOf(cert.get().requestedDnsSans()));
+ EndpointCertificate cert = endpointCertificates.get(new DeploymentId(instance, testZone), DeploymentSpec.empty, lock);
+ assertEquals(0, cert.version());
+ assertEquals(cert, curator.readAssignedCertificate(instance).map(AssignedCertificate::certificate).get());
+ assertEquals("original-request-uuid", cert.rootRequestId());
+ assertNotEquals(Optional.of("leaf-request-uuid"), cert.leafRequestId());
+ assertEquals(Set.copyOf(expectedCombinedSans), Set.copyOf(cert.requestedDnsSans()));
}
@Test
@@ -238,17 +248,16 @@ public class EndpointCertificatesTest {
);
ZoneId testZone = tester.zoneRegistry().zones().all().in(Environment.staging).zones().stream().findFirst().orElseThrow().getId();
- Optional<EndpointCertificate> cert = endpointCertificates.get(instance, testZone, deploymentSpec);
- assertTrue(cert.isPresent());
- assertTrue(cert.get().keyName().matches("vespa.tls.default.default.*-key"));
- assertTrue(cert.get().certName().matches("vespa.tls.default.default.*-cert"));
- assertEquals(0, cert.get().version());
- assertEquals(Set.copyOf(expectedCombinedSans), Set.copyOf(cert.get().requestedDnsSans()));
+ EndpointCertificate cert = endpointCertificates.get(new DeploymentId(instance, testZone), deploymentSpec, lock);
+ assertTrue(cert.keyName().matches("vespa.tls.default.default.*-key"));
+ assertTrue(cert.certName().matches("vespa.tls.default.default.*-cert"));
+ assertEquals(0, cert.version());
+ assertEquals(Set.copyOf(expectedCombinedSans), Set.copyOf(cert.requestedDnsSans()));
}
@Test
void includes_application_endpoint_when_declared() {
- Instance instance = new Instance(ApplicationId.from("t1", "a1", "default"));
+ ApplicationId instance = ApplicationId.from("t1", "a1", "default");
ZoneId zone1 = ZoneId.from(Environment.prod, RegionName.from("aws-us-east-1c"));
ZoneId zone2 = ZoneId.from(Environment.prod, RegionName.from("aws-us-west-2a"));
ControllerTester tester = publicTester();
@@ -280,28 +289,25 @@ public class EndpointCertificatesTest {
"a1.t1.us-east-1.test.z.vespa-app.cloud",
"*.a1.t1.us-east-1.test.z.vespa-app.cloud",
"a1.t1.us-east-3.staging.z.vespa-app.cloud",
- "*.a1.t1.us-east-3.staging.z.vespa-app.cloud"
+ "*.a1.t1.us-east-3.staging.z.vespa-app.cloud",
+ "*.f5549014.z.vespa-app.cloud",
+ "*.f5549014.g.vespa-app.cloud",
+ "*.f5549014.a.vespa-app.cloud"
).sorted().toList();
- Optional<EndpointCertificate> cert = endpointCertificates.get(instance, zone1, applicationPackage.deploymentSpec());
- assertTrue(cert.isPresent());
- assertTrue(cert.get().keyName().matches("vespa.tls.t1.a1.*-key"));
- assertTrue(cert.get().certName().matches("vespa.tls.t1.a1.*-cert"));
- assertEquals(0, cert.get().version());
- assertEquals(expectedSans, cert.get().requestedDnsSans().stream().sorted().toList());
+ EndpointCertificate cert = endpointCertificates.get(new DeploymentId(instance, zone1), applicationPackage.deploymentSpec(), lock);
+ assertTrue(cert.keyName().matches("vespa.tls.t1.a1.*-key"));
+ assertTrue(cert.certName().matches("vespa.tls.t1.a1.*-cert"));
+ assertEquals(0, cert.version());
+ assertEquals(expectedSans, cert.requestedDnsSans().stream().sorted().toList());
}
@Test
public void assign_certificate_from_pool() {
- // Initial certificate is requested directly from provider
- Optional<EndpointCertificate> certFromProvider = endpointCertificates.get(instance, prodZone, DeploymentSpec.empty);
- assertTrue(certFromProvider.isPresent());
- assertFalse(certFromProvider.get().generatedId().isPresent());
-
- // Pooled certificates become available
tester.flagSource().withBooleanFlag(Flags.RANDOMIZED_ENDPOINT_NAMES.id(), true);
+ tester.flagSource().withBooleanFlag(Flags.LEGACY_ENDPOINTS.id(), false);
try {
- addCertificateToPool("pool-cert-1", UnassignedCertificate.State.requested);
- endpointCertificates.get(instance, prodZone, DeploymentSpec.empty);
+ addCertificateToPool("bad0f00d", UnassignedCertificate.State.requested, tester);
+ endpointCertificates.get(new DeploymentId(instance, prodZone), DeploymentSpec.empty, lock);
fail("Expected exception as certificate is not ready");
} catch (IllegalArgumentException ignored) {}
@@ -311,76 +317,169 @@ public class EndpointCertificatesTest {
// Certificate is assigned from pool instead. The previously assigned certificate will eventually be cleaned up
// by EndpointCertificateMaintainer
{ // prod
- String certId = "pool-cert-1";
- addCertificateToPool(certId, UnassignedCertificate.State.ready);
- Optional<EndpointCertificate> cert = endpointCertificates.get(instance, prodZone, DeploymentSpec.empty);
- assertEquals(certId, cert.get().generatedId().get());
- assertEquals(certId, tester.curator().readAssignedCertificate(TenantAndApplicationId.from(instance.id()), Optional.empty()).get().certificate().generatedId().get(), "Certificate is assigned at application-level");
+ String certId = "bad0f00d";
+ addCertificateToPool(certId, UnassignedCertificate.State.ready, tester);
+ EndpointCertificate cert = endpointCertificates.get(new DeploymentId(instance, prodZone), DeploymentSpec.empty, lock);
+ assertEquals(certId, cert.generatedId().get());
+ assertEquals(certId, tester.curator().readAssignedCertificate(TenantAndApplicationId.from(instance), Optional.empty()).get().certificate().generatedId().get(), "Certificate is assigned at application-level");
assertTrue(tester.controller().curator().readUnassignedCertificate(certId).isEmpty(), "Certificate is removed from pool");
- assertEquals(clock.instant().getEpochSecond(), cert.get().lastRequested());
+ assertEquals(clock.instant().getEpochSecond(), cert.lastRequested());
}
{ // dev
- String certId = "pool-cert-2";
- addCertificateToPool(certId, UnassignedCertificate.State.ready);
+ String certId = "f00d0bad";
+ addCertificateToPool(certId, UnassignedCertificate.State.ready, tester);
ZoneId devZone = tester.zoneRegistry().zones().all().routingMethod(RoutingMethod.exclusive).in(Environment.dev).zones().stream().findFirst().orElseThrow().getId();
- Optional<EndpointCertificate> cert = endpointCertificates.get(instance, devZone, DeploymentSpec.empty);
- assertEquals(certId, cert.get().generatedId().get());
- assertEquals(certId, tester.curator().readAssignedCertificate(instance.id()).get().certificate().generatedId().get(), "Certificate is assigned at instance-level");
+ EndpointCertificate cert = endpointCertificates.get(new DeploymentId(instance, devZone), DeploymentSpec.empty, lock);
+ assertEquals(certId, cert.generatedId().get());
+ assertEquals(certId, tester.curator().readAssignedCertificate(instance).get().certificate().generatedId().get(), "Certificate is assigned at instance-level");
assertTrue(tester.controller().curator().readUnassignedCertificate(certId).isEmpty(), "Certificate is removed from pool");
- assertEquals(clock.instant().getEpochSecond(), cert.get().lastRequested());
+ assertEquals(clock.instant().getEpochSecond(), cert.lastRequested());
}
}
@Test
- void reuse_per_instance_certificate_if_assigned_random_id() {
- // Initial certificate is requested directly from provider
- Optional<EndpointCertificate> certFromProvider = endpointCertificates.get(instance, prodZone, DeploymentSpec.empty);
- assertTrue(certFromProvider.isPresent());
- assertFalse(certFromProvider.get().generatedId().isPresent());
-
- // Simulate endpoint certificate maintainer to assign random id
- TenantAndApplicationId tenantAndApplicationId = TenantAndApplicationId.from(instance.id());
- Optional<InstanceName> instanceName = Optional.of(instance.name());
- Optional<AssignedCertificate> assignedCertificate = tester.controller().curator().readAssignedCertificate(tenantAndApplicationId, instanceName);
- assertTrue(assignedCertificate.isPresent());
- String assignedRandomId = "randomid";
- AssignedCertificate updated = assignedCertificate.get().with(assignedCertificate.get().certificate().withGeneratedId(assignedRandomId));
- tester.controller().curator().writeAssignedCertificate(updated);
-
- // Pooled certificates become available
+ public void certificate_migration() {
+ // An application is initially deployed with legacy config
+ ZoneId zone1 = ZoneId.from(Environment.prod, RegionName.from("aws-us-east-1c"));
+ ApplicationPackage applicationPackage = new ApplicationPackageBuilder().region(zone1.region())
+ .build();
+ ControllerTester tester = publicTester();
+ EndpointCertificates endpointCertificates = new EndpointCertificates(tester.controller(), endpointCertificateProviderMock, new EndpointCertificateValidatorMock());
+ ApplicationId instance = ApplicationId.from("t1", "a1", "default");
+ DeploymentId deployment0 = new DeploymentId(instance, zone1);
+ final EndpointCertificate certificate = endpointCertificates.get(deployment0, applicationPackage.deploymentSpec(), lock);
+ final String generatedId = certificate.generatedId().get();
+ assertEquals(List.of("vlfms2wpoa4nyrka2s5lktucypjtxkqhv.internal.vespa-app.cloud",
+ "a1.t1.g.vespa-app.cloud",
+ "*.a1.t1.g.vespa-app.cloud",
+ "a1.t1.aws-us-east-1c.z.vespa-app.cloud",
+ "*.a1.t1.aws-us-east-1c.z.vespa-app.cloud",
+ "*.f5549014.z.vespa-app.cloud",
+ "*.f5549014.g.vespa-app.cloud",
+ "*.f5549014.a.vespa-app.cloud",
+ "a1.t1.us-east-1.test.z.vespa-app.cloud",
+ "*.a1.t1.us-east-1.test.z.vespa-app.cloud",
+ "a1.t1.us-east-3.staging.z.vespa-app.cloud",
+ "*.a1.t1.us-east-3.staging.z.vespa-app.cloud"),
+ certificate.requestedDnsSans());
+ Optional<AssignedCertificate> assignedCertificate = tester.curator().readAssignedCertificate(deployment0.applicationId());
+ assertTrue(assignedCertificate.isPresent(), "Certificate is assigned at instance level");
+ assertTrue(assignedCertificate.get().certificate().generatedId().isPresent(), "Certificate contains generated ID");
+
+ // Re-requesting certificate does not make any changes, except last requested time
+ tester.clock().advance(Duration.ofHours(1));
+ assertEquals(certificate.withLastRequested(tester.clock().instant().getEpochSecond()),
+ endpointCertificates.get(deployment0, applicationPackage.deploymentSpec(), lock),
+ "Next request returns same certificate and updates last requested time");
+
+ // An additional instance is added to deployment spec
+ applicationPackage = new ApplicationPackageBuilder().instances("default,beta")
+ .region(zone1.region())
+ .build();
+ DeploymentId deployment1 = new DeploymentId(ApplicationId.from("t1", "a1", "beta"), zone1);
+ EndpointCertificate betaCert = endpointCertificates.get(deployment1, applicationPackage.deploymentSpec(), lock);
+ assertEquals(List.of("v43ctkgqim52zsbwefrg6ixkuwidvsumy.internal.vespa-app.cloud",
+ "beta.a1.t1.g.vespa-app.cloud",
+ "*.beta.a1.t1.g.vespa-app.cloud",
+ "beta.a1.t1.aws-us-east-1c.z.vespa-app.cloud",
+ "*.beta.a1.t1.aws-us-east-1c.z.vespa-app.cloud",
+ "*.f5549014.z.vespa-app.cloud",
+ "*.f5549014.g.vespa-app.cloud",
+ "*.f5549014.a.vespa-app.cloud",
+ "beta.a1.t1.us-east-1.test.z.vespa-app.cloud",
+ "*.beta.a1.t1.us-east-1.test.z.vespa-app.cloud",
+ "beta.a1.t1.us-east-3.staging.z.vespa-app.cloud",
+ "*.beta.a1.t1.us-east-3.staging.z.vespa-app.cloud"),
+ betaCert.requestedDnsSans());
+ assertEquals(generatedId, betaCert.generatedId().get(), "Certificate inherits generated ID of existing instance");
+
+ // A dev instance is deployed
+ DeploymentId devDeployment0 = new DeploymentId(ApplicationId.from("t1", "a1", "dev"),
+ ZoneId.from("dev", "us-east-1"));
+ EndpointCertificate devCert0 = endpointCertificates.get(devDeployment0, applicationPackage.deploymentSpec(), lock);
+ assertNotEquals(generatedId, devCert0.generatedId().get(), "Dev deployments gets a new generated ID");
+ assertEquals(List.of("vld3y4mggzpd5wmm5jmldzcbyetjoqtzq.internal.vespa-app.cloud",
+ "dev.a1.t1.us-east-1.dev.z.vespa-app.cloud",
+ "*.dev.a1.t1.us-east-1.dev.z.vespa-app.cloud",
+ "*.a89ff7c6.z.vespa-app.cloud",
+ "*.a89ff7c6.g.vespa-app.cloud",
+ "*.a89ff7c6.a.vespa-app.cloud"),
+ devCert0.requestedDnsSans());
+
+ // Application switches to combined config
tester.flagSource().withBooleanFlag(Flags.RANDOMIZED_ENDPOINT_NAMES.id(), true);
-
- // Create 1 cert in pool
- String certId = "pool-cert-1";
- addCertificateToPool(certId, UnassignedCertificate.State.ready);
-
- // Request cert for app
- Optional<EndpointCertificate> cert = endpointCertificates.get(instance, prodZone, DeploymentSpec.empty);
- assertEquals(assignedRandomId, cert.get().generatedId().get());
-
- // Pooled cert remains unassigned
- List<String> unassignedCertificateIds = tester.curator().readUnassignedCertificates().stream()
- .map(UnassignedCertificate::certificate)
- .map(EndpointCertificate::generatedId)
- .map(Optional::get)
- .toList();
- assertEquals(List.of(certId), unassignedCertificateIds);
+ tester.flagSource().withBooleanFlag(Flags.LEGACY_ENDPOINTS.id(), true);
+ tester.clock().advance(Duration.ofHours(1));
+ assertEquals(certificate.withLastRequested(tester.clock().instant().getEpochSecond()),
+ endpointCertificates.get(deployment0, applicationPackage.deploymentSpec(), lock),
+ "No change to certificate: Existing certificate is compatible with " +
+ EndpointConfig.combined + " config");
+ assertTrue(tester.curator().readAssignedCertificate(deployment0.applicationId()).isPresent(), "Certificate is assigned at instance level");
+ assertFalse(tester.curator().readAssignedCertificate(TenantAndApplicationId.from(deployment0.applicationId()), Optional.empty()).isPresent(),
+ "Certificate is not assigned at application level");
+
+ // Application switches to generated config
+ tester.flagSource().withBooleanFlag(Flags.LEGACY_ENDPOINTS.id(), false);
+ tester.clock().advance(Duration.ofHours(1));
+ assertEquals(certificate.withLastRequested(tester.clock().instant().getEpochSecond()),
+ endpointCertificates.get(deployment0, applicationPackage.deploymentSpec(), lock),
+ "No change to certificate: Existing certificate is compatible with " +
+ EndpointConfig.generated + " config");
+ assertFalse(tester.curator().readAssignedCertificate(deployment0.applicationId()).isPresent(), "Certificate is no longer assigned at instance level");
+ assertTrue(tester.curator().readAssignedCertificate(TenantAndApplicationId.from(deployment0.applicationId()), Optional.empty()).isPresent(),
+ "Certificate is assigned at application level");
+
+ // Both instances still use the same certificate
+ assertEquals(endpointCertificates.get(deployment0, applicationPackage.deploymentSpec(), lock),
+ endpointCertificates.get(deployment1, applicationPackage.deploymentSpec(), lock));
+
+ // Another dev instance is deployed, and is assigned certificate from pool
+ String poolCertId0 = "badf00d0";
+ addCertificateToPool(poolCertId0, UnassignedCertificate.State.ready, tester);
+ EndpointCertificate devCert1 = endpointCertificates.get(new DeploymentId(ApplicationId.from("t1", "a1", "dev2"),
+ ZoneId.from("dev", "us-east-1")),
+ applicationPackage.deploymentSpec(), lock);
+ assertEquals(poolCertId0, devCert1.generatedId().get());
+
+ // Another application is deployed, and is assigned certificate from pool
+ String poolCertId1 = "badf00d1";
+ addCertificateToPool(poolCertId1, UnassignedCertificate.State.ready, tester);
+ EndpointCertificate prodCertificate = endpointCertificates.get(new DeploymentId(ApplicationId.from("t1", "a2", "default"),
+ ZoneId.from("prod", "us-east-1")),
+ applicationPackage.deploymentSpec(), lock);
+ assertEquals(poolCertId1, prodCertificate.generatedId().get());
+
+ // Application switches back to legacy config
+ tester.flagSource().withBooleanFlag(Flags.RANDOMIZED_ENDPOINT_NAMES.id(), false);
+ tester.flagSource().withBooleanFlag(Flags.LEGACY_ENDPOINTS.id(), true);
+ EndpointCertificate reissuedCertificate = endpointCertificates.get(deployment0, applicationPackage.deploymentSpec(), lock);
+ assertEquals(certificate.requestedDnsSans(), reissuedCertificate.requestedDnsSans());
+ assertTrue(tester.curator().readAssignedCertificate(deployment0.applicationId()).isPresent(), "Certificate is assigned at instance level again");
+ assertTrue(tester.curator().readAssignedCertificate(TenantAndApplicationId.from(deployment0.applicationId()), Optional.empty()).isPresent(),
+ "Certificate is still assigned at application level"); // Not removed because the assumption is that the application will eventually migrate back
}
- private void addCertificateToPool(String id, UnassignedCertificate.State state) {
- EndpointCertificate cert = new EndpointCertificate(testKeyName, testCertName, 1, 0,
+ private void addCertificateToPool(String id, UnassignedCertificate.State state, ControllerTester tester) {
+ EndpointCertificate cert = new EndpointCertificate(testKeyName,
+ testCertName,
+ 1,
+ 0,
"request-id",
Optional.of("leaf-request-uuid"),
- List.of("name1", "name2"),
- "", Optional.empty(),
- Optional.empty(), Optional.of(id));
+ List.of("*." + id + ".z.vespa.oath.cloud",
+ "*." + id + ".g.vespa.oath.cloud",
+ "*." + id + ".a.vespa.oath.cloud"),
+ "",
+ Optional.empty(),
+ Optional.empty(),
+ Optional.of(id));
UnassignedCertificate pooledCert = new UnassignedCertificate(cert, state);
tester.controller().curator().writeUnassignedCertificate(pooledCert);
}
private static AssignedCertificate assignedCertificate(ApplicationId instance, EndpointCertificate certificate) {
- return new AssignedCertificate(TenantAndApplicationId.from(instance), Optional.of(instance.instance()), certificate);
+ return new AssignedCertificate(TenantAndApplicationId.from(instance), Optional.of(instance.instance()), certificate, false);
}
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/EndpointCertificateMaintainerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/EndpointCertificateMaintainerTest.java
index bb36aa01b0f..f551a99829e 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/EndpointCertificateMaintainerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/EndpointCertificateMaintainerTest.java
@@ -45,7 +45,6 @@ import static com.yahoo.vespa.hosted.controller.deployment.DeploymentContext.pro
import static com.yahoo.vespa.hosted.controller.deployment.DeploymentContext.stagingTest;
import static com.yahoo.vespa.hosted.controller.deployment.DeploymentContext.systemTest;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -120,6 +119,7 @@ public class EndpointCertificateMaintainerTest {
var applicationPackage = new ApplicationPackageBuilder()
.region("us-west-1")
+ .container("default")
.build();
DeploymentContext deploymentContext = deploymentTester.newDeploymentContext("tenant", "application", "default");
@@ -191,68 +191,6 @@ public class EndpointCertificateMaintainerTest {
}
@Test
- void production_deployment_certificates_are_assigned_random_id() {
- var app = ApplicationId.from("tenant", "app", "default");
- DeploymentTester deploymentTester = new DeploymentTester(tester);
- deployToAssignCert(deploymentTester, app, List.of(systemTest, stagingTest, productionUsWest1), Optional.empty());
- assertEquals(1, tester.curator().readAssignedCertificates().size());
-
- maintainer.maintain();
- assertEquals(2, tester.curator().readAssignedCertificates().size());
-
- // Verify random id is same for application and instance certificates
- Optional<AssignedCertificate> applicationCertificate = tester.curator().readAssignedCertificate(TenantAndApplicationId.from(app), Optional.empty());
- assertTrue(applicationCertificate.isPresent());
- Optional<AssignedCertificate> instanceCertificate = tester.curator().readAssignedCertificate(TenantAndApplicationId.from(app), Optional.of(app.instance()));
- assertTrue(instanceCertificate.isPresent());
- assertEquals(instanceCertificate.get().certificate().generatedId(), applicationCertificate.get().certificate().generatedId());
-
- // Verify the 3 wildcard random names are same in all certs
- List<String> appWildcardSans = applicationCertificate.get().certificate().requestedDnsSans();
- assertEquals(3, appWildcardSans.size());
- List<String> instanceSans = instanceCertificate.get().certificate().requestedDnsSans();
- List<String> wildcards = instanceSans.stream().filter(appWildcardSans::contains).toList();
- assertEquals(appWildcardSans, wildcards);
- }
-
- @Test
- void existing_application_randomid_is_copied_to_new_instance_deployments() {
- var instance1 = ApplicationId.from("tenant", "prod", "instance1");
- var instance2 = ApplicationId.from("tenant", "prod", "instance2");
-
- DeploymentTester deploymentTester = new DeploymentTester(tester);
- deployToAssignCert(deploymentTester, instance1, List.of(systemTest, stagingTest,productionUsWest1),Optional.of("instance1"));
- assertEquals(1, tester.curator().readAssignedCertificates().size());
- maintainer.maintain();
-
- String randomId = tester.curator().readAssignedCertificate(instance1).get().certificate().generatedId().get();
-
- deployToAssignCert(deploymentTester, instance2, List.of(productionUsWest1), Optional.of("instance1,instance2"));
- maintainer.maintain();
- assertEquals(3, tester.curator().readAssignedCertificates().size());
-
- assertEquals(randomId, tester.curator().readAssignedCertificate(instance1).get().certificate().generatedId().get());
- }
-
- @Test
- void dev_certificates_are_not_assigned_application_level_certificate() {
- var devApp = ApplicationId.from("tenant", "devonly", "foo");
- DeploymentTester deploymentTester = new DeploymentTester(tester);
- deployToAssignCert(deploymentTester, devApp, List.of(devUsEast1), Optional.empty());
- assertEquals(1, tester.curator().readAssignedCertificates().size());
- List<String> originalRequestedSans = tester.curator().readAssignedCertificate(devApp).get().certificate().requestedDnsSans();
- maintainer.maintain();
- assertEquals(1, tester.curator().readAssignedCertificates().size());
-
- // Verify certificate is assigned random id and 3 new names
- Optional<AssignedCertificate> assignedCertificate = tester.curator().readAssignedCertificate(devApp);
- assertTrue(assignedCertificate.get().certificate().generatedId().isPresent());
- List<String> newRequestedSans = assignedCertificate.get().certificate().requestedDnsSans();
- List<String> randomizedNames = newRequestedSans.stream().filter(san -> !originalRequestedSans.contains(san)).toList();
- assertEquals(3, randomizedNames.size());
- }
-
- @Test
void deploy_to_other_manual_zone_refreshes_cert() {
String devSan = "*.foo.manual.tenant.us-east-1.dev.vespa.oath.cloud";
String perfSan = "*.foo.manual.tenant.us-east-3.perf.vespa.oath.cloud";
@@ -301,10 +239,6 @@ public class EndpointCertificateMaintainerTest {
Assertions.assertThat(usCentralWestSans).contains(centralSan);
}
- private void deploy() {
-
- }
-
private void deployToAssignCert(DeploymentTester tester, ApplicationId applicationId, List<JobType> jobTypes, Optional<String> instances) {
var applicationPackageBuilder = new ApplicationPackageBuilder();
@@ -322,19 +256,15 @@ public class EndpointCertificateMaintainerTest {
jobs.forEach(deploymentContext::runJob);
}
- EndpointCertificate certificate(List<String> sans) {
- return new EndpointCertificate("keyName", "certName", 0, 0, "root-request-uuid", Optional.of("leaf-request-uuid"), List.of(), "issuer", Optional.empty(), Optional.empty(), Optional.empty());
- }
-
-
private static AssignedCertificate assignedCertificate(ApplicationId instance, EndpointCertificate certificate) {
- return new AssignedCertificate(TenantAndApplicationId.from(instance), Optional.of(instance.instance()), certificate);
+ return new AssignedCertificate(TenantAndApplicationId.from(instance), Optional.of(instance.instance()), certificate, false);
}
private void prepareCertificatePool(int numCertificates) {
((InMemoryFlagSource)tester.controller().flagSource()).withIntFlag(PermanentFlags.CERT_POOL_SIZE.id(), numCertificates);
((InMemoryFlagSource)tester.controller().flagSource()).withBooleanFlag(Flags.RANDOMIZED_ENDPOINT_NAMES.id(), true);
+ ((InMemoryFlagSource)tester.controller().flagSource()).withBooleanFlag(Flags.LEGACY_ENDPOINTS.id(), false);
// Provision certificates
for (int i = 0; i < numCertificates; i++) {
@@ -351,4 +281,5 @@ public class EndpointCertificateMaintainerTest {
});
certificatePoolMaintainer.maintain();
}
+
}
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 6882f43f1a7..c8853c008f7 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
@@ -4,7 +4,6 @@ package com.yahoo.vespa.hosted.controller.maintenance;
import com.yahoo.component.Version;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.zone.ZoneId;
-import com.yahoo.test.ManualClock;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId;
import com.yahoo.vespa.hosted.controller.application.Change;
@@ -26,6 +25,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;
@@ -40,7 +40,6 @@ import static com.yahoo.vespa.hosted.controller.deployment.DeploymentTrigger.Cha
import static com.yahoo.vespa.hosted.controller.deployment.DeploymentTrigger.ChangesToCancel.PLATFORM;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
@@ -1100,8 +1099,9 @@ public class UpgraderTest {
default2.instanceId(), default2);
// Throttle upgrades per run
- ((ManualClock) tester.controller().clock()).setInstant(Instant.ofEpochMilli(1589787107000L)); // Fixed random seed
- Upgrader upgrader = new Upgrader(tester.controller(), Duration.ofMinutes(10));
+ Upgrader upgrader = new Upgrader(tester.controller(),
+ Duration.ofMinutes(10),
+ new Random(1589787107000L)); // Fixed random seed
upgrader.setUpgradesPerMinute(0.1);
// Trigger some upgrades
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/RoutingPoliciesTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/RoutingPoliciesTest.java
index 2d9c2f40a2a..a10bfd46b0c 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/RoutingPoliciesTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/RoutingPoliciesTest.java
@@ -1068,11 +1068,9 @@ public class RoutingPoliciesTest {
}
@Test
- public void generated_endpoints() {
- var tester = new RoutingPoliciesTester(SystemName.Public);
+ public void combined_endpoint_config() {
+ var tester = new RoutingPoliciesTester(SystemName.Public).setEndpointConfig(EndpointConfig.combined);
var context = tester.newDeploymentContext("tenant1", "app1", "default");
- tester.controllerTester().flagSource().withBooleanFlag(Flags.RANDOMIZED_ENDPOINT_NAMES.id(), true);
- addCertificateToPool("cafed00d", UnassignedCertificate.State.ready, tester);
// Deploy application
int clustersPerZone = 2;
@@ -1093,10 +1091,10 @@ public class RoutingPoliciesTest {
// Deployment creates generated zone names
List<String> expectedRecords = List.of(
// save me, jebus!
- "a6414896.cafed00d.aws-eu-west-1.w.vespa-app.cloud",
- "b36bf591.cafed00d.z.vespa-app.cloud",
+ "a6414896.f5549014.aws-eu-west-1.w.vespa-app.cloud",
+ "aa7591aa.f5549014.z.vespa-app.cloud",
"bar.app1.tenant1.a.vespa-app.cloud",
- "bc50b636.cafed00d.z.vespa-app.cloud",
+ "bc50b636.f5549014.z.vespa-app.cloud",
"c0.app1.tenant1.aws-eu-west-1.w.vespa-app.cloud",
"c0.app1.tenant1.aws-eu-west-1a.z.vespa-app.cloud",
"c0.app1.tenant1.aws-us-east-1.w.vespa-app.cloud",
@@ -1105,16 +1103,16 @@ public class RoutingPoliciesTest {
"c1.app1.tenant1.aws-eu-west-1a.z.vespa-app.cloud",
"c1.app1.tenant1.aws-us-east-1a.z.vespa-app.cloud",
"c1.app1.tenant1.aws-us-east-1c.z.vespa-app.cloud",
- "c33db5ed.cafed00d.z.vespa-app.cloud",
- "d467800f.cafed00d.z.vespa-app.cloud",
- "d71005bf.cafed00d.z.vespa-app.cloud",
- "dd0971b4.cafed00d.z.vespa-app.cloud",
- "eb48ad53.cafed00d.z.vespa-app.cloud",
- "ec1e1288.cafed00d.z.vespa-app.cloud",
- "f2fa41ec.cafed00d.g.vespa-app.cloud",
- "f411d177.cafed00d.z.vespa-app.cloud",
- "f4a4d111.cafed00d.a.vespa-app.cloud",
- "fcf1bd63.cafed00d.aws-us-east-1.w.vespa-app.cloud",
+ "c33db5ed.f5549014.z.vespa-app.cloud",
+ "d467800f.f5549014.z.vespa-app.cloud",
+ "d71005bf.f5549014.z.vespa-app.cloud",
+ "dd0971b4.f5549014.g.vespa-app.cloud",
+ "eb48ad53.f5549014.z.vespa-app.cloud",
+ "ec1e1288.f5549014.z.vespa-app.cloud",
+ "f2fa41ec.f5549014.a.vespa-app.cloud",
+ "f411d177.f5549014.z.vespa-app.cloud",
+ "f4a4d111.f5549014.z.vespa-app.cloud",
+ "fcf1bd63.f5549014.aws-us-east-1.w.vespa-app.cloud",
"foo.app1.tenant1.g.vespa-app.cloud"
);
assertEquals(expectedRecords, tester.recordNames());
@@ -1178,23 +1176,23 @@ public class RoutingPoliciesTest {
.build();
context.submit(applicationPackage).deferLoadBalancerProvisioningIn(Environment.prod).deploy();
assertEquals(List.of(
- "b36bf591.cafed00d.z.vespa-app.cloud",
+ "aa7591aa.f5549014.z.vespa-app.cloud",
"bar.app1.tenant1.a.vespa-app.cloud",
- "bc50b636.cafed00d.z.vespa-app.cloud",
+ "bc50b636.f5549014.z.vespa-app.cloud",
"c0.app1.tenant1.aws-eu-west-1a.z.vespa-app.cloud",
"c0.app1.tenant1.aws-us-east-1a.z.vespa-app.cloud",
"c0.app1.tenant1.aws-us-east-1c.z.vespa-app.cloud",
"c1.app1.tenant1.aws-eu-west-1a.z.vespa-app.cloud",
"c1.app1.tenant1.aws-us-east-1a.z.vespa-app.cloud",
"c1.app1.tenant1.aws-us-east-1c.z.vespa-app.cloud",
- "c33db5ed.cafed00d.z.vespa-app.cloud",
- "d467800f.cafed00d.z.vespa-app.cloud",
- "d71005bf.cafed00d.z.vespa-app.cloud",
- "dd0971b4.cafed00d.z.vespa-app.cloud",
- "eb48ad53.cafed00d.z.vespa-app.cloud",
- "ec1e1288.cafed00d.z.vespa-app.cloud",
- "f411d177.cafed00d.z.vespa-app.cloud",
- "f4a4d111.cafed00d.a.vespa-app.cloud"
+ "c33db5ed.f5549014.z.vespa-app.cloud",
+ "d467800f.f5549014.z.vespa-app.cloud",
+ "d71005bf.f5549014.z.vespa-app.cloud",
+ "eb48ad53.f5549014.z.vespa-app.cloud",
+ "ec1e1288.f5549014.z.vespa-app.cloud",
+ "f2fa41ec.f5549014.a.vespa-app.cloud",
+ "f411d177.f5549014.z.vespa-app.cloud",
+ "f4a4d111.f5549014.z.vespa-app.cloud"
), tester.recordNames());
// Removing application removes all records
@@ -1206,11 +1204,9 @@ public class RoutingPoliciesTest {
}
@Test
- public void generated_endpoints_enable_token() {
- var tester = new RoutingPoliciesTester(SystemName.Public);
+ public void generated_endpoint_config_with_token() {
+ var tester = new RoutingPoliciesTester(SystemName.Public).setEndpointConfig(EndpointConfig.generated);
var context = tester.newDeploymentContext("tenant1", "app1", "default");
- tester.controllerTester().flagSource().withBooleanFlag(Flags.RANDOMIZED_ENDPOINT_NAMES.id(), true);
- tester.controllerTester().flagSource().withBooleanFlag(Flags.LEGACY_ENDPOINTS.id(), false);
addCertificateToPool("cafed00d", UnassignedCertificate.State.ready, tester);
// Deploy application without token
@@ -1270,12 +1266,9 @@ public class RoutingPoliciesTest {
}
@Test
- public void generated_endpoints_only() {
- var tester = new RoutingPoliciesTester(SystemName.Public);
+ public void generated_endpoint_config() {
+ var tester = new RoutingPoliciesTester(SystemName.Public).setEndpointConfig(EndpointConfig.generated);
var context = tester.newDeploymentContext("tenant1", "app1", "default");
- tester.controllerTester().flagSource()
- .withBooleanFlag(Flags.RANDOMIZED_ENDPOINT_NAMES.id(), true)
- .withBooleanFlag(Flags.LEGACY_ENDPOINTS.id(), false);
addCertificateToPool("cafed00d", UnassignedCertificate.State.ready, tester);
// Deploy application
@@ -1317,12 +1310,10 @@ public class RoutingPoliciesTest {
}
@Test
- public void generated_endpoints_multi_instance() {
- var tester = new RoutingPoliciesTester(SystemName.Public);
+ public void combined_endpoint_config_with_multiple_instances() {
+ var tester = new RoutingPoliciesTester(SystemName.Public).setEndpointConfig(EndpointConfig.combined);
var context0 = tester.newDeploymentContext("tenant1", "app1", "default");
var context1 = tester.newDeploymentContext("tenant1", "app1", "beta");
- tester.controllerTester().flagSource().withBooleanFlag(Flags.RANDOMIZED_ENDPOINT_NAMES.id(), true);
- addCertificateToPool("cafed00d", UnassignedCertificate.State.ready, tester);
// Deploy application
int clustersPerZone = 1;
@@ -1338,11 +1329,11 @@ public class RoutingPoliciesTest {
tester.provisionLoadBalancers(clustersPerZone, context1.instanceId(), zone1);
context0.submit(applicationPackage).deferLoadBalancerProvisioningIn(Environment.prod).deploy();
assertEquals(List.of("a0.app1.tenant1.a.vespa-app.cloud",
- "a9c8c045.cafed00d.z.vespa-app.cloud",
"c0.app1.tenant1.aws-us-east-1c.z.vespa-app.cloud",
"c0.beta.app1.tenant1.aws-us-east-1c.z.vespa-app.cloud",
- "e144a11b.cafed00d.z.vespa-app.cloud",
- "ee82b867.cafed00d.a.vespa-app.cloud"),
+ "cbff1506.f5549014.z.vespa-app.cloud",
+ "e144a11b.f5549014.a.vespa-app.cloud",
+ "ee82b867.f5549014.z.vespa-app.cloud"),
tester.recordNames());
tester.assertTargets(context0.application().id(), EndpointId.of("a0"), ClusterSpec.Id.from("c0"), 0,
Map.of(context0.deploymentIdIn(zone1), 1, context1.deploymentIdIn(zone1), 1));
@@ -1356,11 +1347,11 @@ public class RoutingPoliciesTest {
.build();
context0.submit(applicationPackage).deferLoadBalancerProvisioningIn(Environment.prod).deploy();
assertEquals(List.of("a0.app1.tenant1.a.vespa-app.cloud",
- "a9c8c045.cafed00d.z.vespa-app.cloud",
"c0.app1.tenant1.aws-us-east-1c.z.vespa-app.cloud",
"c0.beta.app1.tenant1.aws-us-east-1c.z.vespa-app.cloud",
- "e144a11b.cafed00d.z.vespa-app.cloud",
- "ee82b867.cafed00d.a.vespa-app.cloud"),
+ "cbff1506.f5549014.z.vespa-app.cloud",
+ "e144a11b.f5549014.a.vespa-app.cloud",
+ "ee82b867.f5549014.z.vespa-app.cloud"),
tester.recordNames());
tester.assertTargets(context0.application().id(), EndpointId.of("a0"), ClusterSpec.Id.from("c0"), 0,
Map.of(context1.deploymentIdIn(zone1), 1));
@@ -1374,10 +1365,9 @@ public class RoutingPoliciesTest {
}
@Test
- public void generated_endpoint_migration_with_global_endpoint() {
- var tester = new RoutingPoliciesTester(SystemName.Public);
+ public void migrate_legacy_to_combined_endpoint_config_with_global_endpoint() {
+ var tester = new RoutingPoliciesTester(SystemName.Public).setEndpointConfig(EndpointConfig.legacy);
var context = tester.newDeploymentContext("tenant1", "app1", "default");
- addCertificateToPool("cafed00d", UnassignedCertificate.State.ready, tester);
// Deploy application
int clustersPerZone = 2;
@@ -1392,8 +1382,8 @@ public class RoutingPoliciesTest {
context.submit(applicationPackage).deferLoadBalancerProvisioningIn(Environment.prod).deploy();
tester.assertTargets(context.instanceId(), EndpointId.of("foo"), 0, zone1, zone2);
- // Switch to generated
- tester.controllerTester().flagSource().withBooleanFlag(Flags.RANDOMIZED_ENDPOINT_NAMES.id(), true);
+ // Switch to combined
+ tester.setEndpointConfig(EndpointConfig.combined);
context.submit(applicationPackage).deferLoadBalancerProvisioningIn(Environment.prod).deploy();
tester.assertTargets(context.instance().id(), EndpointId.of("foo"), ClusterSpec.Id.from("c0"),
0, Map.of(zone1, 1L, zone2, 1L), true);
@@ -1403,9 +1393,13 @@ public class RoutingPoliciesTest {
EndpointCertificate cert = new EndpointCertificate("testKey", "testCert", 1, 0,
"request-id",
Optional.of("leaf-request-uuid"),
- List.of("name1", "name2"),
- "", Optional.empty(),
- Optional.empty(), Optional.of(id));
+ List.of("*." + id + ".z.vespa-app.cloud",
+ "*." + id + ".g.vespa-app.cloud",
+ "*." + id + ".a.vespa-app.cloud"),
+ "",
+ Optional.empty(),
+ Optional.empty(),
+ Optional.of(id));
UnassignedCertificate pooledCert = new UnassignedCertificate(cert, state);
tester.controllerTester().controller().curator().writeUnassignedCertificate(pooledCert);
}
@@ -1521,6 +1515,12 @@ public class RoutingPoliciesTest {
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
+ public RoutingPoliciesTester setEndpointConfig(EndpointConfig config) {
+ tester.controllerTester().flagSource().withBooleanFlag(Flags.LEGACY_ENDPOINTS.id(), config.supportsLegacy());
+ tester.controllerTester().flagSource().withBooleanFlag(Flags.RANDOMIZED_ENDPOINT_NAMES.id(), config.supportsGenerated());
+ return this;
+ }
+
public RoutingPolicies routingPolicies() {
return tester.controllerTester().controller().routing().policies();
}