summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2021-11-15 15:33:33 +0100
committerMartin Polden <mpolden@mpolden.no>2021-11-15 15:33:33 +0100
commitae17913e52e645b10f41ab5633bba785272546e6 (patch)
tree529dc7752f30b6fd0e5cbb5825b5c481e7128909
parent63c1f5a8008d231dd580bc76c38a4d48cd3d1970 (diff)
Require non-empty endpoint targets
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/RoutingController.java5
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Endpoint.java48
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/EndpointTest.java66
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/TestConfigSerializerTest.java6
4 files changed, 76 insertions, 49 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/RoutingController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/RoutingController.java
index 16f12b3ac07..a6b261a2981 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/RoutingController.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/RoutingController.java
@@ -191,9 +191,10 @@ public class RoutingController {
builders.add(Endpoint.of(deployment.applicationId()).target(ClusterSpec.Id.from("default"), deployment));
builders.add(Endpoint.of(deployment.applicationId()).wildcard(deployment));
- // Build all endpoints
+ // Build all certificate names
for (var builder : builders) {
- Endpoint endpoint = builder.routingMethod(RoutingMethod.exclusive)
+ Endpoint endpoint = builder.certificateName()
+ .routingMethod(RoutingMethod.exclusive)
.on(Port.tls())
.in(controller.system());
endpointDnsNames.add(endpoint.dnsName());
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Endpoint.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Endpoint.java
index 35601dd94dd..5bfc5a97e3d 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Endpoint.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Endpoint.java
@@ -46,7 +46,7 @@ public class Endpoint {
private Endpoint(TenantAndApplicationId application, Optional<InstanceName> instanceName, EndpointId id,
ClusterSpec.Id cluster, URI url, List<Target> targets, Scope scope, Port port, boolean legacy,
- RoutingMethod routingMethod) {
+ RoutingMethod routingMethod, boolean certificateName) {
Objects.requireNonNull(application, "application must be non-null");
Objects.requireNonNull(instanceName, "instanceName must be non-null");
Objects.requireNonNull(cluster, "cluster must be non-null");
@@ -56,6 +56,9 @@ public class Endpoint {
Objects.requireNonNull(routingMethod, "routingMethod must be non-null");
if (scope.multiDeployment()) {
if (id == null) throw new IllegalArgumentException("Endpoint ID must be set for multi-deployment endpoints");
+ if (!certificateName && targets.isEmpty()) {
+ throw new IllegalArgumentException("At least one target must be given for " + scope + " endpoints");
+ }
} else {
if (scope == Scope.zone && id != null) throw new IllegalArgumentException("Endpoint ID cannot be set for " + scope + " endpoints");
if (targets.size() != 1) throw new IllegalArgumentException("A single target must be given for " + scope + " endpoints");
@@ -89,11 +92,14 @@ public class Endpoint {
this.legacy = legacy;
this.routingMethod = routingMethod;
this.tls = port.tls;
+ if (!certificateName && "*".equals(name())) {
+ throw new IllegalArgumentException("Wildcard found in endpoint that is not intended as a certificate name");
+ }
}
private Endpoint(EndpointId id, ClusterSpec.Id cluster, TenantAndApplicationId application,
Optional<InstanceName> instance, List<Target> targets, Scope scope, SystemName system, Port port,
- boolean legacy, RoutingMethod routingMethod) {
+ boolean legacy, RoutingMethod routingMethod, boolean certificateName) {
this(application,
instance,
id,
@@ -107,7 +113,7 @@ public class Endpoint {
Objects.requireNonNull(port, "port must be non-null"),
legacy,
routingMethod),
- targets, scope, port, legacy, routingMethod);
+ targets, scope, port, legacy, routingMethod, certificateName);
}
/**
@@ -446,7 +452,7 @@ public class Endpoint {
ClusterSpec.Id.from("admin"),
url,
List.of(new Target(new DeploymentId(systemApplication.id(), zone))),
- Scope.zone, port, false, routingMethod);
+ Scope.zone, port, false, routingMethod, false);
}
/** A target of an endpoint */
@@ -491,6 +497,7 @@ public class Endpoint {
private Port port;
private RoutingMethod routingMethod = RoutingMethod.shared;
private boolean legacy = false;
+ private boolean certificateName = false;
private EndpointBuilder(TenantAndApplicationId application, Optional<InstanceName> instance) {
this.application = Objects.requireNonNull(application);
@@ -499,28 +506,26 @@ public class Endpoint {
/** Sets the deployment target for this */
public EndpointBuilder target(ClusterSpec.Id cluster, DeploymentId deployment) {
- checkScope();
this.cluster = cluster;
- this.scope = Scope.zone;
+ this.scope = requireUnset(Scope.zone);
this.targets = List.of(new Target(deployment));
return this;
}
- /** Sets the global target with given ID and pointing to the default cluster */
- public EndpointBuilder target(EndpointId endpointId) {
- return target(endpointId, ClusterSpec.Id.from("default"), List.of());
- }
-
/** Sets the global target with given ID, deployments and cluster (as defined in deployments.xml) */
public EndpointBuilder target(EndpointId endpointId, ClusterSpec.Id cluster, List<DeploymentId> deployments) {
- checkScope();
this.endpointId = endpointId;
this.cluster = cluster;
this.targets = deployments.stream().map(Target::new).collect(Collectors.toUnmodifiableList());
- this.scope = Scope.global;
+ this.scope = requireUnset(Scope.global);
return this;
}
+ /** Sets the global target with given ID and pointing to the default cluster */
+ public EndpointBuilder target(EndpointId endpointId) {
+ return target(endpointId, ClusterSpec.Id.from("default"), List.of());
+ }
+
/** Sets the global wildcard target for this */
public EndpointBuilder wildcard() {
return target(EndpointId.of("*"), ClusterSpec.Id.from("*"), List.of());
@@ -533,7 +538,6 @@ public class Endpoint {
/** Sets the application target with given ID, cluster, deployments and their weights */
public EndpointBuilder targetApplication(EndpointId endpointId, ClusterSpec.Id cluster, Map<DeploymentId, Integer> deployments) {
- checkScope();
this.endpointId = endpointId;
this.cluster = cluster;
this.targets = deployments.entrySet().stream()
@@ -545,9 +549,8 @@ public class Endpoint {
/** Sets the region target for this, deduced from given zone */
public EndpointBuilder targetRegion(ClusterSpec.Id cluster, ZoneId zone) {
- checkScope();
this.cluster = cluster;
- this.scope = Scope.weighted;
+ this.scope = requireUnset(Scope.weighted);
this.targets = List.of(new Target(new DeploymentId(application.instance(instance.get()), effectiveZone(zone))));
return this;
}
@@ -570,6 +573,12 @@ public class Endpoint {
return this;
}
+ /** Sets whether we're building a name for inclusion in a certificate */
+ public EndpointBuilder certificateName() {
+ this.certificateName = true;
+ return this;
+ }
+
/** Sets the system that owns this */
public Endpoint in(SystemName system) {
if (system.isPublic() && routingMethod != RoutingMethod.exclusive) {
@@ -578,13 +587,14 @@ public class Endpoint {
if (routingMethod.isDirect() && !port.isDefault()) {
throw new IllegalArgumentException("Routing method " + routingMethod + " can only use default port");
}
- return new Endpoint(endpointId, cluster, application, instance, targets, scope, system, port, legacy, routingMethod);
+ return new Endpoint(endpointId, cluster, application, instance, targets, scope, system, port, legacy, routingMethod, certificateName);
}
- private void checkScope() {
- if (scope != null) {
+ private Scope requireUnset(Scope scope) {
+ if (this.scope != null) {
throw new IllegalArgumentException("Cannot change endpoint scope. Already set to " + scope);
}
+ return scope;
}
}
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 c1f9137ecfa..fa4a871d423 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
@@ -27,122 +27,128 @@ public class EndpointTest {
@Test
public void global_endpoints() {
+ DeploymentId deployment1 = new DeploymentId(instance1, ZoneId.from("prod", "us-north-1"));
+ DeploymentId deployment2 = new DeploymentId(instance2, ZoneId.from("prod", "us-north-1"));
+ ClusterSpec.Id cluster = ClusterSpec.Id.from("default");
EndpointId endpointId = EndpointId.defaultId();
Map<String, Endpoint> tests = Map.of(
// Legacy endpoint
"http://a1.t1.global.vespa.yahooapis.com:4080/",
- Endpoint.of(instance1).target(endpointId).on(Port.plain(4080)).legacy().in(SystemName.main),
+ Endpoint.of(instance1).target(endpointId, cluster, List.of(deployment1)).on(Port.plain(4080)).legacy().in(SystemName.main),
// Legacy endpoint with TLS
"https://a1--t1.global.vespa.yahooapis.com:4443/",
- Endpoint.of(instance1).target(endpointId).on(Port.tls(4443)).legacy().in(SystemName.main),
+ Endpoint.of(instance1).target(endpointId, cluster, List.of(deployment1)).on(Port.tls(4443)).legacy().in(SystemName.main),
// Main endpoint
"https://a1--t1.global.vespa.oath.cloud:4443/",
- Endpoint.of(instance1).target(endpointId).on(Port.tls(4443)).in(SystemName.main),
+ Endpoint.of(instance1).target(endpointId, cluster, List.of(deployment1)).on(Port.tls(4443)).in(SystemName.main),
// Main endpoint in CD
"https://cd--a1--t1.global.vespa.oath.cloud:4443/",
- Endpoint.of(instance1).target(endpointId).on(Port.tls(4443)).in(SystemName.cd),
+ Endpoint.of(instance1).target(endpointId, cluster, List.of(deployment1)).on(Port.tls(4443)).in(SystemName.cd),
// Main endpoint in CD
"https://cd--i2--a2--t2.global.vespa.oath.cloud:4443/",
- Endpoint.of(instance2).target(endpointId).on(Port.tls(4443)).in(SystemName.cd),
+ Endpoint.of(instance2).target(endpointId, cluster, List.of(deployment2)).on(Port.tls(4443)).in(SystemName.cd),
// Main endpoint with direct routing and default TLS port
"https://a1.t1.global.vespa.oath.cloud/",
- Endpoint.of(instance1).target(endpointId).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
+ Endpoint.of(instance1).target(endpointId, cluster, List.of(deployment1)).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
// Main endpoint with custom rotation name
"https://r1.a1.t1.global.vespa.oath.cloud/",
- Endpoint.of(instance1).target(EndpointId.of("r1")).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
+ Endpoint.of(instance1).target(EndpointId.of("r1"), cluster, List.of(deployment1)).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
// Main endpoint for custom instance in default rotation
"https://i2.a2.t2.global.vespa.oath.cloud/",
- Endpoint.of(instance2).target(endpointId).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
+ Endpoint.of(instance2).target(endpointId, cluster, List.of(deployment2)).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
// Main endpoint for custom instance with custom rotation name
"https://r2.i2.a2.t2.global.vespa.oath.cloud/",
- Endpoint.of(instance2).target(EndpointId.of("r2")).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
+ Endpoint.of(instance2).target(EndpointId.of("r2"), cluster, List.of(deployment2)).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
// Main endpoint in public system
"https://a1.t1.g.vespa-app.cloud/",
- Endpoint.of(instance1).target(endpointId).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.Public)
+ Endpoint.of(instance1).target(endpointId, cluster, List.of(deployment1)).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.Public)
);
tests.forEach((expected, endpoint) -> assertEquals(expected, endpoint.url().toString()));
Map<String, Endpoint> tests2 = Map.of(
// Default endpoint in public system
"https://a1.t1.g.vespa-app.cloud/",
- Endpoint.of(instance1).target(endpointId).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.Public),
+ Endpoint.of(instance1).target(endpointId, cluster, List.of(deployment1)).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.Public),
// Default endpoint in public CD system
"https://a1.t1.g.cd.vespa-app.cloud/",
- Endpoint.of(instance1).target(endpointId).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.PublicCd),
+ Endpoint.of(instance1).target(endpointId, cluster, List.of(deployment1)).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.PublicCd),
// Custom instance in public system
"https://i2.a2.t2.g.vespa-app.cloud/",
- Endpoint.of(instance2).target(endpointId).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.Public)
+ Endpoint.of(instance2).target(endpointId, cluster, List.of(deployment2)).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.Public)
);
tests2.forEach((expected, endpoint) -> assertEquals(expected, endpoint.url().toString()));
}
@Test
public void global_endpoints_with_endpoint_id() {
- var endpointId = EndpointId.defaultId();
+ DeploymentId deployment1 = new DeploymentId(instance1, ZoneId.from("prod", "us-north-1"));
+ DeploymentId deployment2 = new DeploymentId(instance2, ZoneId.from("prod", "us-north-1"));
+ ClusterSpec.Id cluster = ClusterSpec.Id.from("default");
+ EndpointId endpointId = EndpointId.defaultId();
Map<String, Endpoint> tests = Map.of(
// Legacy endpoint
"http://a1.t1.global.vespa.yahooapis.com:4080/",
- Endpoint.of(instance1).target(endpointId).on(Port.plain(4080)).legacy().in(SystemName.main),
+ Endpoint.of(instance1).target(endpointId, cluster, List.of(deployment1)).on(Port.plain(4080)).legacy().in(SystemName.main),
// Legacy endpoint with TLS
"https://a1--t1.global.vespa.yahooapis.com:4443/",
- Endpoint.of(instance1).target(endpointId).on(Port.tls(4443)).legacy().in(SystemName.main),
+ Endpoint.of(instance1).target(endpointId, cluster, List.of(deployment1)).on(Port.tls(4443)).legacy().in(SystemName.main),
// Main endpoint
"https://a1--t1.global.vespa.oath.cloud:4443/",
- Endpoint.of(instance1).target(endpointId).on(Port.tls(4443)).in(SystemName.main),
+ Endpoint.of(instance1).target(endpointId, cluster, List.of(deployment1)).on(Port.tls(4443)).in(SystemName.main),
// Main endpoint in CD
"https://cd--i2--a2--t2.global.vespa.oath.cloud:4443/",
- Endpoint.of(instance2).target(endpointId).on(Port.tls(4443)).in(SystemName.cd),
+ Endpoint.of(instance2).target(endpointId, cluster, List.of(deployment2)).on(Port.tls(4443)).in(SystemName.cd),
// Main endpoint in CD
"https://cd--a1--t1.global.vespa.oath.cloud:4443/",
- Endpoint.of(instance1).target(endpointId).on(Port.tls(4443)).in(SystemName.cd),
+ Endpoint.of(instance1).target(endpointId, cluster, List.of(deployment1)).on(Port.tls(4443)).in(SystemName.cd),
// Main endpoint with direct routing and default TLS port
"https://a1.t1.global.vespa.oath.cloud/",
- Endpoint.of(instance1).target(endpointId).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
+ Endpoint.of(instance1).target(endpointId, cluster, List.of(deployment1)).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
// Main endpoint with custom rotation name
"https://r1.a1.t1.global.vespa.oath.cloud/",
- Endpoint.of(instance1).target(EndpointId.of("r1")).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
+ Endpoint.of(instance1).target(EndpointId.of("r1"), cluster, List.of(deployment1)).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
// Main endpoint for custom instance in default rotation
"https://i2.a2.t2.global.vespa.oath.cloud/",
- Endpoint.of(instance2).target(endpointId).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
+ Endpoint.of(instance2).target(endpointId, cluster, List.of(deployment2)).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
// Main endpoint for custom instance with custom rotation name
"https://r2.i2.a2.t2.global.vespa.oath.cloud/",
- Endpoint.of(instance2).target(EndpointId.of("r2")).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
+ Endpoint.of(instance2).target(EndpointId.of("r2"), cluster, List.of(deployment2)).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
// Main endpoint in public system
"https://a1.t1.g.vespa-app.cloud/",
- Endpoint.of(instance1).target(endpointId).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.Public)
+ Endpoint.of(instance1).target(endpointId, cluster, List.of(deployment1)).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.Public)
);
tests.forEach((expected, endpoint) -> assertEquals(expected, endpoint.url().toString()));
Map<String, Endpoint> tests2 = Map.of(
// Custom endpoint and instance in public CD system)
"https://foo.i2.a2.t2.g.cd.vespa-app.cloud/",
- Endpoint.of(instance2).target(EndpointId.of("foo")).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.PublicCd),
+ Endpoint.of(instance2).target(EndpointId.of("foo"), cluster, List.of(deployment2)).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.PublicCd),
// Custom endpoint and instance in public system
"https://foo.i2.a2.t2.g.vespa-app.cloud/",
- Endpoint.of(instance2).target(EndpointId.of("foo")).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.Public)
+ Endpoint.of(instance2).target(EndpointId.of("foo"), cluster, List.of(deployment2)).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.Public)
);
tests2.forEach((expected, endpoint) -> assertEquals(expected, endpoint.url().toString()));
}
@@ -228,6 +234,7 @@ public class EndpointTest {
"https://a1.t1.g.vespa-app.cloud/",
Endpoint.of(instance1)
.target(EndpointId.defaultId())
+ .certificateName()
.routingMethod(RoutingMethod.exclusive)
.on(Port.tls())
.in(SystemName.Public),
@@ -236,6 +243,7 @@ public class EndpointTest {
"https://*.a1.t1.g.vespa-app.cloud/",
Endpoint.of(instance1)
.wildcard()
+ .certificateName()
.routingMethod(RoutingMethod.exclusive)
.on(Port.tls())
.in(SystemName.Public),
@@ -244,6 +252,7 @@ public class EndpointTest {
"https://a1.t1.us-north-1.z.vespa-app.cloud/",
Endpoint.of(instance1)
.target(defaultCluster, prodZone)
+ .certificateName()
.routingMethod(RoutingMethod.exclusive)
.on(Port.tls())
.in(SystemName.Public),
@@ -252,6 +261,7 @@ public class EndpointTest {
"https://a1.t1.us-north-2.test.z.vespa-app.cloud/",
Endpoint.of(instance1)
.target(defaultCluster, testZone)
+ .certificateName()
.routingMethod(RoutingMethod.exclusive)
.on(Port.tls())
.in(SystemName.Public),
@@ -260,6 +270,7 @@ public class EndpointTest {
"https://*.a1.t1.us-north-2.test.z.vespa-app.cloud/",
Endpoint.of(instance1)
.wildcard(testZone)
+ .certificateName()
.routingMethod(RoutingMethod.exclusive)
.on(Port.tls())
.in(SystemName.Public),
@@ -268,6 +279,7 @@ public class EndpointTest {
"https://*.a1.t1.us-north-1.z.vespa-app.cloud/",
Endpoint.of(instance1)
.wildcard(prodZone)
+ .certificateName()
.routingMethod(RoutingMethod.exclusive)
.on(Port.tls())
.in(SystemName.Public)
@@ -353,7 +365,7 @@ public class EndpointTest {
var tests1 = Map.of(
// With default cluster
"a1.t1.us-north-1.prod",
- Endpoint.of(instance1).target(EndpointId.defaultId()).on(Port.tls(4443)).in(SystemName.main),
+ Endpoint.of(instance1).target(EndpointId.defaultId(), ClusterSpec.Id.from("default"), List.of(zone)).on(Port.tls(4443)).in(SystemName.main),
// With non-default cluster
"c1.a1.t1.us-north-1.prod",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/TestConfigSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/TestConfigSerializerTest.java
index 4ad70c4e9dd..61eca05cc67 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/TestConfigSerializerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/TestConfigSerializerTest.java
@@ -2,9 +2,11 @@
package com.yahoo.vespa.hosted.controller.deployment;
import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.slime.SlimeUtils;
+import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;
import com.yahoo.vespa.hosted.controller.application.Endpoint;
import com.yahoo.vespa.hosted.controller.application.EndpointId;
@@ -31,7 +33,9 @@ public class TestConfigSerializerTest {
JobType.systemTest,
true,
Map.of(zone, List.of(Endpoint.of(ApplicationId.defaultId())
- .target(EndpointId.of("ai"))
+ .target(EndpointId.of("ai"), ClusterSpec.Id.from("qrs"),
+ List.of(new DeploymentId(ApplicationId.defaultId(),
+ ZoneId.defaultId())))
.on(Endpoint.Port.tls())
.in(SystemName.main))),
Map.of(zone, List.of("facts")));