summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2021-10-22 10:52:45 +0200
committerGitHub <noreply@github.com>2021-10-22 10:52:45 +0200
commitb95cd673648e3cddc28debd38eefde9f5661291c (patch)
tree0cd8f104ac948e26b317fa7c31788dd7f615588d
parent477354aea222aad8b23bb121ce6c4add8da1c462 (diff)
parent5e63d00f81639c4d96a0777aeab7a00479c78772 (diff)
Merge pull request #19695 from vespa-engine/mpolden/named-region-endpoint
Introduce separate scope for internal region endpoint
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Endpoint.java117
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageValidator.java2
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java1
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/routing/RoutingPolicy.java2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/EndpointTest.java163
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/RoutingPoliciesTest.java6
6 files changed, 187 insertions, 104 deletions
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 b441d40c1c3..3a35e3aec7a 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
@@ -3,6 +3,7 @@ package com.yahoo.vespa.hosted.controller.application;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.ClusterSpec;
+import com.yahoo.config.provision.InstanceName;
import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.zone.RoutingMethod;
@@ -13,13 +14,15 @@ import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
import java.net.URI;
import java.util.List;
import java.util.Objects;
+import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
- * Represents an application's endpoint in hosted Vespa. This encapsulates all logic for building URLs and DNS names for
- * application endpoints.
+ * Represents an application or instance endpoint in hosted Vespa.
+ *
+ * This encapsulates the logic for building URLs and DNS names for applications in all hosted Vespa systems.
*
* @author mpolden
*/
@@ -50,7 +53,7 @@ public class Endpoint {
if (scope == Scope.global) {
if (id == null) throw new IllegalArgumentException("Endpoint ID must be set for global endpoints");
} else {
- if (id != null) throw new IllegalArgumentException("Endpoint ID cannot be set for " + scope + " endpoints");
+ if (scope == Scope.zone && id != null) throw new IllegalArgumentException("Endpoint ID cannot be set for " + scope + " endpoints");
if (zones.size() != 1) throw new IllegalArgumentException("A single zone must be given for " + scope + " endpoints");
}
this.id = id;
@@ -63,12 +66,14 @@ public class Endpoint {
this.tls = port.tls;
}
- private Endpoint(EndpointId id, ClusterSpec.Id cluster, ApplicationId application, List<ZoneId> zones, Scope scope, SystemName system,
- Port port, boolean legacy, RoutingMethod routingMethod) {
+ private Endpoint(EndpointId id, ClusterSpec.Id cluster, TenantAndApplicationId application,
+ Optional<InstanceName> instance, List<ZoneId> zones, Scope scope, SystemName system, Port port,
+ boolean legacy, RoutingMethod routingMethod) {
this(id,
cluster,
createUrl(endpointOrClusterAsString(id, cluster),
Objects.requireNonNull(application, "application must be non-null"),
+ Objects.requireNonNull(instance, "instance must be non-null"),
zones,
scope,
Objects.requireNonNull(system, "system must be non-null"),
@@ -164,20 +169,21 @@ public class Endpoint {
return id == null ? cluster.value() : id.id();
}
- private static URI createUrl(String name, ApplicationId application, List<ZoneId> zones, Scope scope,
- SystemName system, Port port, boolean legacy, RoutingMethod routingMethod) {
+ private static URI createUrl(String name, TenantAndApplicationId application, Optional<InstanceName> instance,
+ List<ZoneId> zones, Scope scope, SystemName system, Port port, boolean legacy,
+ RoutingMethod routingMethod) {
String scheme = port.tls ? "https" : "http";
String separator = separator(system, routingMethod, port.tls);
String portPart = port.isDefault() ? "" : ":" + port.port;
return URI.create(scheme + "://" +
sanitize(namePart(name, separator)) +
systemPart(system, separator, legacy) +
- sanitize(instancePart(application, separator)) +
+ sanitize(instancePart(instance, separator)) +
sanitize(application.application().value()) +
separator +
sanitize(application.tenant().value()) +
"." +
- scopePart(scope, zones, legacy, system) +
+ scopePart(scope, zones, system, legacy) +
dnsSuffix(system, legacy) +
portPart +
"/");
@@ -199,26 +205,42 @@ public class Endpoint {
return name + separator;
}
- private static String scopePart(Scope scope, List<ZoneId> zones, boolean legacy, SystemName system) {
+ private static String scopePart(Scope scope, List<ZoneId> zones, SystemName system, boolean legacy) {
+ String scopeSymbol = scopeSymbol(scope, system, legacy);
+ if (scope == Scope.global) return scopeSymbol;
+
+ ZoneId zone = zones.get(0);
+ String region = zone.region().value();
+ boolean skipEnvironment = zone.environment().isProduction() && (system.isPublic() || !legacy);
+ String environment = skipEnvironment ? "" : "." + zone.environment().value();
if (system.isPublic() && !legacy) {
- if (scope == Scope.global) return "g";
- var zone = zones.get(0);
- var region = zone.region().value();
- char scopeSymbol = scope == Scope.region ? 'r' : 'z';
- String environment = zone.environment().isProduction() ? "" : "." + zone.environment().value();
return region + environment + "." + scopeSymbol;
}
- if (scope == Scope.global) return "global";
- var zone = zones.get(0);
- var region = zone.region().value();
- if (scope == Scope.region) region += "-w";
- if ((system.isPublic() || !legacy) && zone.environment().isProduction()) return region;
- return region + "." + zone.environment().value();
+ return region + (scopeSymbol.isEmpty() ? "" : "-" + scopeSymbol) + environment;
}
- private static String instancePart(ApplicationId application, String separator) {
- if (application.instance().isDefault()) return ""; // Skip "default"
- return application.instance().value() + separator;
+ private static String scopeSymbol(Scope scope, SystemName system, boolean legacy) {
+ if (system.isPublic() && !legacy) {
+ switch (scope) {
+ case zone: return "z";
+ case regionSplit: return "w";
+ case region: return "r";
+ case global: return "g";
+ }
+ }
+ switch (scope) {
+ case zone: return "";
+ case regionSplit: return "w";
+ case region: return "r";
+ case global: return "global";
+ }
+ throw new IllegalArgumentException("No scope symbol defined for " + scope + " in " + system + " (legacy: " + legacy + ")");
+ }
+
+ private static String instancePart(Optional<InstanceName> instance, String separator) {
+ if (instance.isEmpty()) return "";
+ if (instance.get().isDefault()) return ""; // Skip "default"
+ return instance.get().value() + separator;
}
private static String systemPart(SystemName system, String separator, boolean legacy) {
@@ -246,7 +268,7 @@ public class Endpoint {
private static String upstreamIdOf(String name, ApplicationId application, ZoneId zone) {
return Stream.of(namePart(name, ""),
- instancePart(application, ""),
+ instancePart(Optional.of(application.instance()), ""),
application.application().value(),
application.tenant().value(),
zone.region().value(),
@@ -289,12 +311,21 @@ public class Endpoint {
/** Endpoint points to one or more zones. Traffic is routed to the zone closest to the client */
global,
- /** Endpoint points to one more zones in the same geographical region. Traffic is routed equally across zones */
+ /**
+ * Endpoint points to one more zones in the same geographical region. Traffic is weighted according to
+ * configured weights.
+ */
region,
/** Endpoint points to a single zone */
zone,
+ /**
+ * Endpoint points to one more zones in the same geographical region. Traffic is routed equally across zones.
+ *
+ * This is for internal use only. Endpoints with this scope are not exposed directly to tenants.
+ */
+ regionSplit,
}
/** Represents an endpoint's HTTP port */
@@ -338,9 +369,14 @@ public class Endpoint {
}
+ /** Build an endpoint for given instance */
+ public static EndpointBuilder of(ApplicationId instance) {
+ return new EndpointBuilder(TenantAndApplicationId.from(instance), Optional.of(instance.instance()));
+ }
+
/** Build an endpoint for given application */
- public static EndpointBuilder of(ApplicationId application) {
- return new EndpointBuilder(application);
+ public static EndpointBuilder of(TenantAndApplicationId application) {
+ return new EndpointBuilder(application, Optional.empty());
}
/** Create an endpoint for given system application */
@@ -353,7 +389,8 @@ public class Endpoint {
public static class EndpointBuilder {
- private final ApplicationId application;
+ private final TenantAndApplicationId application;
+ private final Optional<InstanceName> instance;
private Scope scope;
private List<ZoneId> zones;
@@ -363,8 +400,9 @@ public class Endpoint {
private RoutingMethod routingMethod = RoutingMethod.shared;
private boolean legacy = false;
- private EndpointBuilder(ApplicationId application) {
- this.application = application;
+ private EndpointBuilder(TenantAndApplicationId application, Optional<InstanceName> instance) {
+ this.application = Objects.requireNonNull(application);
+ this.instance = Objects.requireNonNull(instance);
}
/** Sets the zone target for this */
@@ -402,9 +440,19 @@ public class Endpoint {
}
/** Sets the region target for this, deduced from given zone */
- public EndpointBuilder targetRegion(ClusterSpec.Id cluster, ZoneId zone) {
+ public EndpointBuilder targetRegionSplit(ClusterSpec.Id cluster, ZoneId zone) {
checkScope();
this.cluster = cluster;
+ this.scope = Scope.regionSplit;
+ this.zones = List.of(effectiveZone(zone));
+ return this;
+ }
+
+ /** Sets the region target for this by endpointId, deduced from given zone */
+ public EndpointBuilder targetRegion(EndpointId endpointId, ClusterSpec.Id cluster, ZoneId zone) {
+ checkScope();
+ this.endpointId = endpointId;
+ this.cluster = cluster;
this.scope = Scope.region;
this.zones = List.of(effectiveZone(zone));
return this;
@@ -436,7 +484,10 @@ 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, zones, scope, system, port, legacy, routingMethod);
+ if (scope == Scope.region && instance.isPresent()) {
+ throw new IllegalArgumentException("Instance cannot be set for scope " + scope);
+ }
+ return new Endpoint(endpointId, cluster, application, instance, zones, scope, system, port, legacy, routingMethod);
}
private void checkScope() {
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageValidator.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageValidator.java
index 3dc95251eb8..bd6376e58aa 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageValidator.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageValidator.java
@@ -102,7 +102,7 @@ public class ApplicationPackageValidator {
instant));
}
- /** Verify that compactable endpoint parts (instance aname nd endpoint ID) do not clash */
+ /** Verify that compactable endpoint parts (instance name and endpoint ID) do not clash */
private void validateCompactedEndpoint(ApplicationPackage applicationPackage) {
Map<List<String>, InstanceEndpoint> instanceEndpoints = new HashMap<>();
for (var instanceSpec : applicationPackage.deploymentSpec().instances()) {
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
index 59d18fcf17b..51911d62ef4 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
@@ -2698,6 +2698,7 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
private static String endpointScopeString(Endpoint.Scope scope) {
switch (scope) {
case region: return "region";
+ case regionSplit: return "regionSplit";
case global: return "global";
case zone: return "zone";
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/routing/RoutingPolicy.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/routing/RoutingPolicy.java
index ec9cf4064c9..f93e24f969e 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/routing/RoutingPolicy.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/routing/RoutingPolicy.java
@@ -111,7 +111,7 @@ public class RoutingPolicy {
/** Returns the region endpoint of this */
public Endpoint regionEndpointIn(SystemName system, RoutingMethod routingMethod, boolean legacy) {
- Endpoint.EndpointBuilder endpoint = endpoint(routingMethod).targetRegion(id.cluster(), id.zone());
+ Endpoint.EndpointBuilder endpoint = endpoint(routingMethod).targetRegionSplit(id.cluster(), id.zone());
if (legacy) {
endpoint = endpoint.legacy();
}
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 da641d17a8a..5d985518809 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
@@ -20,8 +20,10 @@ import static org.junit.Assert.assertEquals;
*/
public class EndpointTest {
- private static final ApplicationId app1 = ApplicationId.from("t1", "a1", "default");
- private static final ApplicationId app2 = ApplicationId.from("t2", "a2", "i2");
+ private static final ApplicationId instance1 = ApplicationId.from("t1", "a1", "default");
+ private static final ApplicationId instance2 = ApplicationId.from("t2", "a2", "i2");
+ private static final TenantAndApplicationId app1 = TenantAndApplicationId.from(instance1);
+ private static final TenantAndApplicationId app2 = TenantAndApplicationId.from(instance2);
@Test
public void global_endpoints() {
@@ -30,62 +32,62 @@ public class EndpointTest {
Map<String, Endpoint> tests = Map.of(
// Legacy endpoint
"http://a1.t1.global.vespa.yahooapis.com:4080/",
- Endpoint.of(app1).target(endpointId).on(Port.plain(4080)).legacy().in(SystemName.main),
+ Endpoint.of(instance1).target(endpointId).on(Port.plain(4080)).legacy().in(SystemName.main),
// Legacy endpoint with TLS
"https://a1--t1.global.vespa.yahooapis.com:4443/",
- Endpoint.of(app1).target(endpointId).on(Port.tls(4443)).legacy().in(SystemName.main),
+ Endpoint.of(instance1).target(endpointId).on(Port.tls(4443)).legacy().in(SystemName.main),
// Main endpoint
"https://a1--t1.global.vespa.oath.cloud:4443/",
- Endpoint.of(app1).target(endpointId).on(Port.tls(4443)).in(SystemName.main),
+ Endpoint.of(instance1).target(endpointId).on(Port.tls(4443)).in(SystemName.main),
// Main endpoint in CD
"https://cd--a1--t1.global.vespa.oath.cloud:4443/",
- Endpoint.of(app1).target(endpointId).on(Port.tls(4443)).in(SystemName.cd),
+ Endpoint.of(instance1).target(endpointId).on(Port.tls(4443)).in(SystemName.cd),
// Main endpoint in CD
"https://cd--i2--a2--t2.global.vespa.oath.cloud:4443/",
- Endpoint.of(app2).target(endpointId).on(Port.tls(4443)).in(SystemName.cd),
+ Endpoint.of(instance2).target(endpointId).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(app1).target(endpointId).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
+ Endpoint.of(instance1).target(endpointId).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(app1).target(EndpointId.of("r1")).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
+ Endpoint.of(instance1).target(EndpointId.of("r1")).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(app2).target(endpointId).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
+ Endpoint.of(instance2).target(endpointId).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(app2).target(EndpointId.of("r2")).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
+ Endpoint.of(instance2).target(EndpointId.of("r2")).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
// Main endpoint in public system (legacy)
"https://a1.t1.global.public.vespa.oath.cloud/",
- Endpoint.of(app1).target(endpointId).on(Port.tls()).routingMethod(RoutingMethod.exclusive).legacy().in(SystemName.Public)
+ Endpoint.of(instance1).target(endpointId).on(Port.tls()).routingMethod(RoutingMethod.exclusive).legacy().in(SystemName.Public)
);
tests.forEach((expected, endpoint) -> assertEquals(expected, endpoint.url().toString()));
Map<String, Endpoint> tests2 = Map.of(
// Main endpoint in public CD system (legacy)
"https://publiccd.a1.t1.global.public-cd.vespa.oath.cloud/",
- Endpoint.of(app1).target(endpointId).on(Port.tls()).routingMethod(RoutingMethod.exclusive).legacy().in(SystemName.PublicCd),
+ Endpoint.of(instance1).target(endpointId).on(Port.tls()).routingMethod(RoutingMethod.exclusive).legacy().in(SystemName.PublicCd),
// Default endpoint in public system
"https://a1.t1.g.vespa-app.cloud/",
- Endpoint.of(app1).target(endpointId).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.Public),
+ Endpoint.of(instance1).target(endpointId).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(app1).target(endpointId).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.PublicCd),
+ Endpoint.of(instance1).target(endpointId).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.PublicCd),
// Custom instance in public system
"https://i2.a2.t2.g.vespa-app.cloud/",
- Endpoint.of(app2).target(endpointId).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.Public)
+ Endpoint.of(instance2).target(endpointId).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.Public)
);
tests2.forEach((expected, endpoint) -> assertEquals(expected, endpoint.url().toString()));
}
@@ -97,54 +99,54 @@ public class EndpointTest {
Map<String, Endpoint> tests = Map.of(
// Legacy endpoint
"http://a1.t1.global.vespa.yahooapis.com:4080/",
- Endpoint.of(app1).target(endpointId).on(Port.plain(4080)).legacy().in(SystemName.main),
+ Endpoint.of(instance1).target(endpointId).on(Port.plain(4080)).legacy().in(SystemName.main),
// Legacy endpoint with TLS
"https://a1--t1.global.vespa.yahooapis.com:4443/",
- Endpoint.of(app1).target(endpointId).on(Port.tls(4443)).legacy().in(SystemName.main),
+ Endpoint.of(instance1).target(endpointId).on(Port.tls(4443)).legacy().in(SystemName.main),
// Main endpoint
"https://a1--t1.global.vespa.oath.cloud:4443/",
- Endpoint.of(app1).target(endpointId).on(Port.tls(4443)).in(SystemName.main),
+ Endpoint.of(instance1).target(endpointId).on(Port.tls(4443)).in(SystemName.main),
// Main endpoint in CD
"https://cd--i2--a2--t2.global.vespa.oath.cloud:4443/",
- Endpoint.of(app2).target(endpointId).on(Port.tls(4443)).in(SystemName.cd),
+ Endpoint.of(instance2).target(endpointId).on(Port.tls(4443)).in(SystemName.cd),
// Main endpoint in CD
"https://cd--a1--t1.global.vespa.oath.cloud:4443/",
- Endpoint.of(app1).target(endpointId).on(Port.tls(4443)).in(SystemName.cd),
+ Endpoint.of(instance1).target(endpointId).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(app1).target(endpointId).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
+ Endpoint.of(instance1).target(endpointId).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(app1).target(EndpointId.of("r1")).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
+ Endpoint.of(instance1).target(EndpointId.of("r1")).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(app2).target(endpointId).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
+ Endpoint.of(instance2).target(endpointId).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(app2).target(EndpointId.of("r2")).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
+ Endpoint.of(instance2).target(EndpointId.of("r2")).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
// Main endpoint in public system (legacy)
"https://a1.t1.global.public.vespa.oath.cloud/",
- Endpoint.of(app1).target(endpointId).on(Port.tls()).routingMethod(RoutingMethod.exclusive).legacy().in(SystemName.Public)
+ Endpoint.of(instance1).target(endpointId).on(Port.tls()).routingMethod(RoutingMethod.exclusive).legacy().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 (legacy)
"https://foo.publiccd.i2.a2.t2.global.public-cd.vespa.oath.cloud/",
- Endpoint.of(app2).target(EndpointId.of("foo")).on(Port.tls()).routingMethod(RoutingMethod.exclusive).legacy().in(SystemName.PublicCd),
+ Endpoint.of(instance2).target(EndpointId.of("foo")).on(Port.tls()).routingMethod(RoutingMethod.exclusive).legacy().in(SystemName.PublicCd),
// Custom endpoint and instance in public system
"https://foo.i2.a2.t2.g.vespa-app.cloud/",
- Endpoint.of(app2).target(EndpointId.of("foo")).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.Public)
+ Endpoint.of(instance2).target(EndpointId.of("foo")).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.Public)
);
tests2.forEach((expected, endpoint) -> assertEquals(expected, endpoint.url().toString()));
}
@@ -158,62 +160,62 @@ public class EndpointTest {
Map<String, Endpoint> tests = Map.of(
// Legacy endpoint (always contains environment)
"http://a1.t1.us-north-1.prod.vespa.yahooapis.com:4080/",
- Endpoint.of(app1).target(cluster, prodZone).on(Port.plain(4080)).legacy().in(SystemName.main),
+ Endpoint.of(instance1).target(cluster, prodZone).on(Port.plain(4080)).legacy().in(SystemName.main),
// Secure legacy endpoint
"https://a1--t1.us-north-1.prod.vespa.yahooapis.com:4443/",
- Endpoint.of(app1).target(cluster, prodZone).on(Port.tls(4443)).legacy().in(SystemName.main),
+ Endpoint.of(instance1).target(cluster, prodZone).on(Port.tls(4443)).legacy().in(SystemName.main),
// Prod endpoint in main
"https://a1--t1.us-north-1.vespa.oath.cloud:4443/",
- Endpoint.of(app1).target(cluster, prodZone).on(Port.tls(4443)).in(SystemName.main),
+ Endpoint.of(instance1).target(cluster, prodZone).on(Port.tls(4443)).in(SystemName.main),
// Prod endpoint in CD
"https://cd--a1--t1.us-north-1.vespa.oath.cloud:4443/",
- Endpoint.of(app1).target(cluster, prodZone).on(Port.tls(4443)).in(SystemName.cd),
+ Endpoint.of(instance1).target(cluster, prodZone).on(Port.tls(4443)).in(SystemName.cd),
// Test endpoint in main
"https://a1--t1.us-north-2.test.vespa.oath.cloud:4443/",
- Endpoint.of(app1).target(cluster, testZone).on(Port.tls(4443)).in(SystemName.main),
+ Endpoint.of(instance1).target(cluster, testZone).on(Port.tls(4443)).in(SystemName.main),
// Non-default cluster in main
"https://c1--a1--t1.us-north-1.vespa.oath.cloud/",
- Endpoint.of(app1).target(ClusterSpec.Id.from("c1"), prodZone).on(Port.tls()).in(SystemName.main),
+ Endpoint.of(instance1).target(ClusterSpec.Id.from("c1"), prodZone).on(Port.tls()).in(SystemName.main),
// Non-default instance in main
"https://i2--a2--t2.us-north-1.vespa.oath.cloud:4443/",
- Endpoint.of(app2).target(cluster, prodZone).on(Port.tls(4443)).in(SystemName.main),
+ Endpoint.of(instance2).target(cluster, prodZone).on(Port.tls(4443)).in(SystemName.main),
// Non-default cluster in public (legacy)
"https://c1.a1.t1.us-north-1.public.vespa.oath.cloud/",
- Endpoint.of(app1).target(ClusterSpec.Id.from("c1"), prodZone).on(Port.tls()).routingMethod(RoutingMethod.exclusive).legacy().in(SystemName.Public),
+ Endpoint.of(instance1).target(ClusterSpec.Id.from("c1"), prodZone).on(Port.tls()).routingMethod(RoutingMethod.exclusive).legacy().in(SystemName.Public),
// Non-default cluster and instance in public (legacy)
"https://c2.i2.a2.t2.us-north-1.public.vespa.oath.cloud/",
- Endpoint.of(app2).target(ClusterSpec.Id.from("c2"), prodZone).on(Port.tls()).routingMethod(RoutingMethod.exclusive).legacy().in(SystemName.Public),
+ Endpoint.of(instance2).target(ClusterSpec.Id.from("c2"), prodZone).on(Port.tls()).routingMethod(RoutingMethod.exclusive).legacy().in(SystemName.Public),
// Endpoint in main using shared layer 4
"https://a1.t1.us-north-1.vespa.oath.cloud/",
- Endpoint.of(app1).target(cluster, prodZone).on(Port.tls()).routingMethod(RoutingMethod.sharedLayer4).in(SystemName.main)
+ Endpoint.of(instance1).target(cluster, prodZone).on(Port.tls()).routingMethod(RoutingMethod.sharedLayer4).in(SystemName.main)
);
tests.forEach((expected, endpoint) -> assertEquals(expected, endpoint.url().toString()));
Map<String, Endpoint> tests2 = Map.of(
// Non-default cluster and instance in public CD (legacy)
"https://c2.publiccd.i2.a2.t2.us-north-1.public-cd.vespa.oath.cloud/",
- Endpoint.of(app2).target(ClusterSpec.Id.from("c2"), prodZone).on(Port.tls()).routingMethod(RoutingMethod.exclusive).legacy().in(SystemName.PublicCd),
+ Endpoint.of(instance2).target(ClusterSpec.Id.from("c2"), prodZone).on(Port.tls()).routingMethod(RoutingMethod.exclusive).legacy().in(SystemName.PublicCd),
// Custom cluster name in public
"https://c1.a1.t1.us-north-1.z.vespa-app.cloud/",
- Endpoint.of(app1).target(ClusterSpec.Id.from("c1"), prodZone).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.Public),
+ Endpoint.of(instance1).target(ClusterSpec.Id.from("c1"), prodZone).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.Public),
// Default cluster name in non-production zone in public
"https://a1.t1.us-north-2.test.z.vespa-app.cloud/",
- Endpoint.of(app1).target(ClusterSpec.Id.from("default"), testZone).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.Public),
+ Endpoint.of(instance1).target(ClusterSpec.Id.from("default"), testZone).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.Public),
// Default cluster name in public CD
"https://a1.t1.us-north-1.z.cd.vespa-app.cloud/",
- Endpoint.of(app1).target(ClusterSpec.Id.from("default"), prodZone).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.PublicCd)
+ Endpoint.of(instance1).target(ClusterSpec.Id.from("default"), prodZone).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.PublicCd)
);
tests2.forEach((expected, endpoint) -> assertEquals(expected, endpoint.url().toString()));
}
@@ -227,7 +229,7 @@ public class EndpointTest {
var tests = Map.of(
// Default rotation
"https://a1.t1.global.public.vespa.oath.cloud/",
- Endpoint.of(app1)
+ Endpoint.of(instance1)
.target(EndpointId.defaultId())
.routingMethod(RoutingMethod.exclusive)
.on(Port.tls())
@@ -236,7 +238,7 @@ public class EndpointTest {
// Wildcard to match other rotations
"https://*.a1.t1.global.public.vespa.oath.cloud/",
- Endpoint.of(app1)
+ Endpoint.of(instance1)
.wildcard()
.routingMethod(RoutingMethod.exclusive)
.on(Port.tls())
@@ -245,7 +247,7 @@ public class EndpointTest {
// Default cluster in zone
"https://a1.t1.us-north-1.public.vespa.oath.cloud/",
- Endpoint.of(app1)
+ Endpoint.of(instance1)
.target(defaultCluster, prodZone)
.routingMethod(RoutingMethod.exclusive)
.on(Port.tls())
@@ -254,7 +256,7 @@ public class EndpointTest {
// Wildcard to match other clusters in zone
"https://*.a1.t1.us-north-1.public.vespa.oath.cloud/",
- Endpoint.of(app1)
+ Endpoint.of(instance1)
.wildcard(prodZone)
.routingMethod(RoutingMethod.exclusive)
.on(Port.tls())
@@ -263,7 +265,7 @@ public class EndpointTest {
// Default cluster in test zone
"https://a1.t1.us-north-2.test.public.vespa.oath.cloud/",
- Endpoint.of(app1)
+ Endpoint.of(instance1)
.target(defaultCluster, testZone)
.routingMethod(RoutingMethod.exclusive)
.on(Port.tls())
@@ -272,7 +274,7 @@ public class EndpointTest {
// Wildcard to match other clusters in test zone
"https://*.a1.t1.us-north-2.test.public.vespa.oath.cloud/",
- Endpoint.of(app1)
+ Endpoint.of(instance1)
.wildcard(testZone)
.routingMethod(RoutingMethod.exclusive)
.on(Port.tls())
@@ -281,7 +283,7 @@ public class EndpointTest {
// Wildcard to match other clusters in zone
"https://*.a1.t1.us-north-1.z.vespa-app.cloud/",
- Endpoint.of(app1)
+ Endpoint.of(instance1)
.wildcard(prodZone)
.routingMethod(RoutingMethod.exclusive)
.on(Port.tls())
@@ -296,37 +298,66 @@ public class EndpointTest {
var cluster = ClusterSpec.Id.from("default");
var prodZone = ZoneId.from("prod", "us-north-2");
Map<String, Endpoint> tests = Map.of(
- "https://a1.t1.us-north-1-w.public.vespa.oath.cloud/",
+ "https://r0.a1.t1.us-north-2-r.vespa.oath.cloud/",
Endpoint.of(app1)
- .targetRegion(cluster, ZoneId.from("prod", "us-north-1a"))
+ .targetRegion(EndpointId.of("r0"), ClusterSpec.Id.from("c1"), prodZone)
+ .routingMethod(RoutingMethod.sharedLayer4)
+ .on(Port.tls())
+ .in(SystemName.main),
+ "https://r1.a2.t2.us-north-2.r.vespa-app.cloud/",
+ Endpoint.of(app2)
+ .targetRegion(EndpointId.of("r1"), ClusterSpec.Id.from("c1"), prodZone)
+ .routingMethod(RoutingMethod.exclusive)
+ .on(Port.tls())
+ .in(SystemName.Public)
+ );
+ tests.forEach((expected, endpoint) -> assertEquals(expected, endpoint.url().toString()));
+ Endpoint endpoint = Endpoint.of(instance1)
+ .targetRegionSplit(cluster, ZoneId.from("prod", "us-north-1a"))
+ .routingMethod(RoutingMethod.exclusive)
+ .on(Port.tls())
+ .in(SystemName.main);
+ assertEquals("Availability zone is removed from region",
+ "us-north-1",
+ endpoint.zones().get(0).region().value());
+ }
+
+ @Test
+ public void region_split_endpoints() {
+ var cluster = ClusterSpec.Id.from("default");
+ var prodZone = ZoneId.from("prod", "us-north-2");
+ Map<String, Endpoint> tests = Map.of(
+ "https://a1.t1.us-north-1-w.public.vespa.oath.cloud/",
+ Endpoint.of(instance1)
+ .targetRegionSplit(cluster, ZoneId.from("prod", "us-north-1a"))
.routingMethod(RoutingMethod.exclusive)
.on(Port.tls())
.legacy()
.in(SystemName.Public),
"https://a1.t1.us-north-2-w.public.vespa.oath.cloud/",
- Endpoint.of(app1)
- .targetRegion(cluster, prodZone)
+ Endpoint.of(instance1)
+ .targetRegionSplit(cluster, prodZone)
.routingMethod(RoutingMethod.exclusive)
.on(Port.tls())
.legacy()
.in(SystemName.Public),
"https://a1.t1.us-north-2-w.test.public.vespa.oath.cloud/",
- Endpoint.of(app1)
- .targetRegion(cluster, ZoneId.from("test", "us-north-2"))
+ Endpoint.of(instance1)
+ .targetRegionSplit(cluster, ZoneId.from("test", "us-north-2"))
.routingMethod(RoutingMethod.exclusive)
.on(Port.tls())
.legacy()
.in(SystemName.Public),
- "https://c1.a1.t1.us-north-2.r.vespa-app.cloud/",
- Endpoint.of(app1)
- .targetRegion(ClusterSpec.Id.from("c1"), prodZone)
+ "https://c1.a1.t1.us-north-2.w.vespa-app.cloud/",
+ Endpoint.of(instance1)
+ .targetRegionSplit(ClusterSpec.Id.from("c1"), prodZone)
.routingMethod(RoutingMethod.exclusive)
.on(Port.tls())
.in(SystemName.Public)
);
tests.forEach((expected, endpoint) -> assertEquals(expected, endpoint.url().toString()));
- Endpoint endpoint = Endpoint.of(app1)
- .targetRegion(cluster, ZoneId.from("prod", "us-north-1a"))
+ Endpoint endpoint = Endpoint.of(instance1)
+ .targetRegionSplit(cluster, ZoneId.from("prod", "us-north-1a"))
.routingMethod(RoutingMethod.exclusive)
.on(Port.tls())
.in(SystemName.main);
@@ -341,23 +372,23 @@ public class EndpointTest {
var tests1 = Map.of(
// With default cluster
"a1.t1.us-north-1.prod",
- Endpoint.of(app1).target(EndpointId.defaultId()).on(Port.tls(4443)).in(SystemName.main),
+ Endpoint.of(instance1).target(EndpointId.defaultId()).on(Port.tls(4443)).in(SystemName.main),
// With non-default cluster
"c1.a1.t1.us-north-1.prod",
- Endpoint.of(app1).target(EndpointId.of("ignored1"), ClusterSpec.Id.from("c1"), List.of(zone)).on(Port.tls(4443)).in(SystemName.main)
+ Endpoint.of(instance1).target(EndpointId.of("ignored1"), ClusterSpec.Id.from("c1"), List.of(zone)).on(Port.tls(4443)).in(SystemName.main)
);
var tests2 = Map.of(
// With non-default instance and default cluster
"i2.a2.t2.us-north-1.prod",
- Endpoint.of(app2).target(EndpointId.defaultId(), ClusterSpec.Id.from("default"), List.of(zone)).on(Port.tls(4443)).in(SystemName.main),
+ Endpoint.of(instance2).target(EndpointId.defaultId(), ClusterSpec.Id.from("default"), List.of(zone)).on(Port.tls(4443)).in(SystemName.main),
// With non-default instance and cluster
"c2.i2.a2.t2.us-north-1.prod",
- Endpoint.of(app2).target(EndpointId.of("ignored2"), ClusterSpec.Id.from("c2"), List.of(zone)).on(Port.tls(4443)).in(SystemName.main)
+ Endpoint.of(instance2).target(EndpointId.of("ignored2"), ClusterSpec.Id.from("c2"), List.of(zone)).on(Port.tls(4443)).in(SystemName.main)
);
- tests1.forEach((expected, endpoint) -> assertEquals(expected, endpoint.upstreamIdOf(new DeploymentId(app1, zone))));
- tests2.forEach((expected, endpoint) -> assertEquals(expected, endpoint.upstreamIdOf(new DeploymentId(app2, zone))));
+ tests1.forEach((expected, endpoint) -> assertEquals(expected, endpoint.upstreamIdOf(new DeploymentId(instance1, zone))));
+ tests2.forEach((expected, endpoint) -> assertEquals(expected, endpoint.upstreamIdOf(new DeploymentId(instance2, zone))));
}
}
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 2002b59dc1e..c678a83bf2c 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
@@ -364,11 +364,11 @@ public class RoutingPoliciesTest {
Map.of(zone1, 1L, zone2, 1L), true);
assertEquals("Registers expected DNS names",
Set.of("app1.tenant1.aws-eu-west-1-w.public.vespa.oath.cloud",
- "app1.tenant1.aws-eu-west-1.r.vespa-app.cloud",
+ "app1.tenant1.aws-eu-west-1.w.vespa-app.cloud",
"app1.tenant1.aws-eu-west-1a.public.vespa.oath.cloud",
"app1.tenant1.aws-eu-west-1a.z.vespa-app.cloud",
"app1.tenant1.aws-us-east-1-w.public.vespa.oath.cloud",
- "app1.tenant1.aws-us-east-1.r.vespa-app.cloud",
+ "app1.tenant1.aws-us-east-1.w.vespa-app.cloud",
"app1.tenant1.aws-us-east-1c.public.vespa.oath.cloud",
"app1.tenant1.aws-us-east-1c.z.vespa-app.cloud",
"app1.tenant1.g.vespa-app.cloud",
@@ -837,7 +837,7 @@ public class RoutingPoliciesTest {
DeploymentId deployment = new DeploymentId(application, zone);
EndpointList regionEndpoints = tester.controller().routing().endpointsOf(deployment)
.cluster(cluster)
- .scope(Endpoint.Scope.region);
+ .scope(Endpoint.Scope.regionSplit);
if (!legacy) {
regionEndpoints = regionEndpoints.not().legacy();
}