aboutsummaryrefslogtreecommitdiffstats
path: root/node-repository/src/main
diff options
context:
space:
mode:
authorjonmv <venstad@gmail.com>2023-11-08 17:07:03 +0100
committerjonmv <venstad@gmail.com>2023-11-08 17:07:03 +0100
commit033d5f765fa2d17d9309c89d7e62ce64d0be7d58 (patch)
tree682e258c8faf95c7030148036b4543c437c3886c /node-repository/src/main
parent59ecf3b33f29ab82a61bd888b1a4f1dc60d60027 (diff)
Support an ID seed for LB resource ID hashes
Diffstat (limited to 'node-repository/src/main')
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerInstance.java14
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerService.java10
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerServiceMock.java7
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/SharedLoadBalancerService.java6
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/LoadBalancerSerializer.java13
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/LoadBalancersResponse.java1
6 files changed, 40 insertions, 11 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerInstance.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerInstance.java
index c0931ecbc70..04ea9d20edf 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerInstance.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerInstance.java
@@ -11,6 +11,7 @@ import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
+import java.util.UUID;
/**
* Represents a load balancer instance. This contains the fields that are owned by a {@link LoadBalancerService} and is
@@ -20,6 +21,7 @@ import java.util.Set;
*/
public class LoadBalancerInstance {
+ private final Optional<UUID> idSeed;
private final Optional<DomainName> hostname;
private final Optional<String> ip4Address;
private final Optional<String> ip6Address;
@@ -31,9 +33,10 @@ public class LoadBalancerInstance {
private final List<PrivateServiceId> serviceIds;
private final CloudAccount cloudAccount;
- public LoadBalancerInstance(Optional<DomainName> hostname, Optional<String> ip4Address, Optional<String> ip6Address,
+ public LoadBalancerInstance(Optional<UUID> idSeed, Optional<DomainName> hostname, Optional<String> ip4Address, Optional<String> ip6Address,
Optional<DnsZone> dnsZone, Set<Integer> ports, Set<String> networks, Set<Real> reals,
ZoneEndpoint settings, List<PrivateServiceId> serviceIds, CloudAccount cloudAccount) {
+ this.idSeed = Objects.requireNonNull(idSeed, "idSeed must be non-null");
this.hostname = Objects.requireNonNull(hostname, "hostname must be non-null");
this.ip4Address = Objects.requireNonNull(ip4Address, "ip4Address must be non-null");
this.ip6Address = Objects.requireNonNull(ip6Address, "ip6Address must be non-null");
@@ -51,6 +54,11 @@ public class LoadBalancerInstance {
}
}
+ /** A unique seed to use when generating cloud-specific resource IDs for this load balancer instance. */
+ public Optional<UUID> idSeed() {
+ return idSeed;
+ }
+
/** Fully-qualified domain name of this load balancer. This hostname can be used for query and feed */
public Optional<DomainName> hostname() {
return hostname;
@@ -121,7 +129,7 @@ public class LoadBalancerInstance {
public LoadBalancerInstance with(Set<Real> reals, ZoneEndpoint settings, Optional<PrivateServiceId> serviceId) {
List<PrivateServiceId> ids = new ArrayList<>(serviceIds);
serviceId.filter(id -> ! ids.contains(id)).ifPresent(ids::add);
- return new LoadBalancerInstance(hostname, ip4Address, ip6Address, dnsZone, ports, networks,
+ return new LoadBalancerInstance(idSeed, hostname, ip4Address, ip6Address, dnsZone, ports, networks,
reals, settings, ids,
cloudAccount);
}
@@ -130,7 +138,7 @@ public class LoadBalancerInstance {
public LoadBalancerInstance withServiceIds(List<PrivateServiceId> serviceIds) {
List<PrivateServiceId> ids = new ArrayList<>(serviceIds);
for (PrivateServiceId id : this.serviceIds) if ( ! ids.contains(id)) ids.add(id);
- return new LoadBalancerInstance(hostname, ip4Address, ip6Address, dnsZone, ports, networks, reals, settings, ids, cloudAccount);
+ return new LoadBalancerInstance(idSeed, hostname, ip4Address, ip6Address, dnsZone, ports, networks, reals, settings, ids, cloudAccount);
}
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerService.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerService.java
index 6d41f664fad..40323a4f2d3 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerService.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerService.java
@@ -2,15 +2,20 @@
package com.yahoo.vespa.hosted.provision.lb;
import com.yahoo.config.provision.ClusterSpec;
+import com.yahoo.config.provision.EndpointsChecker.Availability;
+import com.yahoo.config.provision.EndpointsChecker.Endpoint;
import com.yahoo.config.provision.EndpointsChecker.HealthChecker;
import com.yahoo.config.provision.NodeType;
+import java.util.Optional;
+import java.util.UUID;
+
/**
* A managed load balance service.
*
* @author mpolden
*/
-public interface LoadBalancerService extends HealthChecker {
+public interface LoadBalancerService {
/**
* Provisions load balancers from the given specification. Implementations are expected to be idempotent
@@ -40,6 +45,9 @@ public interface LoadBalancerService extends HealthChecker {
/** Returns whether load balancers created by this service can forward traffic to given node and cluster type */
boolean supports(NodeType nodeType, ClusterSpec.Type clusterType);
+ /** See {@link HealthChecker#healthy(Endpoint)}. */
+ Availability healthy(Endpoint endpoint, Optional<UUID> idSeed);
+
/** Load balancer protocols */
enum Protocol {
ipv4,
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerServiceMock.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerServiceMock.java
index df4b83d1543..3b444312b14 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerServiceMock.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerServiceMock.java
@@ -14,6 +14,8 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* @author mpolden
@@ -23,6 +25,7 @@ public class LoadBalancerServiceMock implements LoadBalancerService {
private final Map<LoadBalancerId, LoadBalancerInstance> instances = new HashMap<>();
private boolean throwOnCreate = false;
private boolean supportsProvisioning = true;
+ private final AtomicBoolean uuid = new AtomicBoolean(true);
public Map<LoadBalancerId, LoadBalancerInstance> instances() {
return Collections.unmodifiableMap(instances);
@@ -53,8 +56,10 @@ public class LoadBalancerServiceMock implements LoadBalancerService {
@Override
public LoadBalancerInstance provision(LoadBalancerSpec spec) {
if (throwOnCreate) throw new IllegalStateException("Did not expect a new load balancer to be created");
+ Optional<UUID> idSeed = uuid.getAndSet(false) ? Optional.of(UUID.fromString("c11272ab-d20e-4c86-b808-ffedaa00c480")) : Optional.empty();
var id = new LoadBalancerId(spec.application(), spec.cluster());
var instance = new LoadBalancerInstance(
+ idSeed,
Optional.of(DomainName.of("lb-" + spec.application().toShortString() + "-" + spec.cluster().value())),
Optional.empty(),
Optional.empty(),
@@ -89,7 +94,7 @@ public class LoadBalancerServiceMock implements LoadBalancerService {
}
@Override
- public Availability healthy(Endpoint endpoint) {
+ public Availability healthy(Endpoint endpoint, Optional<UUID> idSeed) {
return Availability.ready;
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/SharedLoadBalancerService.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/SharedLoadBalancerService.java
index e463f5aabe6..eb99e5647df 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/SharedLoadBalancerService.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/SharedLoadBalancerService.java
@@ -11,6 +11,7 @@ import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
+import java.util.UUID;
/**
* This implementation of {@link LoadBalancerService} returns the load balancer(s) that exist by default in the shared
@@ -42,7 +43,8 @@ public class SharedLoadBalancerService implements LoadBalancerService {
private LoadBalancerInstance create(LoadBalancerSpec spec) {
if ( ! spec.settings().isPublicEndpoint())
throw new IllegalArgumentException("non-public endpoints is not supported with " + getClass());
- return new LoadBalancerInstance(Optional.of(DomainName.of(vipHostname)),
+ return new LoadBalancerInstance(Optional.empty(),
+ Optional.of(DomainName.of(vipHostname)),
Optional.empty(),
Optional.empty(),
Optional.empty(),
@@ -72,7 +74,7 @@ public class SharedLoadBalancerService implements LoadBalancerService {
}
@Override
- public Availability healthy(Endpoint endpoint) {
+ public Availability healthy(Endpoint endpoint, Optional<UUID> idSeed) {
return Availability.ready;
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/LoadBalancerSerializer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/LoadBalancerSerializer.java
index 7262daf758b..9e81cd3d3b7 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/LoadBalancerSerializer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/LoadBalancerSerializer.java
@@ -26,7 +26,9 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
+import java.util.UUID;
import java.util.function.Function;
+import java.util.function.Predicate;
/**
* Serializer for load balancers.
@@ -43,6 +45,7 @@ public class LoadBalancerSerializer {
// - CHANGING THE FORMAT OF A FIELD: Don't do it bro.
private static final String idField = "id";
+ private static final String idSeedField = "idSeed";
private static final String hostnameField = "hostname";
private static final String lbIpAddressField = "ipAddress";
private static final String lbIp6AddressField = "ip6Address";
@@ -69,6 +72,7 @@ public class LoadBalancerSerializer {
Cursor root = slime.setObject();
root.setString(idField, loadBalancer.id().serializedForm());
+ loadBalancer.instance().flatMap(LoadBalancerInstance::idSeed).ifPresent(idSeed -> root.setString(idSeedField, idSeed.toString()));
loadBalancer.instance().flatMap(LoadBalancerInstance::hostname).ifPresent(hostname -> root.setString(hostnameField, hostname.value()));
loadBalancer.instance().flatMap(LoadBalancerInstance::ip4Address).ifPresent(ip -> root.setString(lbIpAddressField, ip));
loadBalancer.instance().flatMap(LoadBalancerInstance::ip6Address).ifPresent(ip -> root.setString(lbIp6AddressField, ip));
@@ -124,9 +128,10 @@ public class LoadBalancerSerializer {
Set<String> networks = new LinkedHashSet<>();
object.field(networksField).traverse((ArrayTraverser) (i, network) -> networks.add(network.asString()));
- Optional<DomainName> hostname = optionalString(object.field(hostnameField), Function.identity()).filter(s -> !s.isEmpty()).map(DomainName::of);
- Optional<String> ip4Address = optionalString(object.field(lbIpAddressField), Function.identity()).filter(s -> !s.isEmpty());
- Optional<String> ip6Address = optionalString(object.field(lbIp6AddressField), Function.identity()).filter(s -> !s.isEmpty());
+ Optional<UUID> idSeed = SlimeUtils.optionalString(object.field(idSeedField)).map(UUID::fromString);
+ Optional<DomainName> hostname = SlimeUtils.optionalString(object.field(hostnameField)).map(DomainName::of);
+ Optional<String> ip4Address = SlimeUtils.optionalString(object.field(lbIpAddressField));
+ Optional<String> ip6Address = SlimeUtils.optionalString(object.field(lbIp6AddressField));
Optional<DnsZone> dnsZone = optionalString(object.field(dnsZoneField), DnsZone::new);
ZoneEndpoint settings = zoneEndpoint(object.field(settingsField));
Optional<PrivateServiceId> serviceId = optionalString(object.field(serviceIdField), PrivateServiceId::of);
@@ -136,7 +141,7 @@ public class LoadBalancerSerializer {
CloudAccount cloudAccount = optionalString(object.field(cloudAccountField), CloudAccount::from).orElse(CloudAccount.empty);
Optional<LoadBalancerInstance> instance = hostname.isEmpty() && ip4Address.isEmpty() && ip6Address.isEmpty()
? Optional.empty()
- : Optional.of(new LoadBalancerInstance(hostname, ip4Address, ip6Address, dnsZone, ports, networks, reals, settings, serviceIds, cloudAccount));
+ : Optional.of(new LoadBalancerInstance(idSeed, hostname, ip4Address, ip6Address, dnsZone, ports, networks, reals, settings, serviceIds, cloudAccount));
return new LoadBalancer(LoadBalancerId.fromSerializedForm(object.field(idField).asString()),
instance,
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/LoadBalancersResponse.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/LoadBalancersResponse.java
index 175ea8d294e..e40e1ba5951 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/LoadBalancersResponse.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/LoadBalancersResponse.java
@@ -90,6 +90,7 @@ public class LoadBalancersResponse extends SlimeJsonResponse {
}
instance.serviceId().ifPresent(serviceId -> lbObject.setString("serviceId", serviceId.value()));
lbObject.setBool("public", instance.settings().isPublicEndpoint());
+ instance.idSeed().ifPresent(idSeed -> lbObject.setString("idSeed", idSeed.toString()));
});
lb.instance()
.map(LoadBalancerInstance::cloudAccount)