diff options
author | Valerij Fredriksen <valerijf@yahooinc.com> | 2022-10-07 12:15:12 +0200 |
---|---|---|
committer | Valerij Fredriksen <valerijf@yahooinc.com> | 2022-10-10 13:32:41 +0200 |
commit | 9511540736b58f9b47fd3656ad5702eb7496666b (patch) | |
tree | 8a7bdf33bb681f5e8dd69a80c7a688fb8b9cf40f | |
parent | b5cce0b85802e7b512bac7c1c2f2824f6d3f80a3 (diff) |
Support creating DIRECT records
7 files changed, 65 insertions, 12 deletions
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 18d7bc53035..9a9270bdf7f 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 @@ -54,6 +54,20 @@ public class MemoryNameService implements NameService { } @Override + public List<Record> createDirect(RecordName name, Set<DirectTarget> targets) { + var records = targets.stream() + .sorted((a, b) -> Comparator.comparing((DirectTarget target) -> target.recordData().asString()).compare(a, b)) + .map(d -> new Record(Record.Type.DIRECT, name, d.pack())) + .collect(Collectors.toList()); + // Satisfy idempotency contract of interface + for (var r1 : records) { + this.records.removeIf(r2 -> conflicts(r1, r2)); + } + this.records.addAll(records); + return records; + } + + @Override public List<Record> createTxtRecords(RecordName name, List<RecordData> txtData) { var records = txtData.stream() .map(data -> new Record(Record.Type.TXT, name, data)) @@ -122,6 +136,11 @@ public class MemoryNameService implements NameService { AliasTarget t2 = AliasTarget.unpack(r2.data()); return t1.name().equals(t2.name()); // ALIAS records require distinct targets } + if (r1.type() == Record.Type.DIRECT && r1.type() == r2.type()) { + DirectTarget t1 = DirectTarget.unpack(r1.data()); + DirectTarget t2 = DirectTarget.unpack(r2.data()); + return t1.id().equals(t2.id()); // DIRECT records require distinct IDs + } return true; // Anything else is considered a conflict } 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 505ff3850ab..72e983680d9 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 @@ -31,6 +31,15 @@ public interface NameService { List<Record> createAlias(RecordName name, Set<AliasTarget> targets); /** + * Create a non-standard record pointing to given targets. Implementations of this are expected to be + * idempotent + * + * @param targets Targets that should be resolved by this name. + * @return The created records. One per target. + */ + List<Record> createDirect(RecordName name, Set<DirectTarget> targets); + + /** * Create a new TXT record containing the provided data. * @param name Name of the created record * @param txtRecords TXT data values for the record, each consisting of one or more space-separated double-quoted 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 2f9312b2f89..e76445faa60 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 @@ -55,6 +55,7 @@ public record Record(Type type, AAAA, ALIAS, CNAME, + DIRECT, MX, NS, PTR, diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/dns/CreateRecords.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/dns/CreateRecords.java index d0c901ccb36..b97fdde560e 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/dns/CreateRecords.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/dns/CreateRecords.java @@ -2,6 +2,7 @@ package com.yahoo.vespa.hosted.controller.dns; import com.yahoo.vespa.hosted.controller.api.integration.dns.AliasTarget; +import com.yahoo.vespa.hosted.controller.api.integration.dns.DirectTarget; 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.RecordName; @@ -28,8 +29,8 @@ public class CreateRecords implements NameServiceRequest { this.name = requireOneOf(Record::name, records); this.type = requireOneOf(Record::type, records); this.records = List.copyOf(Objects.requireNonNull(records, "records must be non-null")); - if (type != Record.Type.ALIAS && type != Record.Type.TXT) { - throw new IllegalArgumentException("Records of type " + type + "are not supported: " + records); + if (type != Record.Type.ALIAS && type != Record.Type.TXT && type != Record.Type.DIRECT) { + throw new IllegalArgumentException("Records of type " + type + " are not supported: " + records); } } @@ -40,14 +41,18 @@ public class CreateRecords implements NameServiceRequest { @Override public void dispatchTo(NameService nameService) { switch (type) { - case ALIAS: + case ALIAS -> { var targets = records.stream().map(Record::data).map(AliasTarget::unpack).collect(Collectors.toSet()); nameService.createAlias(name, targets); - break; - case TXT: + } + case DIRECT -> { + var targets = records.stream().map(Record::data).map(DirectTarget::unpack).collect(Collectors.toSet()); + nameService.createDirect(name, targets); + } + case TXT -> { var dataFields = records.stream().map(Record::data).collect(Collectors.toList()); nameService.createTxtRecords(name, dataFields); - break; + } } } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/dns/NameServiceForwarder.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/dns/NameServiceForwarder.java index 9d2c7918252..57c83280b8b 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/dns/NameServiceForwarder.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/dns/NameServiceForwarder.java @@ -3,6 +3,7 @@ package com.yahoo.vespa.hosted.controller.dns; import com.yahoo.transaction.Mutex; import com.yahoo.vespa.hosted.controller.api.integration.dns.AliasTarget; +import com.yahoo.vespa.hosted.controller.api.integration.dns.DirectTarget; 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; @@ -55,6 +56,14 @@ public class NameServiceForwarder { forward(new CreateRecords(records), priority); } + /** Create or update a DIRECT record with given name and targets */ + public void createDirect(RecordName name, Set<DirectTarget> targets, NameServiceQueue.Priority priority) { + var records = targets.stream() + .map(target -> new Record(Record.Type.DIRECT, name, target.pack())) + .collect(Collectors.toList()); + forward(new CreateRecords(records), priority); + } + /** Create or update a TXT record with given name and data */ public void createTxt(RecordName name, List<RecordData> txtData, NameServiceQueue.Priority priority) { var records = txtData.stream() diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/dns/RemoveRecords.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/dns/RemoveRecords.java index f940d53fab3..6fa7473ad1e 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/dns/RemoveRecords.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/dns/RemoveRecords.java @@ -2,6 +2,7 @@ package com.yahoo.vespa.hosted.controller.dns; import com.yahoo.vespa.hosted.controller.api.integration.dns.AliasTarget; +import com.yahoo.vespa.hosted.controller.api.integration.dns.DirectTarget; 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; @@ -69,11 +70,11 @@ public class RemoveRecords implements NameServiceRequest { .stream() .filter(record -> { // Records to remove must match both name and data fields - String dataValue = record.data().asString(); - // If we're comparing an ALIAS record we have to unpack it to access the target name - if (record.type() == Record.Type.ALIAS) { - dataValue = AliasTarget.unpack(record.data()).name().value(); - } + String dataValue = switch (record.type()) { + case ALIAS -> AliasTarget.unpack(record.data()).name().value(); + case DIRECT -> DirectTarget.unpack(record.data()).recordData().asString(); + default -> record.data().asString(); + }; return fqdn(dataValue).equals(fqdn(data.get().asString())); }) .forEach(records::add); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/NameServiceQueueSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/NameServiceQueueSerializerTest.java index 6f0a36690ed..c42d5621a46 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/NameServiceQueueSerializerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/NameServiceQueueSerializerTest.java @@ -7,6 +7,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.dns.LatencyAliasTarget; 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.dns.WeightedDirectTarget; import com.yahoo.vespa.hosted.controller.dns.CreateRecord; import com.yahoo.vespa.hosted.controller.dns.CreateRecords; import com.yahoo.vespa.hosted.controller.dns.NameServiceQueue; @@ -38,8 +39,16 @@ public class NameServiceQueueSerializerTest { new Record(Record.Type.ALIAS, RecordName.from("alias.example.com"), new LatencyAliasTarget(HostName.of("alias2"), "dns-zone-02", - ZoneId.from("prod", "us-north-2")).pack())) + ZoneId.from("prod", "us-north-2")).pack()), + new Record(Record.Type.ALIAS, RecordName.from("alias.example.com"), + new LatencyAliasTarget(HostName.of("alias2"), + "ignored", + ZoneId.from("prod", "us-south-1")).pack())) ), + new CreateRecords(List.of(new Record(Record.Type.DIRECT, RecordName.from("direct.example.com"), + new WeightedDirectTarget(RecordData.from("10.1.2.3"), + ZoneId.from("prod", "us-north-1"), + 100).pack()))), new RemoveRecords(record1.type(), record1.name()), new RemoveRecords(record2.type(), record2.data()) ); |