aboutsummaryrefslogtreecommitdiffstats
path: root/controller-server
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2020-01-29 12:38:53 +0100
committerMartin Polden <mpolden@mpolden.no>2020-01-29 14:31:02 +0100
commitab5d7dfccd1f349097b77931b7d55e387fe0a03e (patch)
tree6e5674a56a3b5f5482b873c9c19b11538bbc8970 /controller-server
parentff2010ffd3c15c5518dbc9276cbc7b24cde77879 (diff)
Extract RoutingController
Diffstat (limited to 'controller-server')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java217
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java12
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/RoutingController.java225
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java9
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java12
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporter.java4
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/RotationStatusUpdater.java2
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java20
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/routing/RoutingApiHandler.java12
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java8
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java3
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/rotation/RotationRepositoryTest.java4
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/RoutingPoliciesTest.java4
14 files changed, 280 insertions, 254 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
index f28c877dce6..fe1aaa001b1 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
@@ -1,14 +1,11 @@
// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller;
-import com.google.common.collect.ImmutableList;
import com.yahoo.component.Version;
-import com.yahoo.config.application.api.DeploymentInstanceSpec;
import com.yahoo.config.application.api.DeploymentSpec;
import com.yahoo.config.application.api.ValidationId;
import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.config.provision.ApplicationId;
-import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.InstanceName;
import com.yahoo.config.provision.TenantName;
@@ -22,7 +19,6 @@ import com.yahoo.vespa.athenz.api.AthenzUser;
import com.yahoo.vespa.curator.Lock;
import com.yahoo.vespa.hosted.controller.api.ActivateResult;
import com.yahoo.vespa.hosted.controller.api.application.v4.model.DeployOptions;
-import com.yahoo.vespa.hosted.controller.api.application.v4.model.EndpointStatus;
import com.yahoo.vespa.hosted.controller.api.application.v4.model.configserverbindings.ConfigChangeActions;
import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
import com.yahoo.vespa.hosted.controller.api.identifiers.Hostname;
@@ -41,16 +37,10 @@ import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationV
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ArtifactRepository;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.TesterId;
-import com.yahoo.vespa.hosted.controller.api.integration.dns.Record;
-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.api.integration.routing.RoutingEndpoint;
-import com.yahoo.vespa.hosted.controller.api.integration.routing.RoutingGenerator;
import com.yahoo.vespa.hosted.controller.application.ApplicationPackage;
import com.yahoo.vespa.hosted.controller.application.ApplicationPackageValidator;
import com.yahoo.vespa.hosted.controller.application.Deployment;
import com.yahoo.vespa.hosted.controller.application.DeploymentMetrics;
-import com.yahoo.vespa.hosted.controller.application.Endpoint;
import com.yahoo.vespa.hosted.controller.application.SystemApplication;
import com.yahoo.vespa.hosted.controller.application.TenantAndApplicationId;
import com.yahoo.vespa.hosted.controller.athenz.impl.AthenzFacade;
@@ -58,32 +48,23 @@ import com.yahoo.vespa.hosted.controller.concurrent.Once;
import com.yahoo.vespa.hosted.controller.deployment.DeploymentTrigger;
import com.yahoo.vespa.hosted.controller.deployment.Run;
import com.yahoo.vespa.hosted.controller.deployment.Versions;
-import com.yahoo.vespa.hosted.controller.dns.NameServiceQueue.Priority;
import com.yahoo.vespa.hosted.controller.endpointcertificates.EndpointCertificateManager;
-import com.yahoo.vespa.hosted.controller.routing.RoutingPolicies;
import com.yahoo.vespa.hosted.controller.persistence.CuratorDb;
-import com.yahoo.vespa.hosted.controller.rotation.RotationLock;
-import com.yahoo.vespa.hosted.controller.rotation.RotationRepository;
import com.yahoo.vespa.hosted.controller.security.AccessControl;
import com.yahoo.vespa.hosted.controller.security.Credentials;
import com.yahoo.vespa.hosted.controller.tenant.AthenzTenant;
import com.yahoo.vespa.hosted.controller.tenant.Tenant;
import com.yahoo.vespa.hosted.controller.versions.VespaVersion;
-import com.yahoo.vespa.hosted.rotation.config.RotationsConfig;
-import java.net.URI;
import java.security.Principal;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -93,7 +74,6 @@ import java.util.TreeMap;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
-import java.util.stream.Collectors;
import static com.yahoo.vespa.hosted.controller.api.integration.configserver.Node.State.active;
import static com.yahoo.vespa.hosted.controller.api.integration.configserver.Node.State.reserved;
@@ -119,30 +99,23 @@ public class ApplicationController {
private final ArtifactRepository artifactRepository;
private final ApplicationStore applicationStore;
- private final RotationRepository rotationRepository;
private final AccessControl accessControl;
private final ConfigServer configServer;
- private final RoutingGenerator routingGenerator;
- private final RoutingPolicies routingPolicies;
private final Clock clock;
private final DeploymentTrigger deploymentTrigger;
private final ApplicationPackageValidator applicationPackageValidator;
private final EndpointCertificateManager endpointCertificateManager;
- ApplicationController(Controller controller, CuratorDb curator,
- AccessControl accessControl, RotationsConfig rotationsConfig,
- Clock clock, SecretStore secretStore) {
+ ApplicationController(Controller controller, CuratorDb curator, AccessControl accessControl, Clock clock,
+ SecretStore secretStore) {
this.controller = controller;
this.curator = curator;
this.accessControl = accessControl;
this.configServer = controller.serviceRegistry().configServer();
- this.routingGenerator = controller.serviceRegistry().routingGenerator();
this.clock = clock;
this.artifactRepository = controller.serviceRegistry().artifactRepository();
this.applicationStore = controller.serviceRegistry().applicationStore();
- routingPolicies = new RoutingPolicies(controller);
- rotationRepository = new RotationRepository(rotationsConfig, this, curator);
deploymentTrigger = new DeploymentTrigger(controller, clock);
applicationPackageValidator = new ApplicationPackageValidator(controller);
endpointCertificateManager = new EndpointCertificateManager(controller.zoneRegistry(), curator, secretStore,
@@ -230,7 +203,7 @@ public class ApplicationController {
public Map<ZoneId, List<String>> contentClustersByZone(Collection<DeploymentId> ids) {
Map<ZoneId, List<String>> clusters = new TreeMap<>(Comparator.comparing(ZoneId::value));
for (DeploymentId id : ids)
- clusters.put(id.zoneId(), ImmutableList.copyOf(configServer.getContentClusters(id)));
+ clusters.put(id.zoneId(), List.copyOf(configServer.getContentClusters(id)));
return Collections.unmodifiableMap(clusters);
}
@@ -248,35 +221,6 @@ public class ApplicationController {
.orElse(controller.systemVersion());
}
- /** Change status of all global endpoints for given deployment */
- public void setGlobalRotationStatus(DeploymentId deployment, EndpointStatus status) {
- var globalEndpoints = findGlobalEndpoints(deployment);
- globalEndpoints.forEach(endpoint -> {
- try {
- configServer.setGlobalRotationStatus(deployment, endpoint.upstreamName(), status);
- } catch (Exception e) {
- throw new RuntimeException("Failed to set rotation status of " + endpoint + " in " + deployment, e);
- }
- });
- }
-
- /** Get global endpoint status for given deployment */
- public Map<RoutingEndpoint, EndpointStatus> globalRotationStatus(DeploymentId deployment) {
- var routingEndpoints = new LinkedHashMap<RoutingEndpoint, EndpointStatus>();
- findGlobalEndpoints(deployment).forEach(endpoint -> {
- var status = configServer.getGlobalRotationStatus(deployment, endpoint.upstreamName());
- routingEndpoints.put(endpoint, status);
- });
- return Collections.unmodifiableMap(routingEndpoints);
- }
-
- /** Find the global endpoints of given deployment */
- private List<RoutingEndpoint> findGlobalEndpoints(DeploymentId deployment) {
- return routingGenerator.endpoints(deployment).stream()
- .filter(RoutingEndpoint::isGlobal)
- .collect(Collectors.toUnmodifiableList());
- }
-
/**
* Creates a new application for an existing tenant.
*
@@ -399,7 +343,7 @@ public class ApplicationController {
endpointCertificateMetadata = endpointCertificateManager.getEndpointCertificateMetadata(application.get().require(instance), zone);
- endpoints = registerEndpointsInDns(applicationPackage.deploymentSpec(), application.get().require(instanceId.instance()), zone);
+ endpoints = controller.routingController().registerEndpointsInDns(applicationPackage.deploymentSpec(), application.get().require(instanceId.instance()), zone);
} // Release application lock while doing the deployment, which is a lengthy task.
// Carry out deployment without holding the application lock.
@@ -455,7 +399,7 @@ public class ApplicationController {
for (InstanceName instance : declaredInstances)
if (applicationPackage.deploymentSpec().requireInstance(instance).concerns(Environment.prod))
- application = withRotation(applicationPackage.deploymentSpec(), application, instance);
+ application = controller.routingController().assignRotations(application, instance);
store(application);
return application;
@@ -501,65 +445,10 @@ public class ApplicationController {
} finally {
// Even if prepare fails, a load balancer may have been provisioned. Always refresh routing policies so that
// any DNS updates can be propagated as early as possible.
- routingPolicies.refresh(application, applicationPackage.deploymentSpec(), zone);
+ controller.routingController().policies().refresh(application, applicationPackage.deploymentSpec(), zone);
}
}
- /** Makes sure the application has a global rotation, if eligible. */
- private LockedApplication withRotation(DeploymentSpec deploymentSpec, LockedApplication application, InstanceName instanceName) {
- try (RotationLock rotationLock = rotationRepository.lock()) {
- var rotations = rotationRepository.getOrAssignRotations(deploymentSpec,
- application.get().require(instanceName),
- rotationLock);
- application = application.with(instanceName, instance -> instance.with(rotations));
- store(application); // store assigned rotation even if deployment fails
- }
- return application;
- }
-
- /**
- * Register endpoints for rotations assigned to given application and zone in DNS.
- *
- * @return the registered endpoints
- */
- private Set<ContainerEndpoint> registerEndpointsInDns(DeploymentSpec deploymentSpec, Instance instance, ZoneId zone) {
- var containerEndpoints = new HashSet<ContainerEndpoint>();
- boolean registerLegacyNames = deploymentSpec.instance(instance.name())
- .flatMap(DeploymentInstanceSpec::globalServiceId)
- .isPresent();
- for (var assignedRotation : instance.rotations()) {
- var names = new ArrayList<String>();
- var endpoints = instance.endpointsIn(controller.system(), assignedRotation.endpointId())
- .scope(Endpoint.Scope.global);
-
- // Skip rotations which do not apply to this zone. Legacy names always point to all zones
- if (!registerLegacyNames && !assignedRotation.regions().contains(zone.region())) {
- continue;
- }
-
- // Omit legacy DNS names when assigning rotations using <endpoints/> syntax
- if (!registerLegacyNames) {
- endpoints = endpoints.legacy(false);
- }
-
- // Register names in DNS
- var rotation = rotationRepository.getRotation(assignedRotation.rotationId());
- if (rotation.isPresent()) {
- endpoints.asList().forEach(endpoint -> {
- controller.nameServiceForwarder().createCname(RecordName.from(endpoint.dnsName()),
- RecordData.fqdn(rotation.get().name()),
- Priority.normal);
- names.add(endpoint.dnsName());
- });
- }
-
- // Include rotation ID as a valid name of this container endpoint (required by global routing health checks)
- names.add(assignedRotation.rotationId().asString());
- containerEndpoints.add(new ContainerEndpoint(assignedRotation.clusterId().value(), names));
- }
- return Collections.unmodifiableSet(containerEndpoints);
- }
-
private ActivateResult unexpectedDeployment(ApplicationId application, ZoneId zone) {
Log logEntry = new Log();
logEntry.level = "WARNING";
@@ -611,74 +500,6 @@ public class ApplicationController {
options.deployCurrentVersion);
}
- /** Returns the endpoints of the deployment, or empty if the request fails */
- public List<URI> getDeploymentEndpoints(DeploymentId deploymentId) {
- if ( ! getInstance(deploymentId.applicationId())
- .map(application -> application.deployments().containsKey(deploymentId.zoneId()))
- .orElse(deploymentId.applicationId().instance().isTester()))
- throw new NotExistsException("Deployment", deploymentId.toString());
-
- try {
- return findRoutingEndpoints(deploymentId).stream()
- .map(RoutingEndpoint::endpoint)
- .map(URI::create)
- .collect(Collectors.toUnmodifiableList());
- }
- catch (RuntimeException e) {
- log.log(Level.WARNING, "Failed to get endpoint information for " + deploymentId, e);
- return Collections.emptyList();
- }
- }
-
- /** Find the routing endpoints of a given deployment. Routing endpoints are owned by the shared routing layer. */
- private List<RoutingEndpoint> findRoutingEndpoints(DeploymentId deployment) {
- if (controller.zoneRegistry().zones().directlyRouted().ids().contains(deployment.zoneId())) {
- return List.of(); // No shared routing layer in this zone.
- }
- return routingGenerator.endpoints(deployment);
- }
-
- private Map<ClusterSpec.Id, URI> findClusterEndpoints(DeploymentId deployment) {
- if (controller.zoneRegistry().zones().directlyRouted().ids().contains(deployment.zoneId())) {
- return Map.of(); // No shared routing layer in this zone.
- }
- return routingGenerator.clusterEndpoints(deployment);
- }
-
- /** Returns the non-empty endpoints per cluster in the given deployment, or empty if endpoints can't be found. */
- public Map<ClusterSpec.Id, URI> clusterEndpoints(DeploymentId id) {
- if ( ! getInstance(id.applicationId())
- .map(application -> application.deployments().containsKey(id.zoneId()))
- .orElse(id.applicationId().instance().isTester()))
- throw new NotExistsException("Deployment", id.toString());
-
- // TODO(jvenstad): Swap to use routingPolicies first, when this is ready.
- try {
- var endpoints = findClusterEndpoints(id);
- if ( ! endpoints.isEmpty())
- return endpoints;
- }
- catch (RuntimeException e) {
- log.log(Level.WARNING, "Failed to get endpoint information for " + id, e);
- }
- return routingPolicies.get(id).values().stream()
- .filter(policy -> policy.endpointIn(controller.system()).scope() == Endpoint.Scope.zone)
- .collect(Collectors.toUnmodifiableMap(policy -> policy.id().cluster(),
- policy -> policy.endpointIn(controller.system()).url()));
- }
-
- /** Returns all zone-specific cluster endpoints for the given application, in the given zones. */
- public Map<ZoneId, Map<ClusterSpec.Id, URI>> clusterEndpoints(Collection<DeploymentId> ids) {
- Map<ZoneId, Map<ClusterSpec.Id, URI>> deployments = new TreeMap<>(Comparator.comparing(ZoneId::value));
- for (DeploymentId id : ids) {
- var endpoints = clusterEndpoints(id);
- if ( ! endpoints.isEmpty()) {
- deployments.put(id.zoneId(), endpoints);
- }
- }
- return Collections.unmodifiableMap(deployments);
- }
-
/**
* Deletes the the given application. All known instances of the applications will be deleted.
*
@@ -700,7 +521,7 @@ public class ApplicationController {
throw new IllegalArgumentException("Could not delete '" + application + "': It has active deployments: " + deployments);
for (Instance instance : application.get().instances().values()) {
- removeEndpoints(instance);
+ controller.routingController().removeEndpointsInDns(instance);
application = application.without(instance.name());
}
@@ -736,24 +557,13 @@ public class ApplicationController {
&& application.get().deploymentSpec().instanceNames().contains(instanceId.instance()))
throw new IllegalArgumentException("Can not delete '" + instanceId + "', which is specified in 'deployment.xml'; remove it there first");
- removeEndpoints(application.get().require(instanceId.instance()));
+ controller.routingController().removeEndpointsInDns(application.get().require(instanceId.instance()));
curator.writeApplication(application.without(instanceId.instance()).get());
controller.jobController().collectGarbage();
log.info("Deleted " + instanceId);
});
}
- private void removeEndpoints(Instance instance) {
- instance.rotations().forEach(assignedRotation -> {
- var endpoints = instance.endpointsIn(controller.system(), assignedRotation.endpointId());
- endpoints.asList().stream()
- .map(Endpoint::dnsName)
- .forEach(name -> {
- controller.nameServiceForwarder().removeRecords(Record.Type.CNAME, RecordName.from(name), Priority.normal);
- });
- });
- }
-
/**
* Replace any previous version of this application by this instance
*
@@ -829,7 +639,7 @@ public class ApplicationController {
} catch (NotFoundException ignored) {
// ok; already gone
} finally {
- routingPolicies.refresh(application.get().id().instance(instanceName), application.get().deploymentSpec(), zone);
+ controller.routingController().policies().refresh(application.get().id().instance(instanceName), application.get().deploymentSpec(), zone);
}
return application.with(instanceName, instance -> instance.withoutDeploymentIn(zone));
}
@@ -871,15 +681,6 @@ public class ApplicationController {
instance.id(), zone, platformVersion, applicationVersion, deployment.version(), deployment.applicationVersion()));
}
- /** Returns the rotation repository, used for managing global rotation assignments */
- public RotationRepository rotationRepository() {
- return rotationRepository;
- }
-
- public RoutingPolicies routingPolicies() {
- return routingPolicies;
- }
-
/**
* Verifies that the application can be deployed to the tenant, following these rules:
*
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java
index 14b5c5e02c4..b4136e0de99 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java
@@ -73,6 +73,7 @@ public class Controller extends AbstractComponent implements ApplicationIdSource
private final NameServiceForwarder nameServiceForwarder;
private final MavenRepository mavenRepository;
private final Metric metric;
+ private final RoutingController routingController;
/**
* Creates a controller
@@ -102,11 +103,9 @@ public class Controller extends AbstractComponent implements ApplicationIdSource
metrics = new ConfigServerMetrics(serviceRegistry.configServer());
nameServiceForwarder = new NameServiceForwarder(curator);
jobController = new JobController(this);
- applicationController = new ApplicationController(this, curator, accessControl,
- Objects.requireNonNull(rotationsConfig, "RotationsConfig cannot be null"),
- clock, secretStore
- );
+ applicationController = new ApplicationController(this, curator, accessControl, clock, secretStore);
tenantController = new TenantController(this, curator, accessControl);
+ routingController = new RoutingController(this, Objects.requireNonNull(rotationsConfig, "RotationsConfig cannot be null"));
auditLogger = new AuditLogger(curator, clock);
// Record the version of this controller
@@ -124,6 +123,11 @@ public class Controller extends AbstractComponent implements ApplicationIdSource
/** Returns the instance controlling deployment jobs. */
public JobController jobController() { return jobController; }
+ /** Returns the instance controlling routing */
+ public RoutingController routingController() {
+ return routingController;
+ }
+
/** Returns the service registry of this */
public ServiceRegistry serviceRegistry() {
return serviceRegistry;
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
new file mode 100644
index 00000000000..32b87b8f92b
--- /dev/null
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/RoutingController.java
@@ -0,0 +1,225 @@
+// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.controller;
+
+import com.yahoo.config.application.api.DeploymentInstanceSpec;
+import com.yahoo.config.application.api.DeploymentSpec;
+import com.yahoo.config.provision.ClusterSpec;
+import com.yahoo.config.provision.InstanceName;
+import com.yahoo.config.provision.zone.ZoneId;
+import com.yahoo.vespa.hosted.controller.api.application.v4.model.EndpointStatus;
+import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
+import com.yahoo.vespa.hosted.controller.api.integration.configserver.ContainerEndpoint;
+import com.yahoo.vespa.hosted.controller.api.integration.dns.Record;
+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.api.integration.routing.RoutingEndpoint;
+import com.yahoo.vespa.hosted.controller.api.integration.routing.RoutingGenerator;
+import com.yahoo.vespa.hosted.controller.application.Endpoint;
+import com.yahoo.vespa.hosted.controller.dns.NameServiceQueue.Priority;
+import com.yahoo.vespa.hosted.controller.rotation.RotationLock;
+import com.yahoo.vespa.hosted.controller.rotation.RotationRepository;
+import com.yahoo.vespa.hosted.controller.routing.RoutingPolicies;
+import com.yahoo.vespa.hosted.rotation.config.RotationsConfig;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+
+/**
+ * The routing controller encapsulates state and methods for inspecting and manipulating DNS-level routing of traffic
+ * in a system.
+ *
+ * The one stop shop for all your routing needs!
+ *
+ * @author mpolden
+ */
+public class RoutingController {
+
+ private static final Logger log = Logger.getLogger(RoutingController.class.getName());
+
+ private final Controller controller;
+ private final RoutingPolicies routingPolicies;
+ private final RotationRepository rotationRepository;
+ private final RoutingGenerator routingGenerator;
+
+ public RoutingController(Controller controller, RotationsConfig rotationsConfig) {
+ this.controller = Objects.requireNonNull(controller, "controller must be non-null");
+ this.routingPolicies = new RoutingPolicies(controller);
+ this.rotationRepository = new RotationRepository(rotationsConfig, controller.applications(),
+ controller.curator());
+ this.routingGenerator = controller.serviceRegistry().routingGenerator();
+ }
+
+ public RoutingPolicies policies() {
+ return routingPolicies;
+ }
+
+ public RotationRepository rotations() {
+ return rotationRepository;
+ }
+
+ /** Returns all known endpoint URLs for given deployment, including global, in the shared routing layer */
+ public List<URI> legacyEndpointsOf(DeploymentId deployment) {
+ if (controller.zoneRegistry().zones().directlyRouted().ids().contains(deployment.zoneId())) {
+ return List.of(); // No shared routing layer in this zone.
+ }
+ try {
+ return routingGenerator.endpoints(deployment).stream()
+ .map(RoutingEndpoint::endpoint)
+ .map(URI::create)
+ .collect(Collectors.toUnmodifiableList());
+ } catch (RuntimeException e) {
+ log.log(Level.WARNING, "Failed to get endpoints for " + deployment, e);
+ return List.of();
+ }
+ }
+
+ /** Returns all non-global endpoint URLs for given deployment, grouped by their cluster ID */
+ public Map<ClusterSpec.Id, URI> zoneEndpointsOf(DeploymentId deployment) {
+ if ( ! controller.applications().getInstance(deployment.applicationId())
+ .map(application -> application.deployments().containsKey(deployment.zoneId()))
+ .orElse(deployment.applicationId().instance().isTester()))
+ throw new NotExistsException("Deployment", deployment.toString());
+
+ // In directly routed zones we create endpoint URLs from routing policies
+ if (controller.zoneRegistry().zones().directlyRouted().ids().contains(deployment.zoneId())) {
+ return routingPolicies.get(deployment).values().stream()
+ .filter(policy -> policy.endpointIn(controller.system()).scope() == Endpoint.Scope.zone)
+ .collect(Collectors.toUnmodifiableMap(policy -> policy.id().cluster(),
+ policy -> policy.endpointIn(controller.system())
+ .url()));
+ }
+ // In other zones we fetch endpoints from the shared routing layer
+ try {
+ return routingGenerator.clusterEndpoints(deployment);
+ } catch (RuntimeException e) {
+ log.log(Level.WARNING, "Failed to get endpoint information for " + deployment, e);
+ return Map.of();
+ }
+ }
+
+ /** Returns all non-global endpoint URLs for given deployments, grouped by their cluster ID and zone */
+ public Map<ZoneId, Map<ClusterSpec.Id, URI>> zoneEndpointsOf(Collection<DeploymentId> deployments) {
+ var endpoints = new TreeMap<ZoneId, Map<ClusterSpec.Id, URI>>(Comparator.comparing(ZoneId::value));
+ for (var deployment : deployments) {
+ var zoneEndpoints = zoneEndpointsOf(deployment);
+ if (!zoneEndpoints.isEmpty()) {
+ endpoints.put(deployment.zoneId(), zoneEndpoints);
+ }
+ }
+ return Collections.unmodifiableMap(endpoints);
+ }
+
+ /** Change status of all global endpoints for given deployment */
+ public void setGlobalRotationStatus(DeploymentId deployment, EndpointStatus status) {
+ var globalEndpoints = legacyGlobalEndpointsOf(deployment);
+ globalEndpoints.forEach(endpoint -> {
+ try {
+ controller.serviceRegistry().configServer().setGlobalRotationStatus(deployment, endpoint.upstreamName(), status);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to set rotation status of " + endpoint + " in " + deployment, e);
+ }
+ });
+ }
+
+ /** Get global endpoint status for given deployment */
+ public Map<RoutingEndpoint, EndpointStatus> globalRotationStatus(DeploymentId deployment) {
+ var routingEndpoints = new LinkedHashMap<RoutingEndpoint, EndpointStatus>();
+ legacyGlobalEndpointsOf(deployment).forEach(endpoint -> {
+ var status = controller.serviceRegistry().configServer().getGlobalRotationStatus(deployment, endpoint.upstreamName());
+ routingEndpoints.put(endpoint, status);
+ });
+ return Collections.unmodifiableMap(routingEndpoints);
+ }
+
+ /** Find the global endpoints of given deployment */
+ private List<RoutingEndpoint> legacyGlobalEndpointsOf(DeploymentId deployment) {
+ return controller.serviceRegistry().routingGenerator().endpoints(deployment).stream()
+ .filter(RoutingEndpoint::isGlobal)
+ .collect(Collectors.toUnmodifiableList());
+ }
+
+ /**
+ * Assigns one or more global rotations to given application, if eligible. The given application is implicitly
+ * stored, ensuring that the assigned rotation(s) are persisted when this returns.
+ */
+ public LockedApplication assignRotations(LockedApplication application, InstanceName instanceName) {
+ try (RotationLock rotationLock = rotationRepository.lock()) {
+ var rotations = rotationRepository.getOrAssignRotations(application.get().deploymentSpec(),
+ application.get().require(instanceName),
+ rotationLock);
+ application = application.with(instanceName, instance -> instance.with(rotations));
+ controller.applications().store(application); // store assigned rotation even if deployment fails
+ }
+ return application;
+ }
+
+ /**
+ * Register endpoints for rotations assigned to given application and zone in DNS.
+ *
+ * @return the registered endpoints
+ */
+ public Set<ContainerEndpoint> registerEndpointsInDns(DeploymentSpec deploymentSpec, Instance instance, ZoneId zone) {
+ var containerEndpoints = new HashSet<ContainerEndpoint>();
+ boolean registerLegacyNames = deploymentSpec.instance(instance.name())
+ .flatMap(DeploymentInstanceSpec::globalServiceId)
+ .isPresent();
+ for (var assignedRotation : instance.rotations()) {
+ var names = new ArrayList<String>();
+ var endpoints = instance.endpointsIn(controller.system(), assignedRotation.endpointId())
+ .scope(Endpoint.Scope.global);
+
+ // Skip rotations which do not apply to this zone. Legacy names always point to all zones
+ if (!registerLegacyNames && !assignedRotation.regions().contains(zone.region())) {
+ continue;
+ }
+
+ // Omit legacy DNS names when assigning rotations using <endpoints/> syntax
+ if (!registerLegacyNames) {
+ endpoints = endpoints.legacy(false);
+ }
+
+ // Register names in DNS
+ var rotation = rotationRepository.getRotation(assignedRotation.rotationId());
+ if (rotation.isPresent()) {
+ endpoints.asList().forEach(endpoint -> {
+ controller.nameServiceForwarder().createCname(RecordName.from(endpoint.dnsName()),
+ RecordData.fqdn(rotation.get().name()),
+ Priority.normal);
+ names.add(endpoint.dnsName());
+ });
+ }
+
+ // Include rotation ID as a valid name of this container endpoint (required by global routing health checks)
+ names.add(assignedRotation.rotationId().asString());
+ containerEndpoints.add(new ContainerEndpoint(assignedRotation.clusterId().value(), names));
+ }
+ return Collections.unmodifiableSet(containerEndpoints);
+ }
+
+ /** Remove endpoints in DNS for all rotations assigned to given instance */
+ public void removeEndpointsInDns(Instance instance) {
+ instance.rotations().forEach(assignedRotation -> {
+ var endpoints = instance.endpointsIn(controller.system(), assignedRotation.endpointId());
+ endpoints.asList().stream()
+ .map(Endpoint::dnsName)
+ .forEach(name -> {
+ controller.nameServiceForwarder().removeRecords(Record.Type.CNAME, RecordName.from(name),
+ Priority.normal);
+ });
+ });
+ }
+
+}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java
index 14ca182e00e..6da93ce90a5 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java
@@ -30,7 +30,6 @@ import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
import com.yahoo.vespa.hosted.controller.api.identifiers.Hostname;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServerException;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.Node;
-import com.yahoo.vespa.hosted.controller.api.integration.configserver.Node.ServiceState;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.PrepareResponse;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.ServiceConvergence;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
@@ -87,8 +86,6 @@ import static com.yahoo.vespa.hosted.controller.deployment.Step.deactivateTester
import static com.yahoo.vespa.hosted.controller.deployment.Step.deployInitialReal;
import static com.yahoo.vespa.hosted.controller.deployment.Step.deployReal;
import static com.yahoo.vespa.hosted.controller.deployment.Step.deployTester;
-import static com.yahoo.vespa.hosted.controller.deployment.Step.installInitialReal;
-import static com.yahoo.vespa.hosted.controller.deployment.Step.installReal;
import static com.yahoo.vespa.hosted.controller.deployment.Step.installTester;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.logging.Level.INFO;
@@ -437,7 +434,7 @@ public class InternalStepRunner implements StepRunner {
/** Returns true iff all containers in the deployment give 100 consecutive 200 OK responses on /status.html. */
// TODO: Change implementation to only be used for real deployments when useConfigServerForTesterAPI() always returns true
private boolean containersAreUp(ApplicationId id, ZoneId zoneId, DualLogger logger) {
- var endpoints = controller.applications().clusterEndpoints(Set.of(new DeploymentId(id, zoneId)));
+ var endpoints = controller.routingController().zoneEndpointsOf(Set.of(new DeploymentId(id, zoneId)));
if ( ! endpoints.containsKey(zoneId))
return false;
@@ -473,7 +470,7 @@ public class InternalStepRunner implements StepRunner {
private boolean endpointsAvailable(ApplicationId id, ZoneId zone, DualLogger logger) {
if (useConfigServerForTesterAPI(zone) && id.instance().isTester()) return true; // Endpoints not used in this case, always return true
- var endpoints = controller.applications().clusterEndpoints(Set.of(new DeploymentId(id, zone)));
+ var endpoints = controller.routingController().zoneEndpointsOf(Set.of(new DeploymentId(id, zone)));
if ( ! endpoints.containsKey(zone)) {
logger.log("Endpoints not yet ready.");
return false;
@@ -546,7 +543,7 @@ public class InternalStepRunner implements StepRunner {
deployments.add(new DeploymentId(id.application(), zoneId));
logger.log("Attempting to find endpoints ...");
- var endpoints = controller.applications().clusterEndpoints(deployments);
+ var endpoints = controller.routingController().zoneEndpointsOf(deployments);
if ( ! endpoints.containsKey(zoneId)) {
logger.log(WARNING, "Endpoints for the deployment to test vanished again, while it was still active!");
return Optional.of(error);
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java
index 13b3b368293..43aa3593313 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java
@@ -517,7 +517,7 @@ public class JobController {
} finally {
// Passing an empty DeploymentSpec here is fine as it's used for registering global endpoint names, and
// tester instances have none.
- controller.applications().routingPolicies().refresh(id.id(), DeploymentSpec.empty, zone);
+ controller.routingController().policies().refresh(id.id(), DeploymentSpec.empty, zone);
}
}
@@ -545,14 +545,10 @@ public class JobController {
.collect(toList()));
}
- /** Returns a URI of the tester endpoint retrieved from the routing generator, provided it matches an expected form. */
+ /** Returns the tester endpoint URL, if any */
Optional<URI> testerEndpoint(RunId id) {
- DeploymentId testerId = new DeploymentId(id.tester().id(), id.type().zone(controller.system()));
- return controller.applications().getDeploymentEndpoints(testerId)
- .stream().findAny()
- .or(() -> controller.applications().routingPolicies().get(testerId).values().stream()
- .findAny()
- .map(policy -> policy.endpointIn(controller.system()).url()));
+ var testerId = new DeploymentId(id.tester().id(), id.type().zone(controller.system()));
+ return controller.routingController().zoneEndpointsOf(testerId).values().stream().findFirst();
}
private void prunePackages(TenantAndApplicationId id) {
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporter.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporter.java
index ccb802d314a..d88469645b4 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporter.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporter.java
@@ -64,8 +64,8 @@ public class MetricsReporter extends Maintainer {
}
private void reportRemainingRotations() {
- try (RotationLock lock = controller().applications().rotationRepository().lock()) {
- int availableRotations = controller().applications().rotationRepository().availableRotations(lock).size();
+ try (RotationLock lock = controller().routingController().rotations().lock()) {
+ int availableRotations = controller().routingController().rotations().availableRotations(lock).size();
metric.set(REMAINING_ROTATIONS, availableRotations, metric.createContext(Map.of()));
}
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/RotationStatusUpdater.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/RotationStatusUpdater.java
index ac5612b4e3f..bdfaa9c098f 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/RotationStatusUpdater.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/RotationStatusUpdater.java
@@ -82,7 +82,7 @@ public class RotationStatusUpdater extends Maintainer {
private RotationStatus getStatus(Instance instance) {
var statusMap = new LinkedHashMap<RotationId, RotationStatus.Targets>();
for (var assignedRotation : instance.rotations()) {
- var rotation = applications.rotationRepository().getRotation(assignedRotation.rotationId());
+ var rotation = controller().routingController().rotations().getRotation(assignedRotation.rotationId());
if (rotation.isEmpty()) continue;
var targets = service.getHealthStatus(rotation.get().name()).entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, (kv) -> from(kv.getValue())));
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 00e0bcd36ad..7e4ad0d3384 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
@@ -840,7 +840,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
.forEach(globalEndpointUrls::add);
// Per-cluster endpoints. These are backed by load balancers.
- var routingPolicies = controller.applications().routingPolicies().get(instance.id()).values();
+ var routingPolicies = controller.routingController().policies().get(instance.id()).values();
for (var policy : routingPolicies) {
policy.globalEndpointsIn(controller.system()).asList().stream()
.map(Endpoint::url)
@@ -1029,7 +1029,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
// Add endpoint(s) defined by routing policies
var endpointArray = response.setArray("endpoints");
- for (var policy : controller.applications().routingPolicies().get(deploymentId).values()) {
+ for (var policy : controller.routingController().policies().get(deploymentId).values()) {
if (!policy.status().isActive()) continue;
Cursor endpointObject = endpointArray.addObject();
Endpoint endpoint = policy.endpointIn(controller.system());
@@ -1038,11 +1038,11 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
endpointObject.setString("url", endpoint.url().toString());
}
- // serviceUrls contains zone/cluster-specific endpoints for this deployment. The name of these endpoints may
- // contain the cluster name (if non-default) and since the controller has no knowledge of clusters, we have to
- // ask the routing layer here
+ // serviceUrls contains all valid endpoints for this deployment, including global. The name of these endpoints
+ // may contain the cluster name (if non-default). Since the controller has no knowledge of clusters for legacy
+ // endpoints, we can't generate these URLs on-the-fly and we have to query the routing layer.
Cursor serviceUrlArray = response.setArray("serviceUrls");
- controller.applications().getDeploymentEndpoints(deploymentId)
+ controller.routingController().legacyEndpointsOf(deploymentId)
.forEach(endpoint -> serviceUrlArray.addString(endpoint.toString()));
response.setString("nodes", withPath("/zone/v2/" + deploymentId.zoneId().environment() + "/" + deploymentId.zoneId().region() + "/nodes/v2/node/?&recursive=true&application=" + deploymentId.applicationId().tenant() + "." + deploymentId.applicationId().application() + "." + deploymentId.applicationId().instance(), request.getUri()).toString());
@@ -1186,7 +1186,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
private void setGlobalEndpointStatus(DeploymentId deployment, boolean inService, HttpRequest request) {
var agent = isOperator(request) ? GlobalRouting.Agent.operator : GlobalRouting.Agent.tenant;
var status = inService ? GlobalRouting.Status.in : GlobalRouting.Status.out;
- controller.applications().routingPolicies().setGlobalRoutingStatus(deployment, status, agent);
+ controller.routingController().policies().setGlobalRoutingStatus(deployment, status, agent);
}
/** Set the global rotation status for given deployment. This only applies to global endpoints backed by a rotation */
@@ -1197,7 +1197,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
long timestamp = controller.clock().instant().getEpochSecond();
var status = inService ? EndpointStatus.Status.in : EndpointStatus.Status.out;
var endpointStatus = new EndpointStatus(status, reason, agent.name(), timestamp);
- controller.applications().setGlobalRotationStatus(deployment, endpointStatus);
+ controller.routingController().setGlobalRotationStatus(deployment, endpointStatus);
}
private HttpResponse getGlobalRotationOverride(String tenantName, String applicationName, String instanceName, String environment, String region) {
@@ -1205,7 +1205,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
ZoneId.from(environment, region));
Slime slime = new Slime();
Cursor array = slime.setObject().setArray("globalrotationoverride");
- controller.applications().globalRotationStatus(deploymentId)
+ controller.routingController().globalRotationStatus(deploymentId)
.forEach((endpoint, status) -> {
array.addString(endpoint.upstreamName());
Cursor statusObject = array.addObject();
@@ -1674,7 +1674,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
return new SlimeJsonResponse(testConfigSerializer.configSlime(id,
type,
false,
- controller.applications().clusterEndpoints(deployments),
+ controller.routingController().zoneEndpointsOf(deployments),
controller.applications().contentClustersByZone(deployments)));
}
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 be459614880..8451f8d4f17 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
@@ -79,7 +79,7 @@ public class RoutingApiHandler extends AuditLoggingRequestHandler {
var zone = zoneFrom(path);
if (controller.zoneRegistry().zones().directlyRouted().ids().contains(zone)) {
var status = in ? GlobalRouting.Status.in : GlobalRouting.Status.out;
- controller.applications().routingPolicies().setGlobalRoutingStatus(zone, status);
+ controller.routingController().policies().setGlobalRoutingStatus(zone, status);
} else {
controller.serviceRegistry().configServer().setGlobalRotationStatus(zone, in);
}
@@ -92,7 +92,7 @@ public class RoutingApiHandler extends AuditLoggingRequestHandler {
var slime = new Slime();
var root = slime.setObject();
if (controller.zoneRegistry().zones().directlyRouted().ids().contains(zone)) {
- var zonePolicy = controller.applications().routingPolicies().get(zone);
+ var zonePolicy = controller.routingController().policies().get(zone);
zoneStatusToSlime(root, zonePolicy.zone(), zonePolicy.globalRouting(), RoutingType.policy);
} else {
// Rotation status per zone only exposes in/out status, no agent or time of change.
@@ -115,11 +115,11 @@ public class RoutingApiHandler extends AuditLoggingRequestHandler {
var endpointStatus = new EndpointStatus(in ? EndpointStatus.Status.in : EndpointStatus.Status.out, "",
agent.name(),
controller.clock().instant().getEpochSecond());
- controller.applications().setGlobalRotationStatus(deployment, endpointStatus);
+ controller.routingController().setGlobalRotationStatus(deployment, endpointStatus);
}
// Set policy status
- controller.applications().routingPolicies().setGlobalRoutingStatus(deployment, status, agent);
+ controller.routingController().policies().setGlobalRoutingStatus(deployment, status, agent);
return new MessageResponse("Set global routing status for " + deployment + " to " + (in ? "IN" : "OUT"));
}
@@ -131,7 +131,7 @@ public class RoutingApiHandler extends AuditLoggingRequestHandler {
// Include status from rotation
if (rotationCanRouteTo(deployment.zoneId(), instance)) {
- var rotationStatus = controller.applications().globalRotationStatus(deployment);
+ var rotationStatus = controller.routingController().globalRotationStatus(deployment);
// Status is equal across all global endpoints, as the status is per deployment, not per endpoint.
var endpointStatus = rotationStatus.values().stream().findFirst();
if (endpointStatus.isPresent()) {
@@ -152,7 +152,7 @@ public class RoutingApiHandler extends AuditLoggingRequestHandler {
}
// Include status from routing policies
- var routingPolicies = controller.applications().routingPolicies().get(deployment);
+ var routingPolicies = controller.routingController().policies().get(deployment);
for (var policy : routingPolicies.values()) {
deploymentStatusToSlime(deploymentsObject.addObject(), policy);
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java
index 83f80488ee5..bd59fc45c96 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java
@@ -190,7 +190,7 @@ public class ControllerTest {
new RoutingEndpoint("http://alias-endpoint.vespa.yahooapis.com:4080", "host1", true, "upstream1")
));
- Supplier<Map<RoutingEndpoint, EndpointStatus>> globalRotationStatus = () -> tester.controller().applications().globalRotationStatus(deployment);
+ Supplier<Map<RoutingEndpoint, EndpointStatus>> globalRotationStatus = () -> tester.controller().routingController().globalRotationStatus(deployment);
Supplier<List<EndpointStatus>> upstreamOneEndpoints = () -> {
return globalRotationStatus.get()
.entrySet().stream()
@@ -206,7 +206,7 @@ public class ControllerTest {
// Set the global rotations out of service
EndpointStatus status = new EndpointStatus(EndpointStatus.Status.out, "unit-test", "Test", tester.clock().instant().getEpochSecond());
- tester.controller().applications().setGlobalRotationStatus(deployment, status);
+ tester.controller().routingController().setGlobalRotationStatus(deployment, status);
assertEquals(2, upstreamOneEndpoints.get().size());
assertTrue("All upstreams are out", upstreamOneEndpoints.get().stream().allMatch(es -> es.getStatus() == EndpointStatus.Status.out));
assertTrue("Reason is set", upstreamOneEndpoints.get().stream().allMatch(es -> es.getReason().equals("unit-test")));
@@ -517,9 +517,9 @@ public class ControllerTest {
context.submit(applicationPackage);
tester.applications().deleteApplication(context.application().id(),
tester.controllerTester().credentialsFor(context.application().id().tenant()));
- try (RotationLock lock = tester.applications().rotationRepository().lock()) {
+ try (RotationLock lock = tester.controller().routingController().rotations().lock()) {
assertTrue("Rotation is unassigned",
- tester.applications().rotationRepository().availableRotations(lock)
+ tester.controller().routingController().rotations().availableRotations(lock)
.containsKey(new RotationId("rotation-id-01")));
}
context.flushDnsUpdates();
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java
index 112b8066847..830643b215a 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java
@@ -258,6 +258,9 @@ public class InternalStepRunnerTest {
@Test
public void alternativeEndpointsAreDetected() {
+ var systemTestZone = JobType.systemTest.zone(system());
+ var stagingZone = JobType.stagingTest.zone(system());
+ tester.controllerTester().zoneRegistry().setDirectlyRouted(ZoneApiMock.from(systemTestZone), ZoneApiMock.from(stagingZone));
app.newRun(JobType.systemTest);
tester.runner().run();;
tester.configServer().convergeServices(app.instanceId(), JobType.systemTest.zone(system()));
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java
index e96d25c2cab..0f846ab57e4 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java
@@ -1610,7 +1610,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
private void assertGlobalRouting(DeploymentId deployment, GlobalRouting.Status status, GlobalRouting.Agent agent) {
var changedAt = tester.controller().clock().instant();
- var westPolicies = tester.controller().applications().routingPolicies().get(deployment);
+ var westPolicies = tester.controller().routingController().policies().get(deployment);
assertEquals(1, westPolicies.size());
var westPolicy = westPolicies.values().iterator().next();
assertEquals(status, westPolicy.status().globalRouting().status());
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/rotation/RotationRepositoryTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/rotation/RotationRepositoryTest.java
index 674f084a8b7..1bb531edbc5 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/rotation/RotationRepositoryTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/rotation/RotationRepositoryTest.java
@@ -55,7 +55,7 @@ public class RotationRepositoryTest {
@Before
public void before() {
tester = new DeploymentTester(new ControllerTester(rotationsConfig));
- repository = tester.applications().rotationRepository();
+ repository = tester.controller().routingController().rotations();
application = tester.newDeploymentContext("tenant1", "app1", "default");
}
@@ -83,7 +83,7 @@ public class RotationRepositoryTest {
@Test
public void strips_whitespace_in_rotation_fqdn() {
tester = new DeploymentTester(new ControllerTester(rotationsConfigWhitespaces));
- RotationRepository repository = tester.controller().applications().rotationRepository();
+ RotationRepository repository = tester.controller().routingController().rotations();
var application2 = tester.newDeploymentContext("tenant1", "app2", "default");
application2.submit(applicationPackage);
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 c6f9bb81b63..2b196b9127f 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
@@ -253,7 +253,7 @@ public class RoutingPoliciesTest {
URI.create("https://c1.app1.tenant1.us-west-1.vespa.oath.cloud/"),
ClusterSpec.Id.from("c2"),
URI.create("https://c2.app1.tenant1.us-west-1.vespa.oath.cloud/")),
- tester.controllerTester().controller().applications().clusterEndpoints(context.deploymentIdIn(zone1)));
+ tester.controllerTester().controller().routingController().zoneEndpointsOf(context.deploymentIdIn(zone1)));
}
@Test
@@ -509,7 +509,7 @@ public class RoutingPoliciesTest {
}
public RoutingPolicies routingPolicies() {
- return tester.controllerTester().controller().applications().routingPolicies();
+ return tester.controllerTester().controller().routingController().policies();
}
public DeploymentContext newDeploymentContext(String tenant, String application, String instance) {