summaryrefslogtreecommitdiffstats
path: root/controller-api
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2019-02-07 13:08:08 +0100
committerMartin Polden <mpolden@mpolden.no>2019-02-12 14:15:29 +0100
commit85fd303379221040adcf2984b3c5e13e20ea048c (patch)
treedf9ca62541fdfe00e01a1cc41a0d781062e5660c /controller-api
parent6cd73b95dcdcf95a07a726aab88147c2aa19a029 (diff)
Allow NameService to create ALIAS records
Diffstat (limited to 'controller-api')
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/AliasTarget.java59
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/MemoryNameService.java41
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/NameService.java4
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/Record.java1
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/RecordData.java4
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/RecordId.java4
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/RecordName.java4
7 files changed, 103 insertions, 14 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/AliasTarget.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/AliasTarget.java
new file mode 100644
index 00000000000..e7d7cfe620d
--- /dev/null
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/AliasTarget.java
@@ -0,0 +1,59 @@
+// 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.api.integration.dns;
+
+import com.yahoo.config.provision.HostName;
+import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
+
+import java.util.Objects;
+
+/**
+ * Represents the target of an ALIAS record.
+ *
+ * @author mpolden
+ */
+public class AliasTarget {
+
+ private final HostName name;
+ private final String dnsZone;
+ private final ZoneId zone;
+
+ public AliasTarget(HostName name, String dnsZone, ZoneId zone) {
+ this.name = Objects.requireNonNull(name, "name must be non-null");
+ this.dnsZone = Objects.requireNonNull(dnsZone, "dnsZone must be non-null");
+ this.zone = Objects.requireNonNull(zone, "zone must be non-null");
+ }
+
+ /** DNS name of this */
+ public HostName name() {
+ return name;
+ }
+
+ /** DNS zone of this */
+ public String dnsZone() {
+ return dnsZone;
+ }
+
+ /** The zone where this exists */
+ public ZoneId zone() {
+ return zone;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ AliasTarget that = (AliasTarget) o;
+ return name.equals(that.name);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("rotation target %s [zone: %s] in %s", name, dnsZone, zone);
+ }
+
+}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/MemoryNameService.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/MemoryNameService.java
index 105d2626dcd..46a6d1c35ad 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/MemoryNameService.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/MemoryNameService.java
@@ -2,10 +2,14 @@
package com.yahoo.vespa.hosted.controller.api.integration.dns;
+import java.util.Collection;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
@@ -16,22 +20,37 @@ import java.util.stream.Collectors;
*/
public class MemoryNameService implements NameService {
- private final Map<RecordId, Record> records = new HashMap<>();
+ private final Map<RecordId, Set<Record>> records = new HashMap<>();
- public Map<RecordId, Record> records() {
+ public Map<RecordId, Set<Record>> records() {
return Collections.unmodifiableMap(records);
}
@Override
- public RecordId createCname(RecordName alias, RecordData canonicalName) {
+ public RecordId createCname(RecordName name, RecordData canonicalName) {
RecordId id = new RecordId(UUID.randomUUID().toString());
- records.put(id, new Record(id, Record.Type.CNAME, alias, canonicalName));
+ records.put(id, Set.of(new Record(id, Record.Type.CNAME, name, canonicalName)));
+ return id;
+ }
+
+ @Override
+ public RecordId createAlias(RecordName name, Set<AliasTarget> targets) {
+ RecordId id = new RecordId(UUID.randomUUID().toString());
+ Set<Record> records = targets.stream()
+ .sorted((a, b) -> Comparator.comparing(AliasTarget::name).compare(a, b))
+ .map(target -> new Record(id, Record.Type.ALIAS, name,
+ RecordData.fqdn(target.name().value())))
+ .collect(Collectors.toCollection(LinkedHashSet::new));
+ // Satisfy idempotency contract of interface
+ findRecords(Record.Type.ALIAS, name).stream().map(Record::id).forEach(this::removeRecord);
+ this.records.put(id, records);
return id;
}
@Override
public List<Record> findRecords(Record.Type type, RecordName name) {
return records.values().stream()
+ .flatMap(Collection::stream)
.filter(record -> record.type() == type && record.name().equals(name))
.collect(Collectors.toUnmodifiableList());
}
@@ -39,17 +58,29 @@ public class MemoryNameService implements NameService {
@Override
public List<Record> findRecords(Record.Type type, RecordData data) {
return records.values().stream()
+ .flatMap(Collection::stream)
.filter(record -> record.type() == type && record.data().equals(data))
.collect(Collectors.toUnmodifiableList());
}
@Override
public void updateRecord(RecordId id, RecordData newData) {
- records.computeIfPresent(id, (k, record) -> new Record(id, record.type(), record.name(), newData));
+ records.computeIfPresent(id, (k, records) -> {
+ if (records.isEmpty()) {
+ throw new IllegalArgumentException("No record with data '" + newData.asString() + "' exists");
+ }
+ if (records.size() > 1) {
+ throw new IllegalArgumentException("Cannot update multi-value record '" + id.asString() + "' with '" +
+ newData.asString() + "'");
+ }
+ Record existing = records.iterator().next();
+ return Set.of(new Record(id, existing.type(), existing.name(), newData));
+ });
}
@Override
public void removeRecord(RecordId id) {
records.remove(id);
}
+
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/NameService.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/NameService.java
index 170196fd483..537460c8b1e 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/NameService.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/NameService.java
@@ -2,6 +2,7 @@
package com.yahoo.vespa.hosted.controller.api.integration.dns;
import java.util.List;
+import java.util.Set;
/**
* A managed DNS service.
@@ -18,6 +19,9 @@ public interface NameService {
*/
RecordId createCname(RecordName alias, RecordData canonicalName);
+ /** Create a non-standard ALIAS record pointing to given targets. Implementations of this are expected to be idempotent */
+ RecordId createAlias(RecordName name, Set<AliasTarget> targets);
+
/** Find records matching type and name */
List<Record> findRecords(Record.Type type, RecordName name);
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/Record.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/Record.java
index dd9747ce5ca..218fc9f5266 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/Record.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/Record.java
@@ -45,6 +45,7 @@ public class Record {
public enum Type {
A,
AAAA,
+ ALIAS,
CNAME,
MX,
NS,
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/RecordData.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/RecordData.java
index e0d19e0fff9..6c765efd35a 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/RecordData.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/RecordData.java
@@ -37,9 +37,7 @@ public class RecordData {
@Override
public String toString() {
- return "RecordValue{" +
- "value='" + data + '\'' +
- '}';
+ return data;
}
/** Create a new record containing the given data */
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/RecordId.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/RecordId.java
index 2aa3f4a810e..ed628f0c827 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/RecordId.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/RecordId.java
@@ -22,9 +22,7 @@ public class RecordId {
@Override
public String toString() {
- return "RecordId{" +
- "id='" + id + '\'' +
- '}';
+ return id;
}
@Override
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/RecordName.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/RecordName.java
index aa239ece588..d3abad9fb62 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/RecordName.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/RecordName.java
@@ -35,9 +35,7 @@ public class RecordName {
@Override
public String toString() {
- return "RecordName{" +
- "name='" + name + '\'' +
- '}';
+ return name;
}
public static RecordName from(String name) {