aboutsummaryrefslogtreecommitdiffstats
path: root/controller-api/src/main/java/com/yahoo
diff options
context:
space:
mode:
Diffstat (limited to 'controller-api/src/main/java/com/yahoo')
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/model/DeploymentData.java8
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/ZmsClientMock.java5
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/AliasTarget.java4
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/DirectTarget.java57
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/LatencyAliasTarget.java6
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/LatencyDirectTarget.java66
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/MemoryNameService.java19
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/NameService.java9
-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/WeightedAliasTarget.java6
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/WeightedDirectTarget.java70
11 files changed, 244 insertions, 7 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/model/DeploymentData.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/model/DeploymentData.java
index a35d01f6891..d3331c3cfd4 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/model/DeploymentData.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/model/DeploymentData.java
@@ -5,6 +5,7 @@ import com.yahoo.component.Version;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.CloudAccount;
import com.yahoo.config.provision.DockerImage;
+import com.yahoo.config.provision.Tags;
import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.vespa.athenz.api.AthenzDomain;
import com.yahoo.vespa.hosted.controller.api.integration.billing.Quota;
@@ -22,12 +23,14 @@ import static java.util.Objects.requireNonNull;
/**
* Data pertaining to a deployment to be done on a config server.
+ * Accessor names must match the names in com.yahoo.vespa.config.server.session.PrepareParams.
*
* @author jonmv
*/
public class DeploymentData {
private final ApplicationId instance;
+ private final Tags tags;
private final ZoneId zone;
private final byte[] applicationPackage;
private final Version platform;
@@ -41,7 +44,7 @@ public class DeploymentData {
private final Optional<CloudAccount> cloudAccount;
private final boolean dryRun;
- public DeploymentData(ApplicationId instance, ZoneId zone, byte[] applicationPackage, Version platform,
+ public DeploymentData(ApplicationId instance, Tags tags, ZoneId zone, byte[] applicationPackage, Version platform,
Set<ContainerEndpoint> containerEndpoints,
Optional<EndpointCertificateMetadata> endpointCertificateMetadata,
Optional<DockerImage> dockerImageRepo,
@@ -51,6 +54,7 @@ public class DeploymentData {
List<X509Certificate> operatorCertificates,
Optional<CloudAccount> cloudAccount, boolean dryRun) {
this.instance = requireNonNull(instance);
+ this.tags = requireNonNull(tags);
this.zone = requireNonNull(zone);
this.applicationPackage = requireNonNull(applicationPackage);
this.platform = requireNonNull(platform);
@@ -69,6 +73,8 @@ public class DeploymentData {
return instance;
}
+ public Tags tags() { return tags; }
+
public ZoneId zone() {
return zone;
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/ZmsClientMock.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/ZmsClientMock.java
index 4e5f2ab64cb..28bb9182c6a 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/ZmsClientMock.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/ZmsClientMock.java
@@ -133,6 +133,11 @@ public class ZmsClientMock implements ZmsClient {
return new ArrayList<>(athenz.domains.keySet());
}
+ public List<AthenzDomain> getDomainListByAccount(String id) {
+ log("getDomainListById()");
+ return new ArrayList<>();
+ }
+
@Override
public boolean hasAccess(AthenzResourceName resource, String action, AthenzIdentity identity) {
log("hasAccess(resource=%s, action=%s, identity=%s)", resource, action, identity);
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
index 1659a87acb3..7ccbcf2a954 100644
--- 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
@@ -59,8 +59,8 @@ public sealed abstract class AliasTarget permits LatencyAliasTarget, WeightedAli
public static AliasTarget unpack(RecordData data) {
String[] parts = data.asString().split("/");
switch (parts[0]) {
- case "latency": return LatencyAliasTarget.unpack(data);
- case "weighted": return WeightedAliasTarget.unpack(data);
+ case LatencyAliasTarget.TARGET_TYPE: return LatencyAliasTarget.unpack(data);
+ case WeightedAliasTarget.TARGET_TYPE: return WeightedAliasTarget.unpack(data);
}
throw new IllegalArgumentException("Unknown alias type '" + parts[0] + "'");
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/DirectTarget.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/DirectTarget.java
new file mode 100644
index 00000000000..c3cedf93841
--- /dev/null
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/DirectTarget.java
@@ -0,0 +1,57 @@
+// Copyright Yahoo. 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 java.util.Objects;
+
+/**
+ * Same as {@link AliasTarget}, except for targets outside AWS (cannot be targeted with ALIAS record).
+ *
+ * @author freva
+ */
+public sealed abstract class DirectTarget permits LatencyDirectTarget, WeightedDirectTarget {
+
+ private final RecordData recordData;
+ private final String id;
+
+ protected DirectTarget(RecordData recordData, String id) {
+ this.recordData = Objects.requireNonNull(recordData, "recordData must be non-null");
+ this.id = Objects.requireNonNull(id, "id must be non-null");
+ }
+
+ /** A unique identifier of this record within the record group */
+ public String id() {
+ return id;
+ }
+
+ /** Data in this, e.g. IP address for records of type A */
+ public RecordData recordData() {
+ return recordData;
+ }
+
+ /** Returns the fields in this encoded as record data */
+ public abstract RecordData pack();
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ DirectTarget that = (DirectTarget) o;
+ return recordData.equals(that.recordData) && id.equals(that.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(recordData, id);
+ }
+
+ /** Unpack target from given record data */
+ public static DirectTarget unpack(RecordData data) {
+ String[] parts = data.asString().split("/");
+ return switch (parts[0]) {
+ case LatencyDirectTarget.TARGET_TYPE -> LatencyDirectTarget.unpack(data);
+ case WeightedDirectTarget.TARGET_TYPE -> WeightedDirectTarget.unpack(data);
+ default -> throw new IllegalArgumentException("Unknown alias type '" + parts[0] + "'");
+ };
+ }
+
+}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/LatencyAliasTarget.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/LatencyAliasTarget.java
index 70c89b05f09..00e5218dead 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/LatencyAliasTarget.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/LatencyAliasTarget.java
@@ -13,6 +13,8 @@ import java.util.Objects;
*/
public final class LatencyAliasTarget extends AliasTarget {
+ static final String TARGET_TYPE = "latency";
+
private final ZoneId zone;
public LatencyAliasTarget(DomainName name, String dnsZone, ZoneId zone) {
@@ -27,7 +29,7 @@ public final class LatencyAliasTarget extends AliasTarget {
@Override
public RecordData pack() {
- return RecordData.from("latency/" + name().value() + "/" + dnsZone() + "/" + id());
+ return RecordData.from(String.join("/", TARGET_TYPE, name().value(), dnsZone(), id()));
}
@Override
@@ -56,7 +58,7 @@ public final class LatencyAliasTarget extends AliasTarget {
throw new IllegalArgumentException("Expected data to be on format type/name/DNS-zone/zone-id, but got " +
data.asString());
}
- if (!"latency".equals(parts[0])) {
+ if (!TARGET_TYPE.equals(parts[0])) {
throw new IllegalArgumentException("Unexpected type '" + parts[0] + "'");
}
return new LatencyAliasTarget(DomainName.of(parts[1]), parts[2], ZoneId.from(parts[3]));
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/LatencyDirectTarget.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/LatencyDirectTarget.java
new file mode 100644
index 00000000000..09795ae08a7
--- /dev/null
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/LatencyDirectTarget.java
@@ -0,0 +1,66 @@
+// Copyright Yahoo. 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.zone.ZoneId;
+
+import java.util.Objects;
+
+/**
+ * An implementation of {@link DirectTarget} that uses latency-based routing.
+ *
+ * @author freva
+ */
+public final class LatencyDirectTarget extends DirectTarget {
+
+ static final String TARGET_TYPE = "latency";
+
+ private final ZoneId zone;
+
+ public LatencyDirectTarget(RecordData recordData, ZoneId zone) {
+ super(recordData, zone.value());
+ this.zone = Objects.requireNonNull(zone);
+ }
+
+ /** The zone this record points to */
+ public ZoneId zone() {
+ return zone;
+ }
+
+ @Override
+ public RecordData pack() {
+ return RecordData.from(String.join("/", TARGET_TYPE, recordData().asString(), id()));
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ if (!super.equals(o)) return false;
+ LatencyDirectTarget that = (LatencyDirectTarget) o;
+ return zone.equals(that.zone);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), zone);
+ }
+
+ @Override
+ public String toString() {
+ return "latency target for " + recordData() + " [id=" + id() + "]";
+ }
+
+ /** Unpack latency alias from given record data */
+ public static LatencyDirectTarget unpack(RecordData data) {
+ var parts = data.asString().split("/");
+ if (parts.length != 3) {
+ throw new IllegalArgumentException("Expected data to be on format target-type/record-data/zone-id, but got " +
+ data.asString());
+ }
+ if (!TARGET_TYPE.equals(parts[0])) {
+ throw new IllegalArgumentException("Unexpected type '" + parts[0] + "'");
+ }
+ return new LatencyDirectTarget(RecordData.from(parts[1]), ZoneId.from(parts[2]));
+ }
+
+}
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-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/WeightedAliasTarget.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/WeightedAliasTarget.java
index 6a61b62f3a4..ca01c713e93 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/WeightedAliasTarget.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/WeightedAliasTarget.java
@@ -16,6 +16,8 @@ import java.util.Objects;
*/
public final class WeightedAliasTarget extends AliasTarget {
+ static final String TARGET_TYPE = "weighted";
+
private final long weight;
public WeightedAliasTarget(DomainName name, String dnsZone, ZoneId zone, long weight) {
@@ -31,7 +33,7 @@ public final class WeightedAliasTarget extends AliasTarget {
@Override
public RecordData pack() {
- return RecordData.from("weighted/" + name().value() + "/" + dnsZone() + "/" + id() + "/" + weight);
+ return RecordData.from(String.join("/", TARGET_TYPE, name().value(), dnsZone(), id(), Long.toString(weight)));
}
@Override
@@ -60,7 +62,7 @@ public final class WeightedAliasTarget extends AliasTarget {
throw new IllegalArgumentException("Expected data to be on format type/name/DNS-zone/zone-id/weight, " +
"but got " + data.asString());
}
- if (!"weighted".equals(parts[0])) {
+ if (!TARGET_TYPE.equals(parts[0])) {
throw new IllegalArgumentException("Unexpected type '" + parts[0] + "'");
}
return new WeightedAliasTarget(DomainName.of(parts[1]), parts[2], ZoneId.from(parts[3]),
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/WeightedDirectTarget.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/WeightedDirectTarget.java
new file mode 100644
index 00000000000..b899cb57b60
--- /dev/null
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/dns/WeightedDirectTarget.java
@@ -0,0 +1,70 @@
+// Copyright Yahoo. 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.zone.ZoneId;
+
+import java.util.Objects;
+
+/**
+ * An implementation of {@link DirectTarget} where is requests are answered based on the weight assigned to the
+ * record, as a proportion of the total weight for all records having the same DNS name.
+ *
+ * The portion of received traffic is calculated as follows: (record weight / sum of the weights of all records).
+ *
+ * @author freva
+ */
+public final class WeightedDirectTarget extends DirectTarget {
+
+ static final String TARGET_TYPE = "weighted";
+
+ private final long weight;
+
+ public WeightedDirectTarget(RecordData recordData, ZoneId zone, long weight) {
+ super(recordData, zone.value());
+ this.weight = weight;
+ if (weight < 0) throw new IllegalArgumentException("Weight cannot be negative");
+ }
+
+ /** The weight of this target */
+ public long weight() {
+ return weight;
+ }
+
+ @Override
+ public RecordData pack() {
+ return RecordData.from(String.join("/", TARGET_TYPE, recordData().asString(), id(), Long.toString(weight)));
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ if (!super.equals(o)) return false;
+ WeightedDirectTarget that = (WeightedDirectTarget) o;
+ return weight == that.weight;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), weight);
+ }
+
+ @Override
+ public String toString() {
+ return "weighted target for " + recordData() + "[id=" + id() + ",weight=" + weight + "]";
+ }
+
+ /** Unpack weighted alias from given record data */
+ public static WeightedDirectTarget unpack(RecordData data) {
+ var parts = data.asString().split("/");
+ if (parts.length != 4) {
+ throw new IllegalArgumentException("Expected data to be on format target-type/record-data/zone-id/weight, " +
+ "but got " + data.asString());
+ }
+ if (!TARGET_TYPE.equals(parts[0])) {
+ throw new IllegalArgumentException("Unexpected type '" + parts[0] + "'");
+ }
+ return new WeightedDirectTarget(RecordData.from(parts[1]), ZoneId.from(parts[2]), Long.parseLong(parts[3]));
+ }
+
+}