summaryrefslogtreecommitdiffstats
path: root/controller-server
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2021-11-04 11:16:59 +0100
committerMartin Polden <mpolden@mpolden.no>2021-11-04 11:16:59 +0100
commitca5fd6a2a5c5eb4ffd05810be87628c0082bb9d1 (patch)
tree2a1161647d07d525b486ac976d9bef3227499a75 /controller-server
parent4d275793ca055a211f6cb1cc0d88f42c798518bb (diff)
Replace zones with targets in Endpoint
Diffstat (limited to 'controller-server')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/RoutingController.java23
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Endpoint.java139
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/EndpointId.java4
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/EndpointList.java14
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java2
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/routing/RoutingApiHandler.java10
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/routing/RoutingId.java22
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/routing/RoutingPolicies.java4
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/routing/RoutingPolicy.java8
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/EndpointTest.java38
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/RoutingPoliciesTest.java11
11 files changed, 175 insertions, 100 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 53dec79bba9..6be62367407 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
@@ -58,7 +58,7 @@ import java.util.stream.Collectors;
* The routing controller encapsulates state and methods for inspecting and manipulating deployment endpoints in a
* hosted Vespa system.
*
- * The one stop shop for all your routing needs!
+ * The one-stop shop for all your routing needs!
*
* @author mpolden
*/
@@ -168,8 +168,8 @@ public class RoutingController {
}
// Add wildcard names for zone endpoints
- builders.add(Endpoint.of(deployment.applicationId()).target(ClusterSpec.Id.from("default"), deployment.zoneId()));
- builders.add(Endpoint.of(deployment.applicationId()).wildcard(deployment.zoneId()));
+ builders.add(Endpoint.of(deployment.applicationId()).target(ClusterSpec.Id.from("default"), deployment));
+ builders.add(Endpoint.of(deployment.applicationId()).wildcard(deployment));
// Build all endpoints
for (var builder : builders) {
@@ -256,8 +256,9 @@ public class RoutingController {
containerEndpoints.add(new ContainerEndpoint(assignedRotation.clusterId().value(), names));
}
// Add endpoints not backed by a rotation
+ DeploymentId deployment = new DeploymentId(instance.id(), zone);
endpoints.not().requiresRotation()
- .targets(zone)
+ .targets(deployment)
.groupingBy(Endpoint::cluster)
.forEach((clusterId, clusterEndpoints) -> {
containerEndpoints.add(new ContainerEndpoint(clusterId.value(),
@@ -330,28 +331,28 @@ public class RoutingController {
var directMethods = 0;
var zones = deployments.stream().map(DeploymentId::zoneId).collect(Collectors.toList());
var availableRoutingMethods = routingMethodsOfAll(deployments, deploymentSpec);
- boolean legacyNamesAvailable = legacyNamesAvailable(deploymentSpec, routingId.application().instance());
+ boolean legacyNamesAvailable = legacyNamesAvailable(deploymentSpec, routingId.instance().instance());
for (var method : availableRoutingMethods) {
if (method.isDirect() && ++directMethods > 1) {
throw new IllegalArgumentException("Invalid routing methods for " + routingId + ": Exceeded maximum " +
"direct methods");
}
- endpoints.add(Endpoint.of(routingId.application())
- .target(routingId.endpointId(), cluster, zones)
+ endpoints.add(Endpoint.of(routingId.instance())
+ .target(routingId.endpointId(), cluster, deployments)
.on(Port.fromRoutingMethod(method))
.routingMethod(method)
.in(controller.system()));
// Add legacy endpoints
if (legacyNamesAvailable && method == RoutingMethod.shared) {
- endpoints.add(Endpoint.of(routingId.application())
- .target(routingId.endpointId(), cluster, zones)
+ endpoints.add(Endpoint.of(routingId.instance())
+ .target(routingId.endpointId(), cluster, deployments)
.on(Port.plain(4080))
.legacy()
.routingMethod(method)
.in(controller.system()));
- endpoints.add(Endpoint.of(routingId.application())
- .target(routingId.endpointId(), cluster, zones)
+ endpoints.add(Endpoint.of(routingId.instance())
+ .target(routingId.endpointId(), cluster, deployments)
.on(Port.tls(4443))
.legacy()
.routingMethod(method)
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 5e458a051b6..3102c247cca 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
@@ -13,6 +13,7 @@ import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
import java.net.URI;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;
@@ -36,28 +37,52 @@ public class Endpoint {
private final EndpointId id;
private final ClusterSpec.Id cluster;
private final URI url;
- private final List<ZoneId> zones;
+ private final List<Target> targets;
private final Scope scope;
private final boolean legacy;
private final RoutingMethod routingMethod;
private final boolean tls;
- private Endpoint(EndpointId id, ClusterSpec.Id cluster, URI url, List<ZoneId> zones, Scope scope, Port port, boolean legacy, RoutingMethod routingMethod) {
+ 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) {
+ Objects.requireNonNull(application, "application must be non-null");
+ Objects.requireNonNull(instanceName, "instanceName must be non-null");
Objects.requireNonNull(cluster, "cluster must be non-null");
- Objects.requireNonNull(zones, "zones must be non-null");
+ Objects.requireNonNull(targets, "deployment must be non-null");
Objects.requireNonNull(scope, "scope must be non-null");
Objects.requireNonNull(port, "port must be non-null");
Objects.requireNonNull(routingMethod, "routingMethod must be non-null");
- if (scope == Scope.global) {
- if (id == null) throw new IllegalArgumentException("Endpoint ID must be set for global endpoints");
+ if (scope.multiRegion()) {
+ if (id == null) throw new IllegalArgumentException("Endpoint ID must be set for multi-region endpoints");
} else {
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");
+ if (targets.size() != 1) throw new IllegalArgumentException("A single target must be given for " + scope + " endpoints");
+ }
+ if (scope != Scope.application && instanceName.isEmpty()) {
+ throw new IllegalArgumentException("Instance must be set for scope " + scope);
+ }
+ for (var target : targets) {
+ if (scope == Scope.application) {
+ TenantAndApplicationId owner = TenantAndApplicationId.from(target.deployment().applicationId());
+ if (!owner.equals(application)) {
+ throw new IllegalArgumentException(id + " has target owned by " + owner +
+ ", which does not match application of this endpoint: " +
+ application);
+ }
+ } else {
+ ApplicationId owner = target.deployment.applicationId();
+ ApplicationId instance = application.instance(instanceName.get());
+ if (!owner.equals(instance)) {
+ throw new IllegalArgumentException(id + " has target owned by " + owner +
+ ", which does not match instance of this endpoint: " + instance);
+ }
+ }
}
this.id = id;
this.cluster = cluster;
this.url = url;
- this.zones = List.copyOf(zones);
+ this.targets = List.copyOf(targets);
this.scope = scope;
this.legacy = legacy;
this.routingMethod = routingMethod;
@@ -65,20 +90,22 @@ public class Endpoint {
}
private Endpoint(EndpointId id, ClusterSpec.Id cluster, TenantAndApplicationId application,
- Optional<InstanceName> instance, List<ZoneId> zones, Scope scope, SystemName system, Port port,
+ Optional<InstanceName> instance, List<Target> targets, Scope scope, SystemName system, Port port,
boolean legacy, RoutingMethod routingMethod) {
- this(id,
+ this(application,
+ instance,
+ id,
cluster,
createUrl(endpointOrClusterAsString(id, cluster),
Objects.requireNonNull(application, "application must be non-null"),
Objects.requireNonNull(instance, "instance must be non-null"),
- zones,
+ targets,
scope,
Objects.requireNonNull(system, "system must be non-null"),
Objects.requireNonNull(port, "port must be non-null"),
legacy,
routingMethod),
- zones, scope, port, legacy, routingMethod);
+ targets, scope, port, legacy, routingMethod);
}
/**
@@ -108,9 +135,14 @@ public class Endpoint {
return url.getAuthority().replaceAll(":.*", "");
}
- /** Returns the zone(s) to which this routes traffic */
- public List<ZoneId> zones() {
- return zones;
+ /** Returns the target(s) to which this routes traffic */
+ public List<Target> targets() {
+ return targets;
+ }
+
+ /** Returns the deployments(s) to which this routes traffic */
+ public List<DeploymentId> deployments() {
+ return targets.stream().map(Target::deployment).collect(Collectors.toUnmodifiableList());
}
/** Returns the scope of this */
@@ -168,7 +200,7 @@ public class Endpoint {
}
private static URI createUrl(String name, TenantAndApplicationId application, Optional<InstanceName> instance,
- List<ZoneId> zones, Scope scope, SystemName system, Port port, boolean legacy,
+ List<Target> targets, Scope scope, SystemName system, Port port, boolean legacy,
RoutingMethod routingMethod) {
String scheme = port.tls ? "https" : "http";
String separator = separator(system, routingMethod, port.tls);
@@ -181,7 +213,7 @@ public class Endpoint {
separator +
sanitize(application.tenant().value()) +
"." +
- scopePart(scope, zones, system, legacy) +
+ scopePart(scope, targets, system, legacy) +
dnsSuffix(system, legacy) +
portPart +
"/");
@@ -203,11 +235,11 @@ public class Endpoint {
return name + separator;
}
- private static String scopePart(Scope scope, List<ZoneId> zones, SystemName system, boolean legacy) {
+ private static String scopePart(Scope scope, List<Target> targets, SystemName system, boolean legacy) {
String scopeSymbol = scopeSymbol(scope, system);
if (scope.multiRegion()) return scopeSymbol;
- ZoneId zone = zones.get(0);
+ ZoneId zone = targets.get(0).deployment().zoneId();
String region = zone.region().value();
boolean skipEnvironment = zone.environment().isProduction() && (system.isPublic() || !legacy);
String environment = skipEnvironment ? "" : "." + zone.environment().value();
@@ -405,7 +437,43 @@ public class Endpoint {
if (!systemApplication.hasEndpoint()) throw new IllegalArgumentException(systemApplication + " has no endpoint");
RoutingMethod routingMethod = RoutingMethod.exclusive;
Port port = url.getPort() == -1 ? Port.tls() : Port.tls(url.getPort()); // System application endpoints are always TLS
- return new Endpoint(null, ClusterSpec.Id.from("admin"), url, List.of(zone), Scope.zone, port, false, routingMethod);
+ return new Endpoint(TenantAndApplicationId.from(systemApplication.id()),
+ Optional.of(systemApplication.id().instance()),
+ null,
+ ClusterSpec.Id.from("admin"),
+ url,
+ List.of(new Target(new DeploymentId(systemApplication.id(), zone))),
+ Scope.zone, port, false, routingMethod);
+ }
+
+ /** A target of an endpoint */
+ public static class Target {
+
+ private final DeploymentId deployment;
+ private final int weight;
+
+ private Target(DeploymentId deployment, int weight) {
+ this.deployment = Objects.requireNonNull(deployment);
+ this.weight = weight;
+ if (weight < 0 || weight > 100) {
+ throw new IllegalArgumentException("Endpoint target weight must be in range [0, 100], got " + weight);
+ }
+ }
+
+ private Target(DeploymentId deployment) {
+ this(deployment, 1);
+ }
+
+ /** Returns the deployment of this */
+ public DeploymentId deployment() {
+ return deployment;
+ }
+
+ /** Returns the assigned weight of this */
+ public int weight() {
+ return weight;
+ }
+
}
public static class EndpointBuilder {
@@ -414,7 +482,7 @@ public class Endpoint {
private final Optional<InstanceName> instance;
private Scope scope;
- private List<ZoneId> zones;
+ private List<Target> targets;
private ClusterSpec.Id cluster;
private EndpointId endpointId;
private Port port;
@@ -426,12 +494,12 @@ public class Endpoint {
this.instance = Objects.requireNonNull(instance);
}
- /** Sets the zone target for this */
- public EndpointBuilder target(ClusterSpec.Id cluster, ZoneId zone) {
+ /** Sets the deployment target for this */
+ public EndpointBuilder target(ClusterSpec.Id cluster, DeploymentId deployment) {
checkScope();
this.cluster = cluster;
this.scope = Scope.zone;
- this.zones = List.of(zone);
+ this.targets = List.of(new Target(deployment));
return this;
}
@@ -440,12 +508,12 @@ public class Endpoint {
return target(endpointId, ClusterSpec.Id.from("default"), List.of());
}
- /** Sets the global target with given ID, zones and cluster (as defined in deployments.xml) */
- public EndpointBuilder target(EndpointId endpointId, ClusterSpec.Id cluster, List<ZoneId> zones) {
+ /** 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.zones = zones;
+ this.targets = deployments.stream().map(Target::new).collect(Collectors.toUnmodifiableList());
this.scope = Scope.global;
return this;
}
@@ -456,13 +524,18 @@ public class Endpoint {
}
/** Sets the zone wildcard target for this */
- public EndpointBuilder wildcard(ZoneId zone) {
- return target(ClusterSpec.Id.from("*"), zone);
+ public EndpointBuilder wildcard(DeploymentId deployment) {
+ return target(ClusterSpec.Id.from("*"), deployment);
}
- /** Sets the application target with given ID, zones and cluster (as defined in deployments.xml) */
- public EndpointBuilder targetApplication(EndpointId endpointId, ClusterSpec.Id cluster, ZoneId zone) {
- target(endpointId, cluster, List.of(zone));
+ /** 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()
+ .map(kv -> new Target(kv.getKey(), kv.getValue()))
+ .collect(Collectors.toUnmodifiableList());
this.scope = Scope.application;
return this;
}
@@ -472,7 +545,7 @@ public class Endpoint {
checkScope();
this.cluster = cluster;
this.scope = Scope.region;
- this.zones = List.of(effectiveZone(zone));
+ this.targets = List.of(new Target(new DeploymentId(application.instance(instance.get()), effectiveZone(zone))));
return this;
}
@@ -502,7 +575,7 @@ 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, zones, scope, system, port, legacy, routingMethod);
+ return new Endpoint(endpointId, cluster, application, instance, targets, scope, system, port, legacy, routingMethod);
}
private void checkScope() {
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/EndpointId.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/EndpointId.java
index 1f70b33fee4..70b011feb88 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/EndpointId.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/EndpointId.java
@@ -25,9 +25,7 @@ public class EndpointId implements Comparable<EndpointId> {
@Override
public String toString() {
- return "EndpointId{" +
- "id='" + id + '\'' +
- '}';
+ return "endpoint id '" + id + "'";
}
@Override
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/EndpointList.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/EndpointList.java
index 28f6cb8e0d7..1ad315545e3 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/EndpointList.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/EndpointList.java
@@ -3,7 +3,7 @@ package com.yahoo.vespa.hosted.controller.application;
import com.yahoo.collections.AbstractFilteringList;
import com.yahoo.config.provision.ClusterSpec;
-import com.yahoo.config.provision.zone.ZoneId;
+import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
import java.util.Collection;
import java.util.List;
@@ -41,14 +41,14 @@ public class EndpointList extends AbstractFilteringList<Endpoint, EndpointList>
return matching(endpoint -> endpoint.cluster().equals(cluster));
}
- /** Returns the subset of endpoints which target all of the given zones */
- public EndpointList targets(List<ZoneId> zones) {
- return matching(endpoint -> endpoint.zones().containsAll(zones));
+ /** Returns the subset of endpoints which target all of the given deployments */
+ public EndpointList targets(List<DeploymentId> deployments) {
+ return matching(endpoint -> endpoint.deployments().containsAll(deployments));
}
- /** Returns the subset of endpoints which target the given zones */
- public EndpointList targets(ZoneId zone) {
- return targets(List.of(zone));
+ /** Returns the subset of endpoints which target the given deployments */
+ public EndpointList targets(DeploymentId deployment) {
+ return targets(List.of(deployment));
}
/** Returns the subset of endpoints that are considered legacy */
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 b1371989216..87a7d6674b6 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
@@ -1397,7 +1397,7 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
}
// Add global endpoints
EndpointList globalEndpoints = controller.routing().endpointsOf(application, deploymentId.applicationId().instance())
- .targets(deploymentId.zoneId());
+ .targets(deploymentId);
if (!legacyEndpoints) {
globalEndpoints = globalEndpoints.not().legacy();
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/routing/RoutingApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/routing/RoutingApiHandler.java
index f72c911f369..34fcda3bff8 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/routing/RoutingApiHandler.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/routing/RoutingApiHandler.java
@@ -101,9 +101,8 @@ public class RoutingApiHandler extends AuditLoggingRequestHandler {
.asList();
var deployments = endpoints.stream()
- .flatMap(e -> e.zones().stream())
+ .flatMap(e -> e.deployments().stream())
.distinct()
- .map(zoneId -> new DeploymentId(instanceId, zoneId))
.sorted(Comparator.comparing(DeploymentId::dottedString))
.collect(Collectors.toList());
@@ -123,10 +122,9 @@ public class RoutingApiHandler extends AuditLoggingRequestHandler {
var endpointRoot = endpointsRoot.addObject();
endpointToSlime(endpointRoot, endpoint);
var zonesRoot = endpointRoot.setArray("zones");
- endpoint.zones().stream().sorted(Comparator.comparing(ZoneId::value)).forEach(zoneId -> {
- var deploymentId = new DeploymentId(instanceId, zoneId);
- deploymentsStatus.getOrDefault(deploymentId, List.of()).forEach(status -> {
- deploymentStatusToSlime(zonesRoot.addObject(), deploymentId, status, endpoint.routingMethod());
+ endpoint.deployments().stream().sorted(Comparator.comparing(d -> d.zoneId().value())).forEach(deployment -> {
+ deploymentsStatus.getOrDefault(deployment, List.of()).forEach(status -> {
+ deploymentStatusToSlime(zonesRoot.addObject(), deployment, status, endpoint.routingMethod());
});
});
});
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/routing/RoutingId.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/routing/RoutingId.java
index 63829e340d0..343fa5417ce 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/routing/RoutingId.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/routing/RoutingId.java
@@ -7,22 +7,22 @@ import com.yahoo.vespa.hosted.controller.application.EndpointId;
import java.util.Objects;
/**
- * Unique identifier for a global routing table entry (application x endpoint ID).
+ * Unique identifier for a global routing table entry (instance x endpoint ID).
*
* @author mpolden
*/
public class RoutingId {
- private final ApplicationId application;
+ private final ApplicationId instance;
private final EndpointId endpointId;
- public RoutingId(ApplicationId application, EndpointId endpointId) {
- this.application = Objects.requireNonNull(application, "application must be non-null");
+ public RoutingId(ApplicationId instance, EndpointId endpointId) {
+ this.instance = Objects.requireNonNull(instance, "instance must be non-null");
this.endpointId = Objects.requireNonNull(endpointId, "endpointId must be non-null");
}
- public ApplicationId application() {
- return application;
+ public ApplicationId instance() {
+ return instance;
}
public EndpointId endpointId() {
@@ -34,22 +34,22 @@ public class RoutingId {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RoutingId that = (RoutingId) o;
- return application.equals(that.application) &&
+ return instance.equals(that.instance) &&
endpointId.equals(that.endpointId);
}
@Override
public int hashCode() {
- return Objects.hash(application, endpointId);
+ return Objects.hash(instance, endpointId);
}
@Override
public String toString() {
- return "routing id for " + endpointId + " of " + application;
+ return "routing id for " + endpointId + " of " + instance;
}
- public static RoutingId of(ApplicationId application, EndpointId endpoint) {
- return new RoutingId(application, endpoint);
+ public static RoutingId of(ApplicationId instance, EndpointId endpoint) {
+ return new RoutingId(instance, endpoint);
}
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/routing/RoutingPolicies.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/routing/RoutingPolicies.java
index 1fda681e0a6..e0c0df5234e 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/routing/RoutingPolicies.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/routing/RoutingPolicies.java
@@ -124,7 +124,7 @@ public class RoutingPolicies {
Map<RoutingId, List<RoutingPolicy>> routingTable = routingTableFrom(routingPolicies);
for (Map.Entry<RoutingId, List<RoutingPolicy>> routeEntry : routingTable.entrySet()) {
RoutingId routingId = routeEntry.getKey();
- controller.routing().endpointsOf(routingId.application())
+ controller.routing().endpointsOf(routingId.instance())
.named(routingId.endpointId())
.not().requiresRotation()
.forEach(endpoint -> updateGlobalDnsOf(endpoint, inactiveZones, routeEntry.getValue()));
@@ -250,7 +250,7 @@ public class RoutingPolicies {
var activeRoutingIds = routingIdsFrom(allocation);
removalCandidates.removeAll(activeRoutingIds);
for (var id : removalCandidates) {
- var endpoints = controller.routing().endpointsOf(id.application())
+ var endpoints = controller.routing().endpointsOf(id.instance())
.not().requiresRotation()
.named(id.endpointId());
var forwarder = nameServiceForwarderIn(allocation.deployment.zoneId());
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 0faf209ff29..5653b51f6c9 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
@@ -6,6 +6,7 @@ import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.zone.RoutingMethod;
import com.yahoo.text.Text;
+import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneRegistry;
import com.yahoo.vespa.hosted.controller.application.Endpoint;
import com.yahoo.vespa.hosted.controller.application.Endpoint.Port;
@@ -86,15 +87,16 @@ public class RoutingPolicy {
if (infraEndpoint.isPresent()) {
return List.of(infraEndpoint.get());
}
+ DeploymentId deployment = new DeploymentId(id.owner(), id.zone());
List<Endpoint> endpoints = new ArrayList<>();
- endpoints.add(endpoint(routingMethod).target(id.cluster(), id.zone()).in(system));
+ endpoints.add(endpoint(routingMethod).target(id.cluster(), deployment).in(system));
// Add legacy endpoints
if (routingMethod == RoutingMethod.shared) {
- endpoints.add(endpoint(routingMethod).target(id.cluster(), id.zone())
+ endpoints.add(endpoint(routingMethod).target(id.cluster(), deployment)
.on(Port.plain(4080))
.legacy()
.in(system));
- endpoints.add(endpoint(routingMethod).target(id.cluster(), id.zone())
+ endpoints.add(endpoint(routingMethod).target(id.cluster(), deployment)
.on(Port.tls(4443))
.legacy()
.in(system));
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 e2fb70e5338..f8a19a66cd4 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
@@ -150,8 +150,9 @@ public class EndpointTest {
@Test
public void zone_endpoints() {
var cluster = ClusterSpec.Id.from("default"); // Always default for non-direct routing
- var prodZone = ZoneId.from("prod", "us-north-1");
- var testZone = ZoneId.from("test", "us-north-2");
+ var prodZone = new DeploymentId(instance1, ZoneId.from("prod", "us-north-1"));
+ var prodZone2 = new DeploymentId(instance2, ZoneId.from("prod", "us-north-1"));
+ var testZone = new DeploymentId(instance1, ZoneId.from("test", "us-north-2"));
Map<String, Endpoint> tests = Map.of(
// Legacy endpoint (always contains environment)
@@ -180,7 +181,7 @@ public class EndpointTest {
// Non-default instance in main
"https://i2--a2--t2.us-north-1.vespa.oath.cloud:4443/",
- Endpoint.of(instance2).target(cluster, prodZone).on(Port.tls(4443)).in(SystemName.main),
+ Endpoint.of(instance2).target(cluster, prodZone2).on(Port.tls(4443)).in(SystemName.main),
// Non-default cluster in public
"https://c1.a1.t1.us-north-1.z.vespa-app.cloud/",
@@ -188,7 +189,7 @@ public class EndpointTest {
// Non-default cluster and instance in public
"https://c2.i2.a2.t2.us-north-1.z.vespa-app.cloud/",
- Endpoint.of(instance2).target(ClusterSpec.Id.from("c2"), prodZone).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.Public),
+ Endpoint.of(instance2).target(ClusterSpec.Id.from("c2"), prodZone2).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.Public),
// Endpoint in main using shared layer 4
"https://a1.t1.us-north-1.vespa.oath.cloud/",
@@ -199,7 +200,7 @@ public class EndpointTest {
Map<String, Endpoint> tests2 = Map.of(
// Non-default cluster and instance in public CD (legacy)
"https://c2.i2.a2.t2.us-north-1.z.cd.vespa-app.cloud/",
- Endpoint.of(instance2).target(ClusterSpec.Id.from("c2"), prodZone).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.PublicCd),
+ Endpoint.of(instance2).target(ClusterSpec.Id.from("c2"), prodZone2).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.PublicCd),
// Custom cluster name in public
"https://c1.a1.t1.us-north-1.z.vespa-app.cloud/",
@@ -219,8 +220,8 @@ public class EndpointTest {
@Test
public void wildcard_endpoints() {
var defaultCluster = ClusterSpec.Id.from("default");
- var prodZone = ZoneId.from("prod", "us-north-1");
- var testZone = ZoneId.from("test", "us-north-2");
+ var prodZone = new DeploymentId(instance1, ZoneId.from("prod", "us-north-1"));
+ var testZone = new DeploymentId(instance1, ZoneId.from("test", "us-north-2"));
var tests = Map.of(
// Default rotation
@@ -307,7 +308,7 @@ public class EndpointTest {
.in(SystemName.main);
assertEquals("Availability zone is removed from region",
"us-north-1",
- endpoint.zones().get(0).region().value());
+ endpoint.targets().get(0).deployment().zoneId().region().value());
}
@Test
@@ -316,28 +317,28 @@ public class EndpointTest {
"https://weighted.a1.t1.a.vespa-app.cloud/",
Endpoint.of(app1)
.targetApplication(EndpointId.of("weighted"), ClusterSpec.Id.from("qrs"),
- ZoneId.from("prod", "us-west-1"))
+ Map.of(new DeploymentId(app1.instance("i1"), ZoneId.from("prod", "us-west-1")), 1))
.routingMethod(RoutingMethod.exclusive)
.on(Port.tls())
.in(SystemName.Public),
"https://weighted.a1.t1.a.cd.vespa-app.cloud/",
Endpoint.of(app1)
.targetApplication(EndpointId.of("weighted"), ClusterSpec.Id.from("qrs"),
- ZoneId.from("prod", "us-west-1"))
+ Map.of(new DeploymentId(app1.instance("i1"), ZoneId.from("prod", "us-west-1")), 1))
.routingMethod(RoutingMethod.exclusive)
.on(Port.tls())
.in(SystemName.PublicCd),
"https://a2.t2.a.vespa.oath.cloud/",
Endpoint.of(app2)
.targetApplication(EndpointId.defaultId(), ClusterSpec.Id.from("qrs"),
- ZoneId.from("prod", "us-east-3"))
+ Map.of(new DeploymentId(app2.instance("i1"), ZoneId.from("prod", "us-east-3")), 1))
.routingMethod(RoutingMethod.exclusive)
.on(Port.tls())
.in(SystemName.main),
"https://cd.a2.t2.a.vespa.oath.cloud/",
Endpoint.of(app2)
.targetApplication(EndpointId.defaultId(), ClusterSpec.Id.from("qrs"),
- ZoneId.from("prod", "us-east-3"))
+ Map.of(new DeploymentId(app2.instance("i1"), ZoneId.from("prod", "us-east-3")), 1))
.routingMethod(RoutingMethod.exclusive)
.on(Port.tls())
.in(SystemName.cd)
@@ -347,7 +348,8 @@ public class EndpointTest {
@Test
public void upstream_name() {
- var zone = ZoneId.from("prod", "us-north-1");
+ var zone = new DeploymentId(instance1, ZoneId.from("prod", "us-north-1"));
+ var zone2 = new DeploymentId(instance2, ZoneId.from("prod", "us-north-1"));
var tests1 = Map.of(
// With default cluster
"a1.t1.us-north-1.prod",
@@ -359,7 +361,7 @@ public class EndpointTest {
// With application endpoint
"c2.a1.t1.us-north-1.prod",
- Endpoint.of(app1).targetApplication(EndpointId.defaultId(), ClusterSpec.Id.from("c2"), zone)
+ Endpoint.of(app1).targetApplication(EndpointId.defaultId(), ClusterSpec.Id.from("c2"), Map.of(new DeploymentId(app1.instance("i1"), zone.zoneId()), 1))
.routingMethod(RoutingMethod.sharedLayer4)
.on(Port.tls())
.in(SystemName.main)
@@ -367,14 +369,14 @@ public class EndpointTest {
var tests2 = Map.of(
// With non-default instance and default cluster
"i2.a2.t2.us-north-1.prod",
- Endpoint.of(instance2).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(zone2)).on(Port.tls(4443)).in(SystemName.main),
// With non-default instance and cluster
"c2.i2.a2.t2.us-north-1.prod",
- Endpoint.of(instance2).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(zone2)).on(Port.tls(4443)).in(SystemName.main)
);
- tests1.forEach((expected, endpoint) -> assertEquals(expected, endpoint.upstreamIdOf(new DeploymentId(instance1, zone))));
- tests2.forEach((expected, endpoint) -> assertEquals(expected, endpoint.upstreamIdOf(new DeploymentId(instance2, zone))));
+ tests1.forEach((expected, endpoint) -> assertEquals(expected, endpoint.upstreamIdOf(zone)));
+ tests2.forEach((expected, endpoint) -> assertEquals(expected, endpoint.upstreamIdOf(zone2)));
}
}
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 b303a404ec2..e8bc286ed37 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
@@ -819,11 +819,11 @@ public class RoutingPoliciesTest {
.collect(Collectors.toList());
}
- private void assertTargets(ApplicationId application, EndpointId endpointId, ClusterSpec.Id cluster, int loadBalancerId, Map<ZoneId, Long> zoneWeights) {
+ private void assertTargets(ApplicationId instance, EndpointId endpointId, ClusterSpec.Id cluster, int loadBalancerId, Map<ZoneId, Long> zoneWeights) {
Set<String> latencyTargets = new HashSet<>();
Map<String, List<ZoneId>> zonesByRegionEndpoint = new HashMap<>();
for (var zone : zoneWeights.keySet()) {
- DeploymentId deployment = new DeploymentId(application, zone);
+ DeploymentId deployment = new DeploymentId(instance, zone);
EndpointList regionEndpoints = tester.controller().routing().endpointsOf(deployment)
.cluster(cluster)
.scope(Endpoint.Scope.region);
@@ -834,7 +834,7 @@ public class RoutingPoliciesTest {
zonesByRegionEndpoint.forEach((regionEndpoint, zonesInRegion) -> {
Set<String> weightedTargets = zonesInRegion.stream()
.map(z -> "weighted/lb-" + loadBalancerId + "--" +
- application.serializedForm() + "--" + z.value() +
+ instance.serializedForm() + "--" + z.value() +
"/dns-zone-1/" + z.value() + "/" + zoneWeights.get(z))
.collect(Collectors.toSet());
assertEquals("Region endpoint " + regionEndpoint + " points to load balancer",
@@ -844,9 +844,10 @@ public class RoutingPoliciesTest {
String latencyTarget = "latency/" + regionEndpoint + "/dns-zone-1/" + zone.value();
latencyTargets.add(latencyTarget);
});
- String globalEndpoint = tester.controller().routing().endpointsOf(application)
+ List<DeploymentId> deployments = zoneWeights.keySet().stream().map(z -> new DeploymentId(instance, z)).collect(Collectors.toList());
+ String globalEndpoint = tester.controller().routing().endpointsOf(instance)
.named(endpointId)
- .targets(List.copyOf(zoneWeights.keySet()))
+ .targets(deployments)
.primary()
.map(Endpoint::dnsName)
.orElse("<none>");