summaryrefslogtreecommitdiffstats
path: root/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Endpoint.java
diff options
context:
space:
mode:
Diffstat (limited to 'controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Endpoint.java')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Endpoint.java126
1 files changed, 61 insertions, 65 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 62804074337..aaaeb4218ec 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
@@ -17,8 +17,8 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
- * Represents an application's endpoint. The endpoint scope can either be global or a specific zone. This is visible to
- * the tenant and is used by the tenant when accessing deployments.
+ * Represents an application's endpoint in hosted Vespa. This encapsulates all logic for building URLs and DNS names for
+ * application endpoints.
*
* @author mpolden
*/
@@ -29,7 +29,8 @@ public class Endpoint {
private static final String PUBLIC_DNS_SUFFIX = ".public.vespa.oath.cloud";
private static final String PUBLIC_CD_DNS_SUFFIX = ".public-cd.vespa.oath.cloud";
- private final String name;
+ private final EndpointId id;
+ private final ClusterSpec.Id cluster;
private final URI url;
private final List<ZoneId> zones;
private final Scope scope;
@@ -37,16 +38,20 @@ public class Endpoint {
private final RoutingMethod routingMethod;
private final boolean tls;
- private Endpoint(String name, URI url, List<ZoneId> zones, Scope scope, Port port, boolean legacy, RoutingMethod routingMethod) {
- Objects.requireNonNull(name, "name must be non-null");
+ private Endpoint(EndpointId id, ClusterSpec.Id cluster, URI url, List<ZoneId> zones, Scope scope, Port port, boolean legacy, RoutingMethod routingMethod) {
+ Objects.requireNonNull(cluster, "cluster must be non-null");
Objects.requireNonNull(zones, "zones 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.zone || scope == Scope.weighted) && zones.size() != 1) {
- throw new IllegalArgumentException("A single zone must be given for " + scope + "-scoped endpoints");
+ 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 (zones.size() != 1) throw new IllegalArgumentException("A single zone must be given for " + scope + " endpoints");
}
- this.name = name;
+ this.id = id;
+ this.cluster = cluster;
this.url = url;
this.zones = List.copyOf(zones);
this.scope = scope;
@@ -55,10 +60,11 @@ public class Endpoint {
this.tls = port.tls;
}
- private Endpoint(String name, ApplicationId application, List<ZoneId> zones, Scope scope, SystemName system,
+ private Endpoint(EndpointId id, ClusterSpec.Id cluster, ApplicationId application, List<ZoneId> zones, Scope scope, SystemName system,
Port port, boolean legacy, RoutingMethod routingMethod) {
- this(name,
- createUrl(name,
+ this(id,
+ cluster,
+ createUrl(endpointOrClusterAsString(id, cluster),
Objects.requireNonNull(application, "application must be non-null"),
zones,
scope,
@@ -70,14 +76,19 @@ public class Endpoint {
}
/**
- * Returns the name of this endpoint (the first component of the DNS name). Depending on the endpoint type, this
- * can be one of the following:
- * - A wildcard (any scope)
- * - A cluster name (only zone scope)
- * - An endpoint ID (only global scope)
+ * Returns the name of this endpoint (the first component of the DNS name). This can be one of the following:
+ *
+ * - The wildcard character '*' (for wildcard endpoints, with any scope)
+ * - The cluster ID (zone scope)
+ * - The endpoint ID (global scope)
*/
public String name() {
- return name;
+ return endpointOrClusterAsString(id, cluster);
+ }
+
+ /** Returns the cluster ID to which this routes traffic */
+ public ClusterSpec.Id cluster() {
+ return cluster;
}
/** Returns the URL used to access this */
@@ -106,7 +117,7 @@ public class Endpoint {
return legacy;
}
- /** Returns the routing used for this */
+ /** Returns the routing method used for this */
public RoutingMethod routingMethod() {
return routingMethod;
}
@@ -125,7 +136,7 @@ public class Endpoint {
public String upstreamIdOf(DeploymentId deployment) {
if (scope != Scope.global) throw new IllegalArgumentException("Scope " + scope + " does not have upstream name");
if (!routingMethod.isShared()) throw new IllegalArgumentException("Routing method " + routingMethod + " does not have upstream name");
- return upstreamIdOf(name, deployment.applicationId(), deployment.zoneId());
+ return upstreamIdOf(name(), deployment.applicationId(), deployment.zoneId());
}
@Override
@@ -151,6 +162,10 @@ public class Endpoint {
return dnsSuffix(system, false);
}
+ private static String endpointOrClusterAsString(EndpointId id, ClusterSpec.Id cluster) {
+ 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) {
String scheme = port.tls ? "https" : "http";
@@ -323,7 +338,7 @@ 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("", url, List.of(zone), Scope.zone, port, false, routingMethod);
+ return new Endpoint(null, ClusterSpec.Id.from("admin"), url, List.of(zone), Scope.zone, port, false, routingMethod);
}
public static class EndpointBuilder {
@@ -337,60 +352,55 @@ public class Endpoint {
private Port port;
private RoutingMethod routingMethod = RoutingMethod.shared;
private boolean legacy = false;
- private boolean wildcard = false;
private EndpointBuilder(ApplicationId application) {
this.application = application;
}
- /** Sets the cluster target for this */
+ /** Sets the zone target for this */
public EndpointBuilder target(ClusterSpec.Id cluster, ZoneId zone) {
- if (endpointId != null || wildcard) {
- throw new IllegalArgumentException("Cannot set multiple target types");
- }
+ checkScope();
this.cluster = cluster;
this.scope = Scope.zone;
this.zones = List.of(zone);
return this;
}
- /** Sets the endpoint target ID for this (as defined in deployments.xml) */
- public EndpointBuilder named(EndpointId endpointId) {
- return named(endpointId, List.of());
+ /** 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 endpoint ID for this (as defined in deployments.xml) */
- public EndpointBuilder named(EndpointId endpointId, List<ZoneId> targets) {
- if (cluster != null || wildcard) {
- throw new IllegalArgumentException("Cannot set multiple target types");
- }
+ /** 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) {
+ checkScope();
this.endpointId = endpointId;
- this.zones = targets;
+ this.cluster = cluster;
+ this.zones = zones;
this.scope = Scope.global;
return this;
}
/** Sets the global wildcard target for this */
public EndpointBuilder wildcard() {
- return wildcard(Scope.global, List.of());
+ return target(EndpointId.of("*"), ClusterSpec.Id.from("*"), List.of());
}
/** Sets the zone wildcard target for this */
public EndpointBuilder wildcard(ZoneId zone) {
- return wildcard(Scope.zone, List.of(zone));
+ return target(ClusterSpec.Id.from("*"), zone);
}
- private EndpointBuilder wildcard(Scope scope, List<ZoneId> zones) {
- if (endpointId != null || cluster != null) {
- throw new IllegalArgumentException("Cannot set multiple target types");
- }
- this.wildcard = true;
- this.scope = scope;
- this.zones = zones;
+ /** Sets the weighted target for this */
+ public EndpointBuilder weighted(ClusterSpec.Id cluster, ZoneId zone) {
+ checkScope();
+ this.cluster = cluster;
+ this.scope = Scope.weighted;
+ this.zones = List.of(effectiveZone(zone));
return this;
}
- /** Sets the port of this */
+ /** Sets the port of this */
public EndpointBuilder on(Port port) {
this.port = port;
return this;
@@ -408,35 +418,21 @@ public class Endpoint {
return this;
}
- /** Make this a weighted endpoint */
- public EndpointBuilder weighted() {
- if (scope != Scope.zone && scope != Scope.weighted) {
- throw new IllegalArgumentException("Endpoint must target zone before making it weighted");
- }
- this.scope = Scope.weighted;
- this.zones = List.of(effectiveZone(zones.get(0)));
- return this;
- }
-
/** Sets the system that owns this */
public Endpoint in(SystemName system) {
- String name;
- if (wildcard) {
- name = "*";
- } else if (endpointId != null) {
- name = endpointId.id();
- } else if (cluster != null) {
- name = cluster.value();
- } else {
- throw new IllegalArgumentException("Must set either cluster, rotation or wildcard target");
- }
if (system.isPublic() && routingMethod != RoutingMethod.exclusive) {
throw new IllegalArgumentException("Public system only supports routing method " + RoutingMethod.exclusive);
}
if (routingMethod.isDirect() && !port.isDefault()) {
throw new IllegalArgumentException("Routing method " + routingMethod + " can only use default port");
}
- return new Endpoint(name, application, zones, scope, system, port, legacy, routingMethod);
+ return new Endpoint(endpointId, cluster, application, zones, scope, system, port, legacy, routingMethod);
+ }
+
+ private void checkScope() {
+ if (scope != null) {
+ throw new IllegalArgumentException("Cannot change endpoint scope. Already set to " + scope);
+ }
}
}