aboutsummaryrefslogtreecommitdiffstats
path: root/controller-server
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2019-12-11 21:28:43 -0800
committerMartin Polden <mpolden@mpolden.no>2019-12-11 21:39:44 -0800
commitf59f673ccf0e235856700c23c2d140f115347165 (patch)
treebf1e29f586a3bbaf7d051c3f633a3279fd1cabd0 /controller-server
parent4e8528eecad760a1abf4146168e87bc449ba4e77 (diff)
Preserve DNS records when LB is reprovisioned
Uniqueness of a `RoutingPolicy` cannot be determined by its `canonicalHostname`, because the latter is unique for every newly provisioned load balancer, which means that a distinct cluster may end up with multiple routing policies. This change ensures that only one `RoutingPolicy` can exist per application/cluster/zone.
Diffstat (limited to 'controller-server')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/RoutingPolicy.java11
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPolicies.java10
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPoliciesTest.java48
3 files changed, 57 insertions, 12 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/RoutingPolicy.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/RoutingPolicy.java
index e55bbaf6acc..80a62d94f2e 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/RoutingPolicy.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/RoutingPolicy.java
@@ -14,7 +14,8 @@ import java.util.Optional;
import java.util.Set;
/**
- * Represents the DNS routing policy for a load balancer.
+ * Represents the DNS routing policy for a load balancer. A routing policy is uniquely identified by its owner, cluster
+ * and zone.
*
* @author mortent
* @author mpolden
@@ -90,13 +91,15 @@ public class RoutingPolicy {
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
- RoutingPolicy policy = (RoutingPolicy) o;
- return canonicalName.equals(policy.canonicalName);
+ RoutingPolicy that = (RoutingPolicy) o;
+ return owner.equals(that.owner) &&
+ cluster.equals(that.cluster) &&
+ zone.equals(that.zone);
}
@Override
public int hashCode() {
- return Objects.hash(canonicalName);
+ return Objects.hash(owner, cluster, zone);
}
@Override
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPolicies.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPolicies.java
index 3dc12f422c6..603757e099d 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPolicies.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPolicies.java
@@ -147,17 +147,11 @@ public class RoutingPolicies {
LOGGER.log(LogLevel.WARNING, "Removing " + removalCandidates + ". Active load balancers " +
activeLoadBalancers);
}
- removalCandidates.forEach(allPolicies::remove);
-
- // Find CNAMEs in use
- var cnamesUsed = allPolicies.stream()
- .map(policy -> policy.endpointIn(controller.system()).dnsName())
- .collect(Collectors.toSet());
for (var policy : removalCandidates) {
var dnsName = policy.endpointIn(controller.system()).dnsName();
- if ( ! cnamesUsed.contains(dnsName))
- controller.nameServiceForwarder().removeRecords(Record.Type.CNAME, RecordName.from(dnsName), Priority.normal);
+ controller.nameServiceForwarder().removeRecords(Record.Type.CNAME, RecordName.from(dnsName), Priority.normal);
+ allPolicies.remove(policy);
}
db.writeRoutingPolicies(loadBalancers.application, allPolicies);
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPoliciesTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPoliciesTest.java
index f78873bae09..1bb20296bd2 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPoliciesTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPoliciesTest.java
@@ -307,6 +307,47 @@ public class RoutingPoliciesTest {
assertEquals(1, tester.policiesOf(devInstance).size());
assertEquals(Set.of("c0.user.app1.tenant1.us-east-1.dev.vespa.oath.cloud"), tester.recordNames());
}
+
+ @Test
+ public void reprovisioning_load_balancer_preserves_cname_record() {
+ var tester = new RoutingPoliciesTester();
+ var context = tester.newDeploymentContext("tenant1", "app1", "default");
+
+ // Initial load balancer is provisioned
+ tester.provisionLoadBalancers(1, context.instanceId(), zone1);
+ var applicationPackage = new ApplicationPackageBuilder()
+ .region(zone1.region())
+ .build();
+
+ // Application is deployed
+ context.submit(applicationPackage).deploy();
+ var expectedRecords = Set.of(
+ "c0.app1.tenant1.us-west-1.vespa.oath.cloud"
+ );
+ assertEquals(expectedRecords, tester.recordNames());
+ assertEquals(1, tester.policiesOf(context.instanceId()).size());
+
+ // Application is removed and the load balancer is deprovisioned
+ tester.controllerTester().controller().applications().deactivate(context.instanceId(), zone1);
+ tester.controllerTester().configServer().removeLoadBalancers(context.instanceId(), zone1);
+
+ // Load balancer for the same application is provisioned again, but with a different hostname
+ var newHostname = HostName.from("new-hostname");
+ var loadBalancer = new LoadBalancer("LB-0-Z-" + zone1.value(),
+ context.instanceId(),
+ ClusterSpec.Id.from("c0"),
+ newHostname,
+ LoadBalancer.State.active,
+ Optional.of("dns-zone-1"));
+ tester.controllerTester().configServer().addLoadBalancers(zone1, List.of(loadBalancer));
+
+ // Application redeployment preserves DNS record
+ context.submit(applicationPackage).deploy();
+ assertEquals(expectedRecords, tester.recordNames());
+ assertEquals(1, tester.policiesOf(context.instanceId()).size());
+ assertEquals("CNAME points to current load blancer", newHostname.value() + ".",
+ tester.cnameDataOf(expectedRecords.iterator().next()).get(0));
+ }
private static List<LoadBalancer> createLoadBalancers(ZoneId zone, ApplicationId application, int count) {
List<LoadBalancer> loadBalancers = new ArrayList<>();
@@ -368,6 +409,13 @@ public class RoutingPoliciesTest {
.collect(Collectors.toList());
}
+ private List<String> cnameDataOf(String name) {
+ return tester.controllerTester().nameService().findRecords(Record.Type.CNAME, RecordName.from(name)).stream()
+ .map(Record::data)
+ .map(RecordData::asString)
+ .collect(Collectors.toList());
+ }
+
}
}