aboutsummaryrefslogtreecommitdiffstats
path: root/controller-server/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'controller-server/src/main/java')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/RoutingController.java41
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Endpoint.java56
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java1
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/EnclaveAccessMaintainer.java43
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/routing/RoutingPolicies.java48
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/routing/RoutingPolicy.java8
6 files changed, 137 insertions, 60 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 38c06e4dac2..84aa26b93f3 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
@@ -20,6 +20,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.dns.RecordData;
import com.yahoo.vespa.hosted.controller.api.integration.dns.RecordName;
import com.yahoo.vespa.hosted.controller.application.Endpoint;
import com.yahoo.vespa.hosted.controller.application.Endpoint.Port;
+import com.yahoo.vespa.hosted.controller.application.Endpoint.Scope;
import com.yahoo.vespa.hosted.controller.application.EndpointId;
import com.yahoo.vespa.hosted.controller.application.EndpointList;
import com.yahoo.vespa.hosted.controller.application.SystemApplication;
@@ -115,7 +116,7 @@ public class RoutingController {
if (!policy.status().isActive()) continue;
RoutingMethod routingMethod = controller.zoneRegistry().routingMethod(policy.id().zone());
endpoints.addAll(policy.zoneEndpointsIn(controller.system(), routingMethod, controller.zoneRegistry()));
- endpoints.add(policy.regionEndpointIn(controller.system(), routingMethod));
+ endpoints.add(policy.regionEndpointIn(controller.system(), routingMethod, controller.zoneRegistry()));
}
return EndpointList.copyOf(endpoints);
}
@@ -158,23 +159,21 @@ public class RoutingController {
}
// Add application endpoints
for (var declaredEndpoint : deploymentSpec.endpoints()) {
- Map<ZoneId, Map<DeploymentId, Integer>> deployments = declaredEndpoint.targets().stream()
- .collect(groupingBy(t -> ZoneId.from(Environment.prod, t.region()),
- toMap(t -> new DeploymentId(application.id().instance(t.instance()),
- ZoneId.from(Environment.prod, t.region())),
- t -> t.weight())));
-
- deployments.forEach((zone, weightedInstances) -> {
- // Application endpoints are only supported when using direct routing methods
- RoutingMethod routingMethod = usesSharedRouting(zone) ? RoutingMethod.sharedLayer4 : RoutingMethod.exclusive;
- endpoints.add(Endpoint.of(application.id())
- .targetApplication(EndpointId.of(declaredEndpoint.endpointId()),
- ClusterSpec.Id.from(declaredEndpoint.containerId()),
- weightedInstances)
- .routingMethod(routingMethod)
- .on(Port.fromRoutingMethod(routingMethod))
- .in(controller.system()));
- });
+ Map<DeploymentId, Integer> deployments = declaredEndpoint.targets().stream()
+ .collect(toMap(t -> new DeploymentId(application.id().instance(t.instance()),
+ ZoneId.from(Environment.prod, t.region())),
+ t -> t.weight()));
+
+ ZoneId zone = deployments.keySet().iterator().next().zoneId(); // Where multiple zones are possible, they all have the same routing method.
+ // Application endpoints are only supported when using direct routing methods
+ RoutingMethod routingMethod = usesSharedRouting(zone) ? RoutingMethod.sharedLayer4 : RoutingMethod.exclusive;
+ endpoints.add(Endpoint.of(application.id())
+ .targetApplication(EndpointId.of(declaredEndpoint.endpointId()),
+ ClusterSpec.Id.from(declaredEndpoint.containerId()),
+ deployments)
+ .routingMethod(routingMethod)
+ .on(Port.fromRoutingMethod(routingMethod))
+ .in(controller.system()));
}
return EndpointList.copyOf(endpoints);
}
@@ -236,6 +235,7 @@ public class RoutingController {
.on(Port.tls())
.in(controller.system());
endpointDnsNames.add(endpoint.dnsName());
+ if (endpoint.scope() == Scope.application) endpointDnsNames.add(endpoint.legacyRegionalDnsName());
}
return Collections.unmodifiableList(endpointDnsNames);
}
@@ -313,6 +313,9 @@ public class RoutingController {
controller.nameServiceForwarder().createRecord(
new Record(Record.Type.CNAME, RecordName.from(endpoint.dnsName()), RecordData.fqdn(vipHostname)),
Priority.normal);
+ controller.nameServiceForwarder().createRecord(
+ new Record(Record.Type.CNAME, RecordName.from(endpoint.legacyRegionalDnsName()), RecordData.fqdn(vipHostname)),
+ Priority.normal);
}
Map<ClusterSpec.Id, EndpointList> applicationEndpointsByCluster = applicationEndpoints.groupingBy(Endpoint::cluster);
for (var kv : applicationEndpointsByCluster.entrySet()) {
@@ -325,7 +328,7 @@ public class RoutingController {
if (matchingTarget.isEmpty()) throw new IllegalStateException("No target found routing to " + deployment + " in " + endpoint);
containerEndpoints.add(new ContainerEndpoint(clusterId.value(),
asString(Endpoint.Scope.application),
- List.of(endpoint.dnsName()),
+ List.of(endpoint.dnsName(), endpoint.legacyRegionalDnsName()),
OptionalInt.of(matchingTarget.get().weight()),
endpoint.routingMethod()));
}
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 88366466289..cbac700a9a0 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
@@ -20,9 +20,11 @@ import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import static java.util.Comparator.comparing;
+
/**
* Represents an application or instance endpoint in hosted Vespa.
- *
+ * <p>
* This encapsulates the logic for building URLs and DNS names for applications in all hosted Vespa systems.
*
* @author mpolden
@@ -38,13 +40,14 @@ public class Endpoint {
private final ClusterSpec.Id cluster;
private final Optional<InstanceName> instance;
private final URI url;
+ private final URI legacyRegionalUrl;
private final List<Target> targets;
private final Scope scope;
private final boolean legacy;
private final 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,
+ ClusterSpec.Id cluster, URI url, URI legacyRegionalUrl, List<Target> targets, Scope scope, Port port, boolean legacy,
RoutingMethod routingMethod, boolean certificateName) {
Objects.requireNonNull(application, "application must be non-null");
Objects.requireNonNull(instanceName, "instanceName must be non-null");
@@ -58,6 +61,7 @@ public class Endpoint {
this.cluster = requireCluster(cluster, certificateName);
this.instance = requireInstance(instanceName, scope);
this.url = url;
+ this.legacyRegionalUrl = legacyRegionalUrl;
this.targets = List.copyOf(requireTargets(targets, application, instanceName, scope, certificateName));
this.scope = requireScope(scope, routingMethod);
this.legacy = legacy;
@@ -96,6 +100,12 @@ public class Endpoint {
return url.getAuthority().replaceAll(":.*", "");
}
+ /** Returns the legacy DNS name with region, for application endpoints */
+ public String legacyRegionalDnsName() {
+ if (scope != Scope.application) throw new IllegalStateException("legacy regional URL is only for application scope endpoints, not " + this);
+ return legacyRegionalUrl.getAuthority().replaceAll(":.*", "");
+ }
+
/** Returns the target(s) to which this routes traffic */
public List<Target> targets() {
return targets;
@@ -160,7 +170,8 @@ public class Endpoint {
}
private static URI createUrl(String name, TenantAndApplicationId application, Optional<InstanceName> instance,
- List<Target> targets, Scope scope, SystemName system, Port port, boolean legacy) {
+ List<Target> targets, Scope scope, SystemName system, Port port, boolean legacyRegionalUrl) {
+
String separator = ".";
String portPart = port.isDefault() ? "" : ":" + port.port;
return URI.create("https://" +
@@ -171,8 +182,8 @@ public class Endpoint {
separator +
sanitize(application.tenant().value()) +
"." +
- scopePart(scope, targets, system, legacy) +
- dnsSuffix(system, legacy) +
+ scopePart(scope, targets, system, legacyRegionalUrl) +
+ dnsSuffix(system) +
portPart +
"/");
}
@@ -186,13 +197,14 @@ public class Endpoint {
return name + separator;
}
- private static String scopePart(Scope scope, List<Target> targets, SystemName system, boolean legacy) {
- String scopeSymbol = scopeSymbol(scope, system);
+ private static String scopePart(Scope scope, List<Target> targets, SystemName system, boolean legacyRegion) {
+ String scopeSymbol = scopeSymbol(scope, system, legacyRegion);
if (scope == Scope.global) return scopeSymbol;
+ if (scope == Scope.application && ! legacyRegion) return scopeSymbol;
- ZoneId zone = targets.get(0).deployment().zoneId();
+ ZoneId zone = targets.stream().map(target -> target.deployment.zoneId()).min(comparing(ZoneId::value)).get();
String region = zone.region().value();
- boolean skipEnvironment = zone.environment().isProduction() && (system.isPublic() || !legacy);
+ boolean skipEnvironment = zone.environment().isProduction();
String environment = skipEnvironment ? "" : "." + zone.environment().value();
if (system.isPublic()) {
return region + environment + "." + scopeSymbol;
@@ -200,20 +212,21 @@ public class Endpoint {
return region + (scopeSymbol.isEmpty() ? "" : "-" + scopeSymbol) + environment;
}
- private static String scopeSymbol(Scope scope, SystemName system) {
+ private static String scopeSymbol(Scope scope, SystemName system, boolean legacyRegion) {
+ if (legacyRegion) return "r";
if (system.isPublic()) {
return switch (scope) {
case zone -> "z";
case weighted -> "w";
case global -> "g";
- case application -> "r";
+ case application -> "a";
};
}
return switch (scope) {
case zone -> "";
case weighted -> "w";
case global -> "global";
- case application -> "r";
+ case application -> "a";
};
}
@@ -230,18 +243,15 @@ public class Endpoint {
}
/** Returns the DNS suffix used for endpoints in given system */
- private static String dnsSuffix(SystemName system, boolean legacy) {
+ private static String dnsSuffix(SystemName system) {
switch (system) {
case cd, main -> {
- if (legacy) return YAHOO_DNS_SUFFIX;
return OATH_DNS_SUFFIX;
}
case Public -> {
- if (legacy) throw new IllegalArgumentException("No legacy DNS suffix declared for system " + system);
return PUBLIC_DNS_SUFFIX;
}
case PublicCd -> {
- if (legacy) throw new IllegalArgumentException("No legacy DNS suffix declared for system " + system);
return PUBLIC_CD_DNS_SUFFIX;
}
default -> throw new IllegalArgumentException("No DNS suffix declared for system " + system);
@@ -250,7 +260,7 @@ public class Endpoint {
/** Returns the DNS suffix used for internal names (i.e. names not exposed to tenants) in given system */
public static String internalDnsSuffix(SystemName system) {
- String suffix = dnsSuffix(system, false);
+ String suffix = dnsSuffix(system);
if (system.isPublic()) {
// Certificate provider requires special approval for three-level DNS names, e.g. foo.vespa-app.cloud.
// To avoid this in public we always add an extra level.
@@ -578,12 +588,22 @@ public class Endpoint {
Objects.requireNonNull(scope, "scope must be non-null"),
Objects.requireNonNull(system, "system must be non-null"),
Objects.requireNonNull(port, "port must be non-null"),
- legacy);
+ false);
+ URI legacyRegionalUrl = scope != Scope.application ? null
+ : createUrl(endpointOrClusterAsString(endpointId, cluster),
+ Objects.requireNonNull(application, "application must be non-null"),
+ Objects.requireNonNull(instance, "instance must be non-null"),
+ Objects.requireNonNull(targets, "targets must be non-null"),
+ Objects.requireNonNull(scope, "scope must be non-null"),
+ Objects.requireNonNull(system, "system must be non-null"),
+ Objects.requireNonNull(port, "port must be non-null"),
+ true);
return new Endpoint(application,
instance,
endpointId,
cluster,
url,
+ legacyRegionalUrl,
targets,
scope,
port,
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java
index 9c6ab32a338..89ca31105bb 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java
@@ -78,6 +78,7 @@ public class ControllerMaintenance extends AbstractComponent {
maintainers.add(new UserManagementMaintainer(controller, intervals.userManagementMaintainer, controller.serviceRegistry().roleMaintainer()));
maintainers.add(new BillingDatabaseMaintainer(controller, intervals.billingDatabaseMaintainer));
maintainers.add(new MeteringMonitorMaintainer(controller, intervals.meteringMonitorMaintainer, controller.serviceRegistry().resourceDatabase(), metric));
+ maintainers.add(new EnclaveAccessMaintainer(controller, intervals.defaultInterval));
}
public Upgrader upgrader() { return upgrader; }
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/EnclaveAccessMaintainer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/EnclaveAccessMaintainer.java
new file mode 100644
index 00000000000..d9576f4e176
--- /dev/null
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/EnclaveAccessMaintainer.java
@@ -0,0 +1,43 @@
+package com.yahoo.vespa.hosted.controller.maintenance;
+
+import com.yahoo.config.provision.CloudAccount;
+import com.yahoo.vespa.hosted.controller.Controller;
+import com.yahoo.vespa.hosted.controller.tenant.Tenant;
+
+import java.time.Duration;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import static java.util.logging.Level.WARNING;
+
+public class EnclaveAccessMaintainer extends ControllerMaintainer {
+
+ private static final Logger logger = Logger.getLogger(EnclaveAccessMaintainer.class.getName());
+
+ EnclaveAccessMaintainer(Controller controller, Duration interval) {
+ super(controller, interval);
+ }
+
+ @Override
+ protected double maintain() {
+ try {
+ controller().serviceRegistry().enclaveAccessService().allowAccessFor(externalAccounts());
+ return 1;
+ }
+ catch (RuntimeException e) {
+ logger.log(WARNING, "Failed sharing AMIs", e);
+ return 0;
+ }
+ }
+
+ private Set<CloudAccount> externalAccounts() {
+ Set<CloudAccount> accounts = new HashSet<>();
+ for (Tenant tenant : controller().tenants().asList())
+ accounts.addAll(controller().applications().accountsOf(tenant.name()));
+
+ return accounts;
+ }
+
+
+}
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 27247c065ed..b0d16126600 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
@@ -215,7 +215,7 @@ public class RoutingPolicies {
for (var policy : policies) {
if (policy.dnsZone().isEmpty() && policy.canonicalName().isPresent()) continue;
if (controller.zoneRegistry().routingMethod(policy.id().zone()) != RoutingMethod.exclusive) continue;
- Endpoint endpoint = policy.regionEndpointIn(controller.system(), RoutingMethod.exclusive);
+ Endpoint endpoint = policy.regionEndpointIn(controller.system(), RoutingMethod.exclusive, controller.zoneRegistry());
var zonePolicy = db.readZoneRoutingPolicy(policy.id().zone());
long weight = 1;
if (isConfiguredOut(zonePolicy, policy, inactiveZones)) {
@@ -289,12 +289,10 @@ public class RoutingPolicies {
activeTargets.addAll(inactiveTargets);
inactiveTargets.clear();
}
+
targetsByEndpoint.forEach((applicationEndpoint, targets) -> {
- ZoneId targetZone = applicationEndpoint.targets().stream()
- .map(Endpoint.Target::deployment)
- .map(DeploymentId::zoneId)
- .findFirst()
- .get();
+ // Where multiple zones are permitted, they all have the same routing policy, and nameServiceForwarder (below).
+ ZoneId targetZone = applicationEndpoint.targets().iterator().next().deployment().zoneId();
Set<AliasTarget> aliasTargets = new LinkedHashSet<>();
Set<DirectTarget> directTargets = new LinkedHashSet<>();
for (Target target : targets) {
@@ -305,23 +303,28 @@ public class RoutingPolicies {
if ( ! aliasTargets.isEmpty()) {
nameServiceForwarderIn(targetZone).createAlias(
RecordName.from(applicationEndpoint.dnsName()), aliasTargets, Priority.normal);
+ nameServiceForwarderIn(targetZone).createAlias(
+ RecordName.from(applicationEndpoint.legacyRegionalDnsName()), aliasTargets, Priority.normal);
}
if ( ! directTargets.isEmpty()) {
nameServiceForwarderIn(targetZone).createDirect(
RecordName.from(applicationEndpoint.dnsName()), directTargets, Priority.normal);
+ nameServiceForwarderIn(targetZone).createDirect(
+ RecordName.from(applicationEndpoint.legacyRegionalDnsName()), directTargets, Priority.normal);
}
});
inactiveTargetsByEndpoint.forEach((applicationEndpoint, targets) -> {
- ZoneId targetZone = applicationEndpoint.targets().stream()
- .map(Endpoint.Target::deployment)
- .map(DeploymentId::zoneId)
- .findFirst()
- .get();
+ // Where multiple zones are permitted, they all have the same routing policy, and nameServiceForwarder.
+ ZoneId targetZone = applicationEndpoint.targets().iterator().next().deployment().zoneId();
targets.forEach(target -> {
nameServiceForwarderIn(targetZone).removeRecords(target.type(),
RecordName.from(applicationEndpoint.dnsName()),
target.data(),
Priority.normal);
+ nameServiceForwarderIn(targetZone).removeRecords(target.type(),
+ RecordName.from(applicationEndpoint.legacyRegionalDnsName()),
+ target.data(),
+ Priority.normal);
});
});
}
@@ -377,9 +380,8 @@ public class RoutingPolicies {
.not().matching(policy -> activeIds.contains(policy.id()));
for (var policy : removable) {
for (var endpoint : policy.zoneEndpointsIn(controller.system(), RoutingMethod.exclusive, controller.zoneRegistry())) {
- var dnsName = endpoint.dnsName();
nameServiceForwarderIn(allocation.deployment.zoneId()).removeRecords(Record.Type.CNAME,
- RecordName.from(dnsName),
+ RecordName.from(endpoint.dnsName()),
Priority.normal);
}
newPolicies.remove(policy.id());
@@ -424,14 +426,22 @@ public class RoutingPolicies {
for (Endpoint endpoint : endpoints) {
if (policy.canonicalName().isPresent()) {
forwarder.removeRecords(Record.Type.ALIAS,
- RecordName.from(endpoint.dnsName()),
- RecordData.fqdn(policy.canonicalName().get().value()),
- Priority.normal);
+ RecordName.from(endpoint.dnsName()),
+ RecordData.fqdn(policy.canonicalName().get().value()),
+ Priority.normal);
+ forwarder.removeRecords(Record.Type.ALIAS,
+ RecordName.from(endpoint.legacyRegionalDnsName()),
+ RecordData.fqdn(policy.canonicalName().get().value()),
+ Priority.normal);
} else {
forwarder.removeRecords(Record.Type.DIRECT,
- RecordName.from(endpoint.dnsName()),
- RecordData.from(policy.ipAddress().get()),
- Priority.normal);
+ RecordName.from(endpoint.dnsName()),
+ RecordData.from(policy.ipAddress().get()),
+ Priority.normal);
+ forwarder.removeRecords(Record.Type.DIRECT,
+ RecordName.from(endpoint.legacyRegionalDnsName()),
+ RecordData.from(policy.ipAddress().get()),
+ Priority.normal);
}
}
}
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 04c32590a4c..6ae729a3c02 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
@@ -96,12 +96,12 @@ public record RoutingPolicy(RoutingPolicyId id,
/** Returns the zone endpoints of this */
public List<Endpoint> zoneEndpointsIn(SystemName system, RoutingMethod routingMethod, ZoneRegistry zoneRegistry) {
DeploymentId deployment = new DeploymentId(id.owner(), id.zone());
- return List.of(endpoint(routingMethod).target(id.cluster(), deployment).in(system));
+ return List.of(endpoint(routingMethod, zoneRegistry).target(id.cluster(), deployment).in(system));
}
/** Returns the region endpoint of this */
- public Endpoint regionEndpointIn(SystemName system, RoutingMethod routingMethod) {
- return endpoint(routingMethod).targetRegion(id.cluster(), id.zone()).in(system);
+ public Endpoint regionEndpointIn(SystemName system, RoutingMethod routingMethod, ZoneRegistry zoneRegistry) {
+ return endpoint(routingMethod, zoneRegistry).targetRegion(id.cluster(), id.zone()).in(system);
}
@Override
@@ -125,7 +125,7 @@ public record RoutingPolicy(RoutingPolicyId id,
id.zone().value());
}
- private Endpoint.EndpointBuilder endpoint(RoutingMethod routingMethod) {
+ private Endpoint.EndpointBuilder endpoint(RoutingMethod routingMethod, ZoneRegistry zones) {
return Endpoint.of(id.owner())
.on(Port.fromRoutingMethod(routingMethod))
.routingMethod(routingMethod);