aboutsummaryrefslogtreecommitdiffstats
path: root/config-provisioning
diff options
context:
space:
mode:
authorjonmv <venstad@gmail.com>2023-01-18 13:29:34 +0100
committerjonmv <venstad@gmail.com>2023-01-18 13:29:34 +0100
commit0cb625f5fd5f94b4b8025a9d4f9b546c7ec94d41 (patch)
tree1f4c98f26d6dc4b339ce26c4f3b550e186881300 /config-provisioning
parenta395e87d6073c5b2d09dee8fdd2f5fb43f8192d4 (diff)
Revert "Merge pull request #25614 from vespa-engine/revert-25587-jonmv/private-endpoints"
This reverts commit 7b736f0a09444664cff118eac5b28e608632de72, reversing changes made to 6c457e6dd5993ec2ef15177dab4a16e3d3702b85.
Diffstat (limited to 'config-provisioning')
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/ClusterMembership.java10
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java28
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/LoadBalancerSettings.java20
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/ZoneEndpoint.java132
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializer.java55
-rw-r--r--config-provisioning/src/test/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializerTest.java5
6 files changed, 197 insertions, 53 deletions
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterMembership.java b/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterMembership.java
index 213166447ca..9e8388b6442 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterMembership.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterMembership.java
@@ -20,7 +20,7 @@ public class ClusterMembership {
private final String stringValue;
private ClusterMembership(String stringValue, Version vespaVersion, Optional<DockerImage> dockerImageRepo,
- LoadBalancerSettings loadBalancerSettings) {
+ ZoneEndpoint zoneEndpoint) {
String[] components = stringValue.split("/");
if (components.length < 4)
throw new RuntimeException("Could not parse '" + stringValue + "' to a cluster membership. " +
@@ -49,7 +49,7 @@ public class ClusterMembership {
.exclusive(exclusive)
.combinedId(combinedId.map(ClusterSpec.Id::from))
.dockerImageRepository(dockerImageRepo)
- .loadBalancerSettings(loadBalancerSettings)
+ .loadBalancerSettings(zoneEndpoint)
.stateful(stateful)
.build();
this.index = Integer.parseInt(components[3]);
@@ -125,12 +125,12 @@ public class ClusterMembership {
public String toString() { return stringValue(); }
public static ClusterMembership from(String stringValue, Version vespaVersion, Optional<DockerImage> dockerImageRepo) {
- return from(stringValue, vespaVersion, dockerImageRepo, LoadBalancerSettings.empty);
+ return from(stringValue, vespaVersion, dockerImageRepo, ZoneEndpoint.defaultEndpoint);
}
public static ClusterMembership from(String stringValue, Version vespaVersion, Optional<DockerImage> dockerImageRepo,
- LoadBalancerSettings loadBalancerSettings) {
- return new ClusterMembership(stringValue, vespaVersion, dockerImageRepo, loadBalancerSettings);
+ ZoneEndpoint zoneEndpoint) {
+ return new ClusterMembership(stringValue, vespaVersion, dockerImageRepo, zoneEndpoint);
}
public static ClusterMembership from(ClusterSpec cluster, int index) {
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java b/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java
index 153b305dc01..196255a8342 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java
@@ -24,12 +24,12 @@ public final class ClusterSpec {
private final boolean exclusive;
private final Optional<Id> combinedId;
private final Optional<DockerImage> dockerImageRepo;
- private final LoadBalancerSettings loadBalancerSettings;
+ private final ZoneEndpoint zoneEndpoint;
private final boolean stateful;
private ClusterSpec(Type type, Id id, Optional<Group> groupId, Version vespaVersion, boolean exclusive,
Optional<Id> combinedId, Optional<DockerImage> dockerImageRepo,
- LoadBalancerSettings loadBalancerSettings, boolean stateful) {
+ ZoneEndpoint zoneEndpoint, boolean stateful) {
this.type = type;
this.id = id;
this.groupId = groupId;
@@ -47,7 +47,7 @@ public final class ClusterSpec {
if (type.isContent() && !stateful) {
throw new IllegalArgumentException("Cluster of type " + type + " must be stateful");
}
- this.loadBalancerSettings = Objects.requireNonNull(loadBalancerSettings);
+ this.zoneEndpoint = Objects.requireNonNull(zoneEndpoint);
this.stateful = stateful;
}
@@ -63,8 +63,8 @@ public final class ClusterSpec {
/** Returns the docker image (repository + vespa version) we want this cluster to run */
public Optional<String> dockerImage() { return dockerImageRepo.map(repo -> repo.withTag(vespaVersion).asString()); }
- /** Returns any additional load balancer settings for application container clusters. */
- public LoadBalancerSettings loadBalancerSettings() { return loadBalancerSettings; }
+ /** Returns any additional zone endpoint settings for application container clusters. */
+ public ZoneEndpoint zoneEndpoint() { return zoneEndpoint; }
/** Returns the version of Vespa that we want this cluster to run */
public Version vespaVersion() { return vespaVersion; }
@@ -87,15 +87,15 @@ public final class ClusterSpec {
public boolean isStateful() { return stateful; }
public ClusterSpec with(Optional<Group> newGroup) {
- return new ClusterSpec(type, id, newGroup, vespaVersion, exclusive, combinedId, dockerImageRepo, loadBalancerSettings, stateful);
+ return new ClusterSpec(type, id, newGroup, vespaVersion, exclusive, combinedId, dockerImageRepo, zoneEndpoint, stateful);
}
public ClusterSpec withExclusivity(boolean exclusive) {
- return new ClusterSpec(type, id, groupId, vespaVersion, exclusive, combinedId, dockerImageRepo, loadBalancerSettings, stateful);
+ return new ClusterSpec(type, id, groupId, vespaVersion, exclusive, combinedId, dockerImageRepo, zoneEndpoint, stateful);
}
public ClusterSpec exclusive(boolean exclusive) {
- return new ClusterSpec(type, id, groupId, vespaVersion, exclusive, combinedId, dockerImageRepo, loadBalancerSettings, stateful);
+ return new ClusterSpec(type, id, groupId, vespaVersion, exclusive, combinedId, dockerImageRepo, zoneEndpoint, stateful);
}
/** Creates a ClusterSpec when requesting a cluster */
@@ -119,7 +119,7 @@ public final class ClusterSpec {
private Version vespaVersion;
private boolean exclusive = false;
private Optional<Id> combinedId = Optional.empty();
- private LoadBalancerSettings loadBalancerSettings = LoadBalancerSettings.empty;
+ private ZoneEndpoint zoneEndpoint = ZoneEndpoint.defaultEndpoint;
private boolean stateful;
private Builder(Type type, Id id, boolean specification) {
@@ -135,7 +135,7 @@ public final class ClusterSpec {
if (vespaVersion == null) throw new IllegalArgumentException("vespaVersion is required to be set when creating a ClusterSpec with specification()");
} else
if (groupId.isPresent()) throw new IllegalArgumentException("groupId is not allowed to be set when creating a ClusterSpec with request()");
- return new ClusterSpec(type, id, groupId, vespaVersion, exclusive, combinedId, dockerImageRepo, loadBalancerSettings, stateful);
+ return new ClusterSpec(type, id, groupId, vespaVersion, exclusive, combinedId, dockerImageRepo, zoneEndpoint, stateful);
}
public Builder group(Group groupId) {
@@ -168,8 +168,8 @@ public final class ClusterSpec {
return this;
}
- public Builder loadBalancerSettings(LoadBalancerSettings loadBalancerSettings) {
- this.loadBalancerSettings = loadBalancerSettings;
+ public Builder loadBalancerSettings(ZoneEndpoint zoneEndpoint) {
+ this.zoneEndpoint = zoneEndpoint;
return this;
}
@@ -198,12 +198,12 @@ public final class ClusterSpec {
vespaVersion.equals(that.vespaVersion) &&
combinedId.equals(that.combinedId) &&
dockerImageRepo.equals(that.dockerImageRepo) &&
- loadBalancerSettings.equals(that.loadBalancerSettings);
+ zoneEndpoint.equals(that.zoneEndpoint);
}
@Override
public int hashCode() {
- return Objects.hash(type, id, groupId, vespaVersion, exclusive, combinedId, dockerImageRepo, loadBalancerSettings, stateful);
+ return Objects.hash(type, id, groupId, vespaVersion, exclusive, combinedId, dockerImageRepo, zoneEndpoint, stateful);
}
/**
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/LoadBalancerSettings.java b/config-provisioning/src/main/java/com/yahoo/config/provision/LoadBalancerSettings.java
deleted file mode 100644
index 723de25fa87..00000000000
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/LoadBalancerSettings.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.yahoo.config.provision;
-
-import java.util.List;
-
-/**
- * Settings for a load balancer provisioned for an application container cluster.
- *
- * @author jonmv
- */
-public record LoadBalancerSettings(List<String> allowedUrns) {
-
- public static final LoadBalancerSettings empty = new LoadBalancerSettings(List.of());
-
- public LoadBalancerSettings(List<String> allowedUrns) {
- this.allowedUrns = List.copyOf(allowedUrns);
- }
-
- public boolean isEmpty() { return allowedUrns.isEmpty(); }
-
-}
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/ZoneEndpoint.java b/config-provisioning/src/main/java/com/yahoo/config/provision/ZoneEndpoint.java
new file mode 100644
index 00000000000..10e22f8df06
--- /dev/null
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/ZoneEndpoint.java
@@ -0,0 +1,132 @@
+package com.yahoo.config.provision;
+
+import ai.vespa.validation.Validation;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Settings for a zone endpoint of a deployment.
+ *
+ * TODO: Fix isEmpty
+ * Inline empty and constructor
+ *
+ * @author jonmv
+ */
+public class ZoneEndpoint {
+
+ public static final ZoneEndpoint defaultEndpoint = new ZoneEndpoint(true, false, List.of());
+
+ private final boolean isPublicEndpoint;
+ private final boolean isPrivateEndpoint;
+ private final List<AllowedUrn> allowedUrns;
+
+ public ZoneEndpoint(List<String> allowedUrns) {
+ this(true, true, allowedUrns.stream().map(arn -> new AllowedUrn(AccessType.awsPrivateLink, arn)).toList());
+ }
+
+ public ZoneEndpoint(boolean isPublicEndpoint, boolean isPrivateEndpoint, List<AllowedUrn> allowedUrns) {
+ if ( ! allowedUrns.isEmpty() && ! isPrivateEndpoint)
+ throw new IllegalArgumentException("cannot list allowed urns, without also enabling private visibility");
+ this.isPublicEndpoint = isPublicEndpoint;
+ this.isPrivateEndpoint = isPrivateEndpoint;
+ this.allowedUrns = List.copyOf(allowedUrns);
+ }
+
+ /** Whether this has an endpoint which is visible from the public internet. */
+ public boolean isPublicEndpoint() {
+ return isPublicEndpoint;
+ }
+
+ /** Whether this has an endpoint which is visible through private DNS of the cloud. */
+ public boolean isPrivateEndpoint() {
+ return isPrivateEndpoint;
+ }
+
+ /** List of allowed URNs, for specified private access types. */
+ public List<AllowedUrn> allowedUrns() {
+ return allowedUrns;
+ }
+
+ /** List of URNs for the given access type. */
+ public List<String> allowedUrnsWith(AccessType type) {
+ return allowedUrns.stream().filter(urn -> urn.type == type).map(AllowedUrn::urn).toList();
+ }
+
+ public boolean isDefault() {
+ return equals(defaultEndpoint);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ZoneEndpoint that = (ZoneEndpoint) o;
+ return isPublicEndpoint == that.isPublicEndpoint && isPrivateEndpoint == that.isPrivateEndpoint && allowedUrns.equals(that.allowedUrns);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(isPublicEndpoint, isPrivateEndpoint, allowedUrns);
+ }
+
+ @Override
+ public String toString() {
+ return "ZoneEndpoint{" +
+ "isPublicEndpoint=" + isPublicEndpoint +
+ ", isPrivateEndpoint=" + isPrivateEndpoint +
+ ", allowedUrns=" + allowedUrns +
+ '}';
+ }
+
+ public enum AccessType {
+ awsPrivateLink,
+ gcpServiceConnect,
+ }
+
+ /** A URN allowed to access this (private) endpoint, through a {@link AccessType} method. */
+ public static class AllowedUrn {
+
+ private final AccessType type;
+ private final String urn;
+
+ public AllowedUrn(AccessType type, String urn) {
+ this.type = Objects.requireNonNull(type);
+ this.urn = Validation.requireNonBlank(urn, "URN");
+ }
+
+ /** Type of private connection. */
+ public AccessType type() {
+ return type;
+ }
+
+ /** URN allowed to access this private endpoint. */
+ public String urn() {
+ return urn;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ AllowedUrn that = (AllowedUrn) o;
+ return type == that.type && urn.equals(that.urn);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(type, urn);
+ }
+
+ @Override
+ public String toString() {
+ return "'" + urn + "' through '" +
+ switch (type) {
+ case awsPrivateLink -> "aws-private-link";
+ case gcpServiceConnect -> "gcp-service-connect";
+ } + "'";
+ }
+
+ }
+
+}
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializer.java b/config-provisioning/src/main/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializer.java
index 01bb0ca45ff..64e8a7feb94 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializer.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializer.java
@@ -6,8 +6,10 @@ import com.yahoo.config.provision.AllocatedHosts;
import com.yahoo.config.provision.ClusterMembership;
import com.yahoo.config.provision.DockerImage;
import com.yahoo.config.provision.HostSpec;
-import com.yahoo.config.provision.LoadBalancerSettings;
import com.yahoo.config.provision.NodeResources;
+import com.yahoo.config.provision.ZoneEndpoint;
+import com.yahoo.config.provision.ZoneEndpoint.AllowedUrn;
+import com.yahoo.config.provision.ZoneEndpoint.AccessType;
import com.yahoo.slime.ArrayTraverser;
import com.yahoo.slime.Cursor;
import com.yahoo.slime.Inspector;
@@ -40,8 +42,12 @@ public class AllocatedHostsSerializer {
private static final String hostSpecKey = "hostSpec";
private static final String hostSpecHostNameKey = "hostName";
private static final String hostSpecMembershipKey = "membership";
- private static final String loadBalancerSettingsKey = "loadBalancerSettings";
- private static final String allowedUrnsKey = "allowedUrns";
+ private static final String loadBalancerSettingsKey = "zoneEndpoint";
+ private static final String publicField = "public";
+ private static final String privateField = "private";
+ private static final String allowedUrnsField = "allowedUrns";
+ private static final String accessTypeField = "type";
+ private static final String urnField = "urn";
private static final String realResourcesKey = "realResources";
private static final String advertisedResourcesKey = "advertisedResources";
@@ -85,9 +91,8 @@ public class AllocatedHostsSerializer {
host.membership().ifPresent(membership -> {
object.setString(hostSpecMembershipKey, membership.stringValue());
object.setString(hostSpecVespaVersionKey, membership.cluster().vespaVersion().toFullString());
- if ( ! membership.cluster().loadBalancerSettings().isEmpty())
- membership.cluster().loadBalancerSettings().allowedUrns()
- .forEach(object.setObject(loadBalancerSettingsKey).setArray(allowedUrnsKey)::addString);
+ if ( ! membership.cluster().zoneEndpoint().isDefault())
+ toSlime(object.setObject(loadBalancerSettingsKey), membership.cluster().zoneEndpoint());
membership.cluster().dockerImageRepo().ifPresent(repo -> object.setString(hostSpecDockerImageRepoKey, repo.untagged()));
});
toSlime(host.realResources(), object.setObject(realResourcesKey));
@@ -222,13 +227,41 @@ public class AllocatedHostsSerializer {
object.field(hostSpecDockerImageRepoKey).valid()
? Optional.of(DockerImage.fromString(object.field(hostSpecDockerImageRepoKey).asString()))
: Optional.empty(),
- object.field(loadBalancerSettingsKey).valid()
- ? new LoadBalancerSettings(SlimeUtils.entriesStream(object.field(loadBalancerSettingsKey).field(allowedUrnsKey))
- .map(Inspector::asString)
- .toList())
- : LoadBalancerSettings.empty);
+ zoneEndpoint(object.field(loadBalancerSettingsKey)));
}
+ private static void toSlime(Cursor settingsObject, ZoneEndpoint settings) {
+ settingsObject.setBool(publicField, settings.isPublicEndpoint());
+ settingsObject.setBool(privateField, settings.isPrivateEndpoint());
+ if (settings.isPrivateEndpoint()) {
+ Cursor allowedUrnsArray = settingsObject.setArray(allowedUrnsField);
+ for (AllowedUrn urn : settings.allowedUrns()) {
+ Cursor urnObject = allowedUrnsArray.addObject();
+ urnObject.setString(urnField, urn.urn());
+ urnObject.setString(accessTypeField,
+ switch (urn.type()) {
+ case awsPrivateLink -> "awsPrivateLink";
+ case gcpServiceConnect -> "gcpServiceConnect";
+ });
+ }
+ }
+ }
+
+ private static ZoneEndpoint zoneEndpoint(Inspector settingsObject) {
+ if ( ! settingsObject.valid()) return ZoneEndpoint.defaultEndpoint;
+ return new ZoneEndpoint(settingsObject.field(publicField).asBool(),
+ settingsObject.field(privateField).asBool(),
+ SlimeUtils.entriesStream(settingsObject.field(allowedUrnsField))
+ .map(urnObject -> new AllowedUrn(switch (urnObject.field(accessTypeField).asString()) {
+ case "awsPrivateLink" -> AccessType.awsPrivateLink;
+ case "gcpServiceConnect" -> AccessType.gcpServiceConnect;
+ default -> throw new IllegalArgumentException("unknown service access type in '" + urnObject + "'");
+ },
+ urnObject.field(urnField).asString()))
+ .toList());
+ }
+
+
private static Optional<String> optionalString(Inspector inspector) {
if ( ! inspector.valid()) return Optional.empty();
return Optional.of(inspector.asString());
diff --git a/config-provisioning/src/test/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializerTest.java b/config-provisioning/src/test/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializerTest.java
index bcb3b8cd4aa..3404d7ed55e 100644
--- a/config-provisioning/src/test/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializerTest.java
+++ b/config-provisioning/src/test/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializerTest.java
@@ -6,9 +6,9 @@ import com.yahoo.config.provision.AllocatedHosts;
import com.yahoo.config.provision.ClusterMembership;
import com.yahoo.config.provision.DockerImage;
import com.yahoo.config.provision.HostSpec;
-import com.yahoo.config.provision.LoadBalancerSettings;
import com.yahoo.config.provision.NetworkPorts;
import com.yahoo.config.provision.NodeResources;
+import com.yahoo.config.provision.ZoneEndpoint;
import org.junit.jupiter.api.Test;
import java.io.IOException;
@@ -20,7 +20,6 @@ import java.util.Set;
import static com.yahoo.config.provision.serialization.AllocatedHostsSerializer.fromJson;
import static com.yahoo.config.provision.serialization.AllocatedHostsSerializer.toJson;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.fail;
/**
* @author bratseth
@@ -69,7 +68,7 @@ public class AllocatedHostsSerializerTest {
bigSlowDiskSpeedNode,
anyDiskSpeedNode,
ClusterMembership.from("container/test/0/0", Version.fromString("6.73.1"),
- Optional.empty(), new LoadBalancerSettings(List.of("burn"))),
+ Optional.empty(), new ZoneEndpoint(List.of("burn"))),
Optional.empty(),
Optional.empty(),
Optional.empty()));