diff options
author | Morten Tokle <mortent@verizonmedia.com> | 2020-01-30 09:00:47 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-01-30 09:00:47 +0100 |
commit | 2533470181c45a877fdc884f1c6742e0934aa6bb (patch) | |
tree | a152e26e5af7f0c795af8c3d6abcc317a8cd3bda /controller-server | |
parent | 330656493815924dd8c984c1c16a1e39f49374af (diff) | |
parent | ab5d7dfccd1f349097b77931b7d55e387fe0a03e (diff) |
Merge pull request #12000 from vespa-engine/mpolden/routing-controller
Extract RoutingController
Diffstat (limited to 'controller-server')
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) { |