diff options
author | Martin Polden <mpolden@mpolden.no> | 2019-01-25 14:45:21 +0100 |
---|---|---|
committer | Martin Polden <mpolden@mpolden.no> | 2019-01-25 14:45:21 +0100 |
commit | 8d90a1fd5a0e6b08ab03ab9497e2508a8e15fcae (patch) | |
tree | 6b109f250b0237a1e35ad6c1e0f47b1c4ae47a69 /controller-server | |
parent | 01c8dd3582c3c86a7fab4699617ef9d1eec13681 (diff) |
Simplify DNS record cleanup
Diffstat (limited to 'controller-server')
14 files changed, 425 insertions, 420 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedApplication.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedApplication.java index 5d0b71a809b..130519335ce 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedApplication.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedApplication.java @@ -10,6 +10,7 @@ import com.yahoo.config.provision.HostName; import com.yahoo.vespa.curator.Lock; import com.yahoo.vespa.hosted.controller.api.integration.MetricsService; import com.yahoo.vespa.hosted.controller.api.integration.MetricsService.ApplicationMetrics; +import com.yahoo.vespa.hosted.controller.api.integration.configserver.LoadBalancer; import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion; import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; import com.yahoo.vespa.hosted.controller.api.integration.organization.IssueId; @@ -27,10 +28,12 @@ import com.yahoo.vespa.hosted.controller.rotation.RotationId; import java.time.Instant; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.OptionalLong; +import java.util.stream.Collectors; /** * An application that has been locked for modification. Provides methods for modifying an application's fields. @@ -248,8 +251,11 @@ public class LockedApplication { outstandingChange, ownershipIssueId, owner, majorVersion, metrics, rotation, rotationStatus); } - public LockedApplication withDeploymentLoadBalancers(ZoneId zoneId, Map<ClusterSpec.Id, HostName> loadBalancers) { - return with(deployments.get(zoneId).withLoadBalancers(loadBalancers)); + public LockedApplication withLoadBalancersIn(ZoneId zoneId, List<LoadBalancer> loadBalancers) { + Map<ClusterSpec.Id, HostName> loadBalancersByCluster = loadBalancers.stream() + .collect(Collectors.toUnmodifiableMap(LoadBalancer::cluster, + LoadBalancer::hostname)); + return with(deployments.get(zoneId).withLoadBalancers(loadBalancersByCluster)); } /** Don't expose non-leaf sub-objects. */ diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/LoadBalancerAlias.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/LoadBalancerAlias.java new file mode 100644 index 00000000000..4e1c79248a9 --- /dev/null +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/LoadBalancerAlias.java @@ -0,0 +1,93 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.application; + +import com.google.common.base.Strings; +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.ClusterSpec; +import com.yahoo.config.provision.HostName; +import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * Represents a DNS alias for a load balancer. + * + * @author mortent + */ +public class LoadBalancerAlias { + + private static final String ignoredEndpointPart = "default"; + private final ApplicationId owner; + private final String id; + private final HostName alias; + private final HostName canonicalName; + + public LoadBalancerAlias(ApplicationId owner, String id, HostName alias, HostName canonicalName) { + this.owner = Objects.requireNonNull(owner, "owner must be non-null"); + this.id = Objects.requireNonNull(id, "id must be non-null"); + this.alias = Objects.requireNonNull(alias, "alias must be non-null"); + this.canonicalName = Objects.requireNonNull(canonicalName, "canonicalName must be non-null"); + } + + /** The application owning this */ + public ApplicationId owner() { + return owner; + } + + /** The ID of the DNS record represented by this */ + public String id() { + return id; + } + + /** This alias (lhs of the CNAME record) */ + public HostName alias() { + return alias; + } + + /** The canonical name of this (rhs of the CNAME record) */ + public HostName canonicalName() { + return canonicalName; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + LoadBalancerAlias that = (LoadBalancerAlias) o; + return Objects.equals(owner, that.owner) && + Objects.equals(id, that.id) && + Objects.equals(alias, that.alias) && + Objects.equals(canonicalName, that.canonicalName); + } + + @Override + public int hashCode() { + return Objects.hash(owner, id, alias, canonicalName); + } + + @Override + public String toString() { + return String.format("%s: %s -> %s, owned by %s", id, alias, canonicalName, owner.toShortString()); + } + + public static String createAlias(ClusterSpec.Id clusterId, ApplicationId applicationId, ZoneId zoneId) { + List<String> parts = Arrays.asList(ignorePartIfDefault(clusterId.value()), + ignorePartIfDefault(applicationId.instance().value()), + applicationId.application().value(), + applicationId.tenant().value(), + zoneId.value(), + "vespa.oath.cloud" + ); + return parts.stream() + .filter(s -> !Strings.isNullOrEmpty((s))) + .collect(Collectors.joining("--")); + } + + private static String ignorePartIfDefault(String s) { + return ignoredEndpointPart.equalsIgnoreCase(s) ? "" : s; + } + +} diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/loadbalancer/LoadBalancerName.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/loadbalancer/LoadBalancerName.java deleted file mode 100644 index b2963a62eba..00000000000 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/loadbalancer/LoadBalancerName.java +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.hosted.controller.loadbalancer; - -import com.yahoo.vespa.hosted.controller.api.integration.dns.RecordId; -import com.yahoo.vespa.hosted.controller.api.integration.dns.RecordName; - -import java.util.Objects; - -/** - * Represents a pair of RecordId and RecordName - * - * @author mortent - */ -public class LoadBalancerName { - private final RecordId recordId; - private final RecordName recordName; - - public LoadBalancerName(RecordId recordId, RecordName recordName) { - this.recordId = recordId; - this.recordName = recordName; - } - - public RecordId recordId() { - return recordId; - } - - public RecordName recordName() { - return recordName; - } - - @Override - public String toString() { - return "LoadBalancerName{" + - "recordId=" + recordId + - ", recordName=" + recordName + - '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - LoadBalancerName that = (LoadBalancerName) o; - return recordId.equals(that.recordId) && - recordName.equals(that.recordName); - } - - @Override - public int hashCode() { - return Objects.hash(recordId, recordName); - } -} diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java index 132b4a28514..b38f55826d6 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java @@ -52,7 +52,7 @@ public class ControllerMaintenance extends AbstractComponent { private final JobRunner jobRunner; private final ContactInformationMaintainer contactInformationMaintainer; private final CostReportMaintainer costReportMaintainer; - private final LoadBalancerMaintainer loadbalancerMaintainer; + private final LoadBalancerAliasMaintainer loadBalancerAliasMaintainer; @SuppressWarnings("unused") // instantiated by Dependency Injection public ControllerMaintenance(MaintainerConfig maintainerConfig, ApiAuthorityConfig apiAuthorityConfig, Controller controller, CuratorDb curator, @@ -82,7 +82,7 @@ public class ControllerMaintenance extends AbstractComponent { osVersionStatusUpdater = new OsVersionStatusUpdater(controller, maintenanceInterval, jobControl); contactInformationMaintainer = new ContactInformationMaintainer(controller, Duration.ofHours(12), jobControl, contactRetriever); costReportMaintainer = new CostReportMaintainer(controller, Duration.ofHours(2), reportConsumer, jobControl, nodeRepositoryClient, Clock.systemUTC(), selfHostedCostConfig); - loadbalancerMaintainer = new LoadBalancerMaintainer(controller, Duration.ofMinutes(5), jobControl, nameService, curator); + loadBalancerAliasMaintainer = new LoadBalancerAliasMaintainer(controller, Duration.ofMinutes(5), jobControl, nameService, curator); } public Upgrader upgrader() { return upgrader; } @@ -110,7 +110,7 @@ public class ControllerMaintenance extends AbstractComponent { jobRunner.deconstruct(); contactInformationMaintainer.deconstruct(); costReportMaintainer.deconstruct(); - loadbalancerMaintainer.deconstruct(); + loadBalancerAliasMaintainer.deconstruct(); } /** Create one OS upgrader per cloud found in the zone registry of controller */ diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/LoadBalancerAliasMaintainer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/LoadBalancerAliasMaintainer.java new file mode 100644 index 00000000000..6c5000e3e3d --- /dev/null +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/LoadBalancerAliasMaintainer.java @@ -0,0 +1,147 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.maintenance; + +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.HostName; +import com.yahoo.log.LogLevel; +import com.yahoo.vespa.curator.Lock; +import com.yahoo.vespa.hosted.controller.Application; +import com.yahoo.vespa.hosted.controller.ApplicationController; +import com.yahoo.vespa.hosted.controller.Controller; +import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId; +import com.yahoo.vespa.hosted.controller.api.integration.configserver.LoadBalancer; +import com.yahoo.vespa.hosted.controller.api.integration.dns.NameService; +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.RecordId; +import com.yahoo.vespa.hosted.controller.api.integration.dns.RecordName; +import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId; +import com.yahoo.vespa.hosted.controller.application.Deployment; +import com.yahoo.vespa.hosted.controller.application.LoadBalancerAlias; +import com.yahoo.vespa.hosted.controller.persistence.CuratorDb; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +/** + * Maintains DNS aliases for all load balancers in this system. + * + * @author mortent + */ +public class LoadBalancerAliasMaintainer extends Maintainer { + + private static final Logger log = Logger.getLogger(LoadBalancerAliasMaintainer.class.getName()); + + private final NameService nameService; + private final CuratorDb db; + private final ApplicationController applications; + + public LoadBalancerAliasMaintainer(Controller controller, + Duration interval, + JobControl jobControl, + NameService nameService, + CuratorDb db) { + super(controller, interval, jobControl); + this.nameService = nameService; + this.db = db; + this.applications = controller.applications(); + } + + @Override + protected void maintain() { + updateDnsRecords(); + removeObsoleteDnsRecords(); + } + + /** Create DNS records for all exclusive load balancers */ + private void updateDnsRecords() { + for (Application application : applications.asList()) { + for (ZoneId zone : application.deployments().keySet()) { + List<LoadBalancer> loadBalancers = findLoadBalancersIn(zone, application.id()); + if (loadBalancers.isEmpty()) continue; + + applications.lockIfPresent(application.id(), (locked) -> { + applications.store(locked.withLoadBalancersIn(zone, loadBalancers)); + }); + + try (Lock lock = db.lockLoadBalancerAliases()) { + Set<LoadBalancerAlias> aliases = new LinkedHashSet<>(db.readLoadBalancerAliases(application.id())); + for (LoadBalancer loadBalancer : loadBalancers) { + try { + aliases.add(registerDnsAlias(application.id(), zone, loadBalancer)); + } catch (Exception e) { + log.log(LogLevel.WARNING, "Failed to create or update DNS record for load balancer " + + loadBalancer.hostname() + ". Retrying in " + maintenanceInterval(), + e); + } + } + db.writeLoadBalancerAliases(application.id(), aliases); + } + } + } + } + + /** Register DNS alias for given load balancer */ + private LoadBalancerAlias registerDnsAlias(ApplicationId application, ZoneId zone, LoadBalancer loadBalancer) { + HostName alias = HostName.from(LoadBalancerAlias.createAlias(loadBalancer.cluster(), application, zone)); + RecordName name = RecordName.from(alias.value()); + RecordData data = RecordData.fqdn(loadBalancer.hostname().value()); + Optional<Record> existingRecord = nameService.findRecord(Record.Type.CNAME, name); + RecordId id; + if(existingRecord.isPresent()) { + id = existingRecord.get().id(); + nameService.updateRecord(existingRecord.get().id(), data); + } else { + id = nameService.createCname(name, data); + } + return new LoadBalancerAlias(application, id.asString(), alias, loadBalancer.hostname()); + } + + /** Find all load balancers assigned to application in given zone */ + private List<LoadBalancer> findLoadBalancersIn(ZoneId zone, ApplicationId application) { + try { + return controller().applications().configServer().getLoadBalancers(new DeploymentId(application, zone)); + } catch (Exception e) { + log.log(LogLevel.WARNING, + String.format("Got exception fetching load balancers for application: %s, in zone: %s. Retrying in %s", + application.toShortString(), zone.value(), maintenanceInterval()), e); + } + return Collections.emptyList(); + } + + /** Remove all DNS records that point to non-existing load balancers */ + private void removeObsoleteDnsRecords() { + try (Lock lock = db.lockLoadBalancerAliases()) { + List<LoadBalancerAlias> removalCandidates = new ArrayList<>(db.readLoadBalancerAliases()); + Set<HostName> activeLoadBalancers = controller().applications().asList().stream() + .map(Application::deployments) + .map(Map::values) + .flatMap(Collection::stream) + .map(Deployment::loadBalancers) + .map(Map::values) + .flatMap(Collection::stream) + .collect(Collectors.toUnmodifiableSet()); + + // Remove any active load balancers + removalCandidates.removeIf(lb -> activeLoadBalancers.contains(lb.canonicalName())); + for (LoadBalancerAlias alias : removalCandidates) { + try { + nameService.removeRecord(new RecordId(alias.id())); + } catch (Exception e) { + log.log(LogLevel.WARNING, "Failed to remove DNS record with ID '" + alias.id() + + "'. Retrying in " + maintenanceInterval()); + } + } + } + } + +} diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/LoadBalancerMaintainer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/LoadBalancerMaintainer.java deleted file mode 100644 index 71b2482a650..00000000000 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/LoadBalancerMaintainer.java +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.hosted.controller.maintenance; - -import com.google.common.base.Strings; -import com.yahoo.config.provision.ApplicationId; -import com.yahoo.config.provision.ClusterSpec; -import com.yahoo.config.provision.HostName; -import com.yahoo.log.LogLevel; -import com.yahoo.vespa.curator.Lock; -import com.yahoo.vespa.hosted.controller.Application; -import com.yahoo.vespa.hosted.controller.Controller; -import com.yahoo.vespa.hosted.controller.LockedApplication; -import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId; -import com.yahoo.vespa.hosted.controller.api.integration.configserver.LoadBalancer; -import com.yahoo.vespa.hosted.controller.api.integration.dns.NameService; -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.RecordId; -import com.yahoo.vespa.hosted.controller.api.integration.dns.RecordName; -import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId; -import com.yahoo.vespa.hosted.controller.application.Deployment; -import com.yahoo.vespa.hosted.controller.loadbalancer.LoadBalancerName; -import com.yahoo.vespa.hosted.controller.persistence.CuratorDb; - -import java.time.Duration; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.logging.Logger; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * Maintains loadbalancer endpoints. - * Reads load balancer information for each application in all zones and updates name service. - * - * @author mortent - */ -public class LoadBalancerMaintainer extends Maintainer { - - private static final Logger log = Logger.getLogger(LoadBalancerMaintainer.class.getName()); - private static final String IGNORE_ENDPOINT_VALUE = "default"; - - private final NameService nameService; - private final CuratorDb curatorDb; - - public LoadBalancerMaintainer(Controller controller, - Duration interval, - JobControl jobControl, - NameService nameService, - CuratorDb curatorDb) { - super(controller, interval, jobControl); - this.nameService = nameService; - this.curatorDb = curatorDb; - } - - @Override - protected void maintain() { - // update application object with load balancer information - controller().applications().asList().forEach(this::updateApplicationLoadBalancers); - - // Create or update cnames - List<Application> applications = controller().applications().asList(); - Map<ApplicationId, List<LoadBalancerName>> applicationEndpointMap = applications.stream() - .collect(Collectors.toMap(Application::id, this::registerLoadBalancerEndpoint)); - - try (Lock lock = curatorDb.lockLoadBalancerNames()) { - updatePersistedLoadBalancerNames(applicationEndpointMap); - removeObsoleteLoadBalancerNames(); - } - } - - - private void removeObsoleteLoadBalancerNames() { - Map<ApplicationId, List<LoadBalancerName>> persistedLoadBalancerNames = new HashMap<>(curatorDb.readLoadBalancerNames()); - Map<ApplicationId, List<LoadBalancerName>> result = new HashMap<>(); - - Map<ApplicationId, List<String>> wantedLoadBalancers = new HashMap<>(); - - for (Application application : controller().applications().asList()) { - for (Map.Entry<ZoneId, Deployment> entry : application.deployments().entrySet()) { - Map<ClusterSpec.Id, HostName> loadBalancers = entry.getValue().loadBalancers(); - List<String> loadBalancerNames = loadBalancers.keySet().stream() - .map(cluster -> getEndpointName(cluster, application.id(), entry.getKey())) - .collect(Collectors.toList()); - wantedLoadBalancers.merge(application.id(), loadBalancerNames, (v1, v2) -> - Stream.concat(v1.stream(), v2.stream()).collect(Collectors.toList())); - } - } - - for (Map.Entry<ApplicationId, List<LoadBalancerName>> loadbalancerEntry : persistedLoadBalancerNames.entrySet()) { - List<String> wanted = wantedLoadBalancers.getOrDefault(loadbalancerEntry.getKey(), Collections.emptyList()); - List<LoadBalancerName> current = loadbalancerEntry.getValue(); - List<LoadBalancerName> toBeRemoved = current.stream() - .filter(lbname -> !wanted.contains(lbname.recordName().asString())) - .collect(Collectors.toList()); - removeLoadBalancerNames(toBeRemoved); - List<LoadBalancerName> resultingLoadBalancers = current.stream().filter(lb -> !toBeRemoved.contains(lb)).collect(Collectors.toList()); - result.put(loadbalancerEntry.getKey(), resultingLoadBalancers); - } - - curatorDb.writeLoadBalancerNames(result); - } - - private void updatePersistedLoadBalancerNames(Map<ApplicationId, List<LoadBalancerName>> applicationEndpointMap) { - // Read current list of maintained load balancer endpoints - Map<ApplicationId, List<LoadBalancerName>> existingApplicationEndpointList = curatorDb.readLoadBalancerNames(); - - // Update ZK with new load balancer endpoints - Map<ApplicationId, List<LoadBalancerName>> allCreated = new HashMap<>(applicationEndpointMap); - existingApplicationEndpointList.forEach((k, v) -> allCreated.merge(k, v, (v1, v2) -> - // Merge the two lists, removing duplicates - List.copyOf(new LinkedHashSet<LoadBalancerName>( - Stream.concat(v1.stream(), v2.stream()).collect(Collectors.toList())) - ))); - - curatorDb.writeLoadBalancerNames(allCreated); - - } - - private void removeLoadBalancerNames(List<LoadBalancerName> loadBalancerNames) { - if(loadBalancerNames.isEmpty()) return; - log.log(LogLevel.INFO, String.format("Removing %d Load Balancer names", loadBalancerNames.size())); - for (LoadBalancerName loadBalancerName : loadBalancerNames) { - nameService.removeRecord(loadBalancerName.recordId()); - } - } - - private void updateApplicationLoadBalancers(Application application) { - // Get a list of all load balancers for this applications (for all zones and clusters) - Map<ZoneId, List<LoadBalancer>> zoneLoadBalancers = new HashMap<>(); - for (ZoneId zoneId : application.deployments().keySet()) { - try { - zoneLoadBalancers.put(zoneId, controller().applications().configServer().getLoadBalancers(new DeploymentId(application.id(), zoneId))); - } catch (Exception e) { - log.log(LogLevel.WARNING, - String.format("Got exception fetching load balancers for application: %s, in zone: %s. Retrying in %s", - application.id().toShortString(), zoneId.value(), maintenanceInterval()), - e); - } - } - - // store the load balancers on the deployments - controller().applications().lockIfPresent(application.id(), lockedApplication -> storeApplicationWithLoadBalancers(lockedApplication, zoneLoadBalancers)); - } - - private void storeApplicationWithLoadBalancers(LockedApplication lockedApplication, Map<ZoneId, List<LoadBalancer>> loadBalancers) { - for (Map.Entry<ZoneId, List<LoadBalancer>> entry : loadBalancers.entrySet()) { - Map<ClusterSpec.Id, HostName> loadbalancerClusterMap = entry.getValue().stream() - .collect(Collectors.toMap(LoadBalancer::cluster, LoadBalancer::hostname)); - lockedApplication = lockedApplication.withDeploymentLoadBalancers(entry.getKey(), loadbalancerClusterMap); - - } - controller().applications().store(lockedApplication); - } - - private List<LoadBalancerName> registerLoadBalancerEndpoint(Application application) { - List<LoadBalancerName> hostNamesRegistered = new ArrayList<>(); - for (Map.Entry<ZoneId, Deployment> deploymentEntry : application.deployments().entrySet()) { - ZoneId zone = deploymentEntry.getKey(); - Deployment deployment = deploymentEntry.getValue(); - for (Map.Entry<ClusterSpec.Id, HostName> loadBalancers : deployment.loadBalancers().entrySet()) { - try { - RecordName recordName = RecordName.from(getEndpointName(loadBalancers.getKey(), application.id(), zone)); - RecordData recordData = RecordData.fqdn(loadBalancers.getValue().value()); - Optional<Record> existingRecord = nameService.findRecord(Record.Type.CNAME, recordName); - final RecordId recordId; - if(existingRecord.isPresent()) { - recordId = existingRecord.get().id(); - nameService.updateRecord(existingRecord.get().id(), recordData); - } else { - recordId = nameService.createCname(recordName, recordData); - } - hostNamesRegistered.add(new LoadBalancerName(recordId, recordName)); - } catch (Exception e) { - // Catching any exception, will be retried on next run - log.log(LogLevel.WARNING, - String.format("Got exception updating name service for application: %s, cluster: %s in zone: %s. Retrying in %s", - application.id().toShortString(), loadBalancers.getKey().value(), zone.value(), maintenanceInterval()), - e); - } - } - } - return hostNamesRegistered; - } - - static String getEndpointName(ClusterSpec.Id clusterId, ApplicationId applicationId, ZoneId zoneId) { - List<String> endpointTerms = Arrays.asList(ignorePartIfDefault(clusterId.value()), - ignorePartIfDefault(applicationId.instance().value()), - applicationId.application().value(), - applicationId.tenant().value(), - zoneId.value(), - "vespa.oath.cloud" - ); - return endpointTerms.stream() - .filter(s -> !Strings.isNullOrEmpty((s))) - .collect(Collectors.joining(".")); - } - - private static String ignorePartIfDefault(String s) { - return IGNORE_ENDPOINT_VALUE.equalsIgnoreCase(s) ? "" : s; - } -} diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java index 5fac0896246..9c498233809 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java @@ -18,7 +18,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId; import com.yahoo.vespa.hosted.controller.deployment.Run; import com.yahoo.vespa.hosted.controller.deployment.Step; -import com.yahoo.vespa.hosted.controller.loadbalancer.LoadBalancerName; +import com.yahoo.vespa.hosted.controller.application.LoadBalancerAlias; import com.yahoo.vespa.hosted.controller.tenant.AthenzTenant; import com.yahoo.vespa.hosted.controller.tenant.Tenant; import com.yahoo.vespa.hosted.controller.tenant.UserTenant; @@ -72,6 +72,7 @@ public class CuratorDb { private static final Path applicationRoot = root.append("applications"); private static final Path jobRoot = root.append("jobs"); private static final Path controllerRoot = root.append("controllers"); + private static final Path loadBalancerAliasesRoot = root.append("loadBalancerAliases"); private final StringSetSerializer stringSetSerializer = new StringSetSerializer(); private final VersionStatusSerializer versionStatusSerializer = new VersionStatusSerializer(); @@ -82,7 +83,7 @@ public class CuratorDb { private final RunSerializer runSerializer = new RunSerializer(); private final OsVersionSerializer osVersionSerializer = new OsVersionSerializer(); private final OsVersionStatusSerializer osVersionStatusSerializer = new OsVersionStatusSerializer(osVersionSerializer); - private final LoadBalancerNameSerializer loadBalancerNameSerializer = new LoadBalancerNameSerializer(); + private final LoadBalancerAliasSerializer loadBalancerAliasSerializer = new LoadBalancerAliasSerializer(); private final Curator curator; private final Duration tryLockTimeout; @@ -176,8 +177,8 @@ public class CuratorDb { return lock(lockRoot.append("osVersionStatus"), defaultLockTimeout); } - public Lock lockLoadBalancerNames() { - return lock(lockRoot.append("loadBalancerNames"), defaultLockTimeout); + public Lock lockLoadBalancerAliases() { + return lock(lockRoot.append("loadBalancerAliases"), defaultLockTimeout); } // -------------- Helpers ------------------------------------------ @@ -460,14 +461,22 @@ public class CuratorDb { curator.set(openStackServerPoolPath(), data); } - // -------------- Load balancer names ------------------------------------- + // -------------- Load balancer aliases------------------------------------ - public void writeLoadBalancerNames(Map<ApplicationId, List<LoadBalancerName>> loadBalancerNames) { - curator.set(loadBalancerNamePath(), asJson(loadBalancerNameSerializer.toSlime(loadBalancerNames))); + public void writeLoadBalancerAliases(ApplicationId application, Set<LoadBalancerAlias> aliases) { + curator.set(loadBalancerAliasPath(application), asJson(loadBalancerAliasSerializer.toSlime(aliases))); } - public Map<ApplicationId, List<LoadBalancerName>> readLoadBalancerNames() { - return readSlime(loadBalancerNamePath()).map(loadBalancerNameSerializer::fromSlime).orElseGet(Collections::emptyMap); + public Set<LoadBalancerAlias> readLoadBalancerAliases() { + return curator.getChildren(loadBalancerAliasesRoot).stream() + .map(ApplicationId::fromSerializedForm) + .flatMap(application -> readLoadBalancerAliases(application).stream()) + .collect(Collectors.toUnmodifiableSet()); + } + + public Set<LoadBalancerAlias> readLoadBalancerAliases(ApplicationId application) { + return readSlime(loadBalancerAliasPath(application)).map(slime -> loadBalancerAliasSerializer.fromSlime(application, slime)) + .orElseGet(Collections::emptySet); } // -------------- Paths --------------------------------------------------- @@ -545,8 +554,8 @@ public class CuratorDb { return root.append("versionStatus"); } - private static Path loadBalancerNamePath() { - return root.append("loadBalancerNames"); + private static Path loadBalancerAliasPath(ApplicationId application) { + return loadBalancerAliasesRoot.append(application.serializedForm()); } private static Path provisionStatePath() { diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/LoadBalancerAliasSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/LoadBalancerAliasSerializer.java new file mode 100644 index 00000000000..0e7682eaf96 --- /dev/null +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/LoadBalancerAliasSerializer.java @@ -0,0 +1,52 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.persistence; + +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.HostName; +import com.yahoo.slime.ArrayTraverser; +import com.yahoo.slime.Cursor; +import com.yahoo.slime.Slime; +import com.yahoo.vespa.hosted.controller.application.LoadBalancerAlias; + +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * Serializer and deserializer for a {@link LoadBalancerAlias}. + * + * @author mortent + */ +public class LoadBalancerAliasSerializer { + + private static final String aliasesField = "aliases"; + private static final String idField = "id"; + private static final String aliasField = "alias"; + private static final String canonicalNameField = "canonicalName"; + + public Slime toSlime(Set<LoadBalancerAlias> aliases) { + Slime slime = new Slime(); + Cursor root = slime.setObject(); + Cursor aliasArray = root.setArray(aliasesField); + aliases.forEach(alias -> { + Cursor nameObject = aliasArray.addObject(); + nameObject.setString(idField, alias.id()); + nameObject.setString(aliasField, alias.alias().value()); + nameObject.setString(canonicalNameField, alias.canonicalName().value()); + }); + return slime; + } + + public Set<LoadBalancerAlias> fromSlime(ApplicationId owner, Slime slime) { + Set<LoadBalancerAlias> names = new LinkedHashSet<>(); + slime.get().field(aliasesField).traverse((ArrayTraverser) (i, inspect) -> { + names.add(new LoadBalancerAlias(owner, + inspect.field(idField).asString(), + HostName.from(inspect.field(aliasField).asString()), + HostName.from(inspect.field(canonicalNameField).asString()))); + }); + + return Collections.unmodifiableSet(names); + } + +} diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/LoadBalancerNameSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/LoadBalancerNameSerializer.java deleted file mode 100644 index a76e1189294..00000000000 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/LoadBalancerNameSerializer.java +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.hosted.controller.persistence; - -import com.yahoo.config.provision.ApplicationId; -import com.yahoo.slime.ArrayTraverser; -import com.yahoo.slime.Cursor; -import com.yahoo.slime.Inspector; -import com.yahoo.slime.ObjectTraverser; -import com.yahoo.slime.Slime; -import com.yahoo.vespa.hosted.controller.api.integration.dns.RecordId; -import com.yahoo.vespa.hosted.controller.api.integration.dns.RecordName; -import com.yahoo.vespa.hosted.controller.loadbalancer.LoadBalancerName; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Serializer and deserializer for LoadBalancerName - * - * @author mortent - */ -public class LoadBalancerNameSerializer { - - private static final String loadBalancerNamesField = "loadBalancerNames"; - - public Slime toSlime(Map<ApplicationId, List<LoadBalancerName>> loadBalancerNames) { - Slime slime = new Slime(); - Cursor root = slime.setObject(); - Cursor applicationEndpoints = root.setObject(loadBalancerNamesField); - - for (Map.Entry<ApplicationId, List<LoadBalancerName>> entry : loadBalancerNames.entrySet()) { - ApplicationId applicationId = entry.getKey(); - Cursor cursor = applicationEndpoints.setArray(applicationId.serializedForm()); - entry.getValue().forEach( lb -> cursor.addObject().setString(lb.recordId().asString(), lb.recordName().asString())); - } - return slime; - } - - public Map<ApplicationId, List<LoadBalancerName>> fromSlime(Slime slime) { - - Inspector object = slime.get().field(loadBalancerNamesField); - Map<ApplicationId, List<LoadBalancerName>> loadBalancerNames = new HashMap<>(); - object.traverse((ObjectTraverser) (appId, inspector) -> - loadBalancerNames.put(ApplicationId.fromSerializedForm(appId), loadBalancerNamesFromSlime(inspector))); - - return loadBalancerNames; - } - - private List<LoadBalancerName> loadBalancerNamesFromSlime(Inspector root) { - List<LoadBalancerName> names = new ArrayList<>(); - root.traverse((ArrayTraverser) (i, inspector) -> inspector.traverse((ObjectTraverser)(x,y)-> names.add(new LoadBalancerName(new RecordId(x), RecordName.from(y.asString()))))); - return names; - } -} diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/LoadBalancerAliasTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/LoadBalancerAliasTest.java new file mode 100644 index 00000000000..965a639a68c --- /dev/null +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/LoadBalancerAliasTest.java @@ -0,0 +1,33 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.application; + +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.ClusterSpec; +import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId; +import org.junit.Test; + +import static com.yahoo.vespa.hosted.controller.application.LoadBalancerAlias.createAlias; +import static org.junit.Assert.*; + +/** + * @author mpolden + */ +public class LoadBalancerAliasTest { + + @Test + public void test_endpoint_names() { + ZoneId zoneId = ZoneId.from("prod", "us-north-1"); + ApplicationId withInstanceName = ApplicationId.from("tenant", "application", "instance"); + testAlias("instance--application--tenant--prod.us-north-1--vespa.oath.cloud", "default", withInstanceName, zoneId); + testAlias("cluster--instance--application--tenant--prod.us-north-1--vespa.oath.cloud", "cluster", withInstanceName, zoneId); + + ApplicationId withDefaultInstance = ApplicationId.from("tenant", "application", "default"); + testAlias("application--tenant--prod.us-north-1--vespa.oath.cloud", "default", withDefaultInstance, zoneId); + testAlias("cluster--application--tenant--prod.us-north-1--vespa.oath.cloud", "cluster", withDefaultInstance, zoneId); + } + + private void testAlias(String expected, String clusterName, ApplicationId applicationId, ZoneId zoneId) { + assertEquals(expected, createAlias(ClusterSpec.Id.from(clusterName), applicationId, zoneId)); + } + +} diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/LoadBalancerMaintainerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/LoadBalancerAliasMaintainerTest.java index 05c3de79023..fa3fe505f3c 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/LoadBalancerMaintainerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/LoadBalancerAliasMaintainerTest.java @@ -16,7 +16,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId; import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder; import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester; -import com.yahoo.vespa.hosted.controller.loadbalancer.LoadBalancerName; +import com.yahoo.vespa.hosted.controller.application.LoadBalancerAlias; import com.yahoo.vespa.hosted.controller.persistence.MockCuratorDb; import org.junit.Test; @@ -25,23 +25,23 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Set; import static org.junit.Assert.assertEquals; /** * @author mortent */ -public class LoadBalancerMaintainerTest { +public class LoadBalancerAliasMaintainerTest { @Test - public void maintains_loadbalancer_records_correctly () { + public void maintains_load_balancer_records_correctly() { DeploymentTester tester = new DeploymentTester(); Application application = tester.createApplication("app1", "tenant1", 1, 1L); - - LoadBalancerMaintainer loadbalancerMaintainer = new LoadBalancerMaintainer(tester.controller(), Duration.ofHours(12), - new JobControl(new MockCuratorDb()), - tester.controllerTester().nameService(), - tester.controllerTester().curator()); + LoadBalancerAliasMaintainer maintainer = new LoadBalancerAliasMaintainer(tester.controller(), Duration.ofHours(12), + new JobControl(new MockCuratorDb()), + tester.controllerTester().nameService(), + tester.controllerTester().curator()); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) @@ -55,18 +55,17 @@ public class LoadBalancerMaintainerTest { tester.deployCompletely(application, applicationPackage); setupClustersWithLoadBalancers(tester, application, numberOfClustersPerZone); - loadbalancerMaintainer.maintain(); + maintainer.maintain(); Map<RecordId, Record> records = tester.controllerTester().nameService().records(); long recordCount = records.entrySet().stream().filter(entry -> entry.getValue().data().asString().contains("loadbalancer")).count(); - assertEquals(4,recordCount); + assertEquals(4, recordCount); - Map<ApplicationId, List<LoadBalancerName>> loadBalancerNames = tester.controller().curator().readLoadBalancerNames(); - List<LoadBalancerName> names = loadBalancerNames.get(application.id()); - assertEquals(4, names.size()); + Set<LoadBalancerAlias> loadBalancerAliases = tester.controller().curator().readLoadBalancerAliases(application.id()); + assertEquals(4, loadBalancerAliases.size()); // no update - loadbalancerMaintainer.maintain(); + maintainer.maintain(); Map<RecordId, Record> records2 = tester.controllerTester().nameService().records(); long recordCount2 = records2.entrySet().stream().filter(entry -> entry.getValue().data().asString().contains("loadbalancer")).count(); assertEquals(recordCount, recordCount2); @@ -76,14 +75,13 @@ public class LoadBalancerMaintainerTest { // add 1 cluster per zone setupClustersWithLoadBalancers(tester, application, numberOfClustersPerZone + 1); - loadbalancerMaintainer.maintain(); + maintainer.maintain(); Map<RecordId, Record> records3 = tester.controllerTester().nameService().records(); long recordCount3 = records3.entrySet().stream().filter(entry -> entry.getValue().data().asString().contains("loadbalancer")).count(); assertEquals(6,recordCount3); - Map<ApplicationId, List<LoadBalancerName>> loadBalancerNames3 = tester.controller().curator().readLoadBalancerNames(); - List<LoadBalancerName> names3 = loadBalancerNames3.get(application.id()); - assertEquals(6, names3.size()); + Set<LoadBalancerAlias> aliases3 = tester.controller().curator().readLoadBalancerAliases(application.id()); + assertEquals(6, aliases3.size()); // Add application @@ -91,35 +89,33 @@ public class LoadBalancerMaintainerTest { tester.deployCompletely(application2, applicationPackage); setupClustersWithLoadBalancers(tester, application2, numberOfClustersPerZone); - loadbalancerMaintainer.maintain(); + maintainer.maintain(); Map<RecordId, Record> records4 = tester.controllerTester().nameService().records(); long recordCount4 = records4.entrySet().stream().filter(entry -> entry.getValue().data().asString().contains("loadbalancer")).count(); assertEquals(10,recordCount4); - Map<ApplicationId, List<LoadBalancerName>> loadBalancerNames4 = tester.controller().curator().readLoadBalancerNames(); - List<LoadBalancerName> names4 = loadBalancerNames4.get(application2.id()); - assertEquals(4, names4.size()); + Set<LoadBalancerAlias> aliases4 = tester.controller().curator().readLoadBalancerAliases(application2.id()); + assertEquals(4, aliases4.size()); // Remove cluster in app1 setupClustersWithLoadBalancers(tester, application, numberOfClustersPerZone); - loadbalancerMaintainer.maintain(); + maintainer.maintain(); Map<RecordId, Record> records5 = tester.controllerTester().nameService().records(); long recordCount5 = records5.entrySet().stream().filter(entry -> entry.getValue().data().asString().contains("loadbalancer")).count(); - assertEquals(8,recordCount5); + assertEquals(8, recordCount5); // Remove application app2 tester.controller().applications().get(application2.id()) - .map(app -> app.deployments().keySet()) - .orElse(Collections.emptySet()) - .forEach(zone -> tester.controller().applications().deactivate(application2.id(), zone)); + .map(app -> app.deployments().keySet()) + .orElse(Collections.emptySet()) + .forEach(zone -> tester.controller().applications().deactivate(application2.id(), zone)); - loadbalancerMaintainer.maintain(); + maintainer.maintain(); Map<RecordId, Record> records6 = tester.controllerTester().nameService().records(); long recordCount6 = records6.entrySet().stream().filter(entry -> entry.getValue().data().asString().contains("loadbalancer")).count(); - assertEquals(4,recordCount6); - + assertEquals(4, recordCount6); } private void setupClustersWithLoadBalancers(DeploymentTester tester, Application application, int numberOfClustersPerZone) { @@ -128,40 +124,23 @@ public class LoadBalancerMaintainerTest { .removeLoadBalancers(new DeploymentId(application.id(), zone))); tester.controller().applications().get(application.id()).orElseThrow(()->new RuntimeException("No deployments")).deployments().keySet() .forEach(zone -> tester.configServer() - .addLoadBalancers(zone, application.id(), getLoadBalancers(zone, application.id(), numberOfClustersPerZone))); + .addLoadBalancers(zone, application.id(), makeLoadBalancers(zone, application.id(), numberOfClustersPerZone))); } - - @Test - public void test_endpoint_names() { - ZoneId zoneId = ZoneId.from("prod", "us-north-1"); - ApplicationId withInstanceName = ApplicationId.from("tenant", "application", "instance"); - testLoadBalancerName("instance.application.tenant.prod.us-north-1.vespa.oath.cloud", "default", withInstanceName, zoneId); - testLoadBalancerName("cluster.instance.application.tenant.prod.us-north-1.vespa.oath.cloud", "cluster", withInstanceName, zoneId); - - ApplicationId withDefaultInstance = ApplicationId.from("tenant", "application", "default"); - testLoadBalancerName("application.tenant.prod.us-north-1.vespa.oath.cloud", "default", withDefaultInstance, zoneId); - testLoadBalancerName("cluster.application.tenant.prod.us-north-1.vespa.oath.cloud", "cluster", withDefaultInstance, zoneId); - } - - private void testLoadBalancerName(String expected, String clusterName, ApplicationId applicationId, ZoneId zoneId) { - assertEquals(expected, - LoadBalancerMaintainer.getEndpointName(ClusterSpec.Id.from(clusterName), applicationId, zoneId)); - } - - private List<LoadBalancer> getLoadBalancers(ZoneId zone, ApplicationId applicationId, int loadBalancerCount) { + private List<LoadBalancer> makeLoadBalancers(ZoneId zone, ApplicationId applicationId, int count) { List<LoadBalancer> loadBalancers = new ArrayList<>(); - for (int i = 0; i < loadBalancerCount; i++) { + for (int i = 0; i < count; i++) { loadBalancers.add( - new LoadBalancer("LB-"+ i + "-Z-"+zone.value(), + new LoadBalancer("LB-" + i + "-Z-" + zone.value(), new TenantId(applicationId.tenant().value()), new com.yahoo.vespa.hosted.controller.api.identifiers.ApplicationId(applicationId.application().value()), new InstanceId(applicationId.instance().value()), - ClusterSpec.Id.from("cluster-"+i), - HostName.from("loadbalancer-" + i + "-zone-" + zone.value()) + ClusterSpec.Id.from("cluster-" + i), + HostName.from("loadbalancer-" + i + "-" + applicationId.serializedForm() + "-zone-" + zone.value()) )); } return loadBalancers; } + } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/LoadBalancerAliasSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/LoadBalancerAliasSerializerTest.java new file mode 100644 index 00000000000..6ef15be775e --- /dev/null +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/LoadBalancerAliasSerializerTest.java @@ -0,0 +1,35 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.persistence; + +import com.google.common.collect.ImmutableSet; +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.HostName; +import com.yahoo.vespa.hosted.controller.application.LoadBalancerAlias; +import org.junit.Test; + +import java.util.Set; + +import static org.junit.Assert.assertEquals; + +/** + * @author mortent + */ +public class LoadBalancerAliasSerializerTest { + + @Test + public void test_serialization() { + LoadBalancerAliasSerializer serializer = new LoadBalancerAliasSerializer(); + ApplicationId owner = ApplicationId.defaultId(); + Set<LoadBalancerAlias> names = ImmutableSet.of(new LoadBalancerAlias(owner, + "record-id-1", + HostName.from("my-pretty-alias"), + HostName.from("long-and-ugly-name")), + new LoadBalancerAlias(owner, + "record-id-2", + HostName.from("my-pretty-alias-2"), + HostName.from("long-and-ugly-name-2"))); + Set<LoadBalancerAlias> serialized = serializer.fromSlime(owner, serializer.toSlime(names)); + assertEquals(names, serialized); + } + +} diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/LoadBalancerNameSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/LoadBalancerNameSerializerTest.java deleted file mode 100644 index a66fe127cd5..00000000000 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/LoadBalancerNameSerializerTest.java +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.hosted.controller.persistence; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import com.yahoo.config.provision.ApplicationId; -import com.yahoo.vespa.hosted.controller.api.integration.dns.RecordId; -import com.yahoo.vespa.hosted.controller.api.integration.dns.RecordName; -import com.yahoo.vespa.hosted.controller.loadbalancer.LoadBalancerName; -import org.junit.Test; - -import java.io.IOException; -import java.util.List; -import java.util.Map; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.junit.Assert.assertThat; - -/** - * @author mortent - */ -public class LoadBalancerNameSerializerTest { - - @Test - public void test_serialization() throws IOException { - LoadBalancerNameSerializer serializer = new LoadBalancerNameSerializer(); - ImmutableMap<ApplicationId, List<LoadBalancerName>> lbnames = ImmutableMap.of( - ApplicationId.from("foo", "bar", "default"), Lists.newArrayList(new LoadBalancerName(new RecordId("123.4123.:124123"), RecordName.from("foo.bar")))); - Map<ApplicationId, List<LoadBalancerName>> deserialized = serializer.fromSlime(serializer.toSlime(lbnames)); - - assertThat(deserialized, equalTo(lbnames)); - } -}
\ No newline at end of file diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json index 75e98d2d5e9..169c86fabbe 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json @@ -34,7 +34,7 @@ "name": "JobRunner" }, { - "name": "LoadBalancerMaintainer" + "name": "LoadBalancerAliasMaintainer" }, { "name": "MetricsReporter" |