summaryrefslogtreecommitdiffstats
path: root/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/IP.java
diff options
context:
space:
mode:
Diffstat (limited to 'node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/IP.java')
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/IP.java138
1 files changed, 77 insertions, 61 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/IP.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/IP.java
index 955936931be..41d6c1e5425 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/IP.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/IP.java
@@ -60,15 +60,29 @@ public class IP {
/** IP configuration of a node */
public static class Config {
- public static final Config EMPTY = new Config(Set.of(), Set.of());
+ public static final Config EMPTY = Config.ofEmptyPool(Set.of());
private final Set<String> primary;
private final Pool pool;
- /** DO NOT USE in non-test code. Public for serialization purposes. */
+ public static Config ofEmptyPool(Set<String> primary) {
+ return new Config(primary, Set.of(), List.of());
+ }
+
+ public static Config of(Set<String> primary, Set<String> ipPool, List<Address> addressPool) {
+ return new Config(primary, ipPool, addressPool);
+ }
+
+ /** LEGACY TEST CONSTRUCTOR - use of() variants and/or the with- methods. */
public Config(Set<String> primary, Set<String> pool) {
+ this(primary, pool, List.of());
+ }
+
+ /** DO NOT USE: Public for NodeSerializer. */
+ public Config(Set<String> primary, Set<String> pool, List<Address> addresses) {
this.primary = ImmutableSet.copyOf(Objects.requireNonNull(primary, "primary must be non-null"));
- this.pool = Pool.of(Objects.requireNonNull(pool, "pool must be non-null"));
+ this.pool = Pool.of(Objects.requireNonNull(pool, "pool must be non-null"),
+ Objects.requireNonNull(addresses, "addresses must be non-null"));
}
/** The primary addresses of this. These addresses are used when communicating with the node itself */
@@ -82,13 +96,13 @@ public class IP {
}
/** Returns a copy of this with pool set to given value */
- public Config with(Pool pool) {
- return new Config(primary, pool.asSet());
+ public Config withPool(Pool pool) {
+ return new Config(primary, pool.getIpSet(), pool.getAddressList());
}
/** Returns a copy of this with pool set to given value */
- public Config with(Set<String> primary) {
- return new Config(primary, pool.asSet());
+ public Config withPrimary(Set<String> primary) {
+ return new Config(primary, pool.getIpSet(), pool.getAddressList());
}
@Override
@@ -107,7 +121,7 @@ public class IP {
@Override
public String toString() {
- return String.format("ip config primary=%s pool=%s", primary, pool.asSet());
+ return String.format("ip config primary=%s pool=%s", primary, pool.getIpSet());
}
/**
@@ -124,8 +138,8 @@ public class IP {
var addresses = new HashSet<>(node.ipConfig().primary());
var otherAddresses = new HashSet<>(other.ipConfig().primary());
if (node.type().isHost()) { // Addresses of a host can never overlap with any other nodes
- addresses.addAll(node.ipConfig().pool().asSet());
- otherAddresses.addAll(other.ipConfig().pool().asSet());
+ addresses.addAll(node.ipConfig().pool().getIpSet());
+ otherAddresses.addAll(other.ipConfig().pool().getIpSet());
}
otherAddresses.retainAll(addresses);
if (!otherAddresses.isEmpty())
@@ -157,18 +171,18 @@ public class IP {
}
/** A list of IP addresses and their protocol */
- public static class Addresses {
+ public static class IpAddresses {
- private final Set<String> addresses;
+ private final Set<String> ipAddresses;
private final Protocol protocol;
- private Addresses(Set<String> addresses, Protocol protocol) {
- this.addresses = ImmutableSet.copyOf(Objects.requireNonNull(addresses, "addresses must be non-null"));
+ private IpAddresses(Set<String> ipAddresses, Protocol protocol) {
+ this.ipAddresses = ImmutableSet.copyOf(Objects.requireNonNull(ipAddresses, "addresses must be non-null"));
this.protocol = Objects.requireNonNull(protocol, "type must be non-null");
}
public Set<String> asSet() {
- return addresses;
+ return ipAddresses;
}
/** The protocol of addresses in this */
@@ -177,20 +191,20 @@ public class IP {
}
/** Create addresses of the given set */
- private static Addresses of(Set<String> addresses) {
+ private static IpAddresses of(Set<String> addresses) {
long ipv6AddrCount = addresses.stream().filter(IP::isV6).count();
if (ipv6AddrCount == addresses.size()) { // IPv6-only
- return new Addresses(addresses, Protocol.ipv6);
+ return new IpAddresses(addresses, Protocol.ipv6);
}
long ipv4AddrCount = addresses.stream().filter(IP::isV4).count();
if (ipv4AddrCount == addresses.size()) { // IPv4-only
- return new Addresses(addresses, Protocol.ipv4);
+ return new IpAddresses(addresses, Protocol.ipv4);
}
// If we're dual-stacked, we must must have an equal number of addresses of each protocol.
if (ipv4AddrCount == ipv6AddrCount) {
- return new Addresses(addresses, Protocol.dualStack);
+ return new IpAddresses(addresses, Protocol.dualStack);
}
throw new IllegalArgumentException(String.format("Dual-stacked IP address list must have an " +
@@ -208,15 +222,28 @@ public class IP {
}
/**
- * A pool of IP addresses from which an allocation can be made.
+ * A pool of addresses from which an allocation can be made.
*
* Addresses in this are available for use by Docker containers
*/
public static class Pool {
- private final Addresses addresses;
+ private final IpAddresses ipAddresses;
+ private final List<Address> addresses;
- private Pool(Addresses addresses) {
+ /** Creates an empty pool. */
+ public static Pool of() {
+ return of(Set.of(), List.of());
+ }
+
+ /** Create a new pool containing given ipAddresses */
+ public static Pool of(Set<String> ipAddresses, List<Address> addresses) {
+ IpAddresses ips = IpAddresses.of(ipAddresses);
+ return new Pool(ips, addresses);
+ }
+
+ private Pool(IpAddresses ipAddresses, List<Address> addresses) {
+ this.ipAddresses = Objects.requireNonNull(ipAddresses, "ipAddresses must be non-null");
this.addresses = Objects.requireNonNull(addresses, "addresses must be non-null");
}
@@ -227,6 +254,12 @@ public class IP {
* @return an allocation from the pool, if any can be made
*/
public Optional<Allocation> findAllocation(LockedNodeList nodes, NameResolver resolver) {
+ if (ipAddresses.protocol == IpAddresses.Protocol.ipv4) {
+ return findUnused(nodes).stream()
+ .findFirst()
+ .map(addr -> Allocation.ofIpv4(addr, resolver));
+ }
+
var unusedAddresses = findUnused(nodes);
var allocation = unusedAddresses.stream()
.filter(IP::isV6)
@@ -248,64 +281,47 @@ public class IP {
* @param nodes a list of all nodes in the repository
*/
public Set<String> findUnused(NodeList nodes) {
- var unusedAddresses = new LinkedHashSet<>(asSet());
- nodes.matching(node -> node.ipConfig().primary().stream().anyMatch(ip -> asSet().contains(ip)))
+ var unusedAddresses = new LinkedHashSet<>(getIpSet());
+ nodes.matching(node -> node.ipConfig().primary().stream().anyMatch(ip -> getIpSet().contains(ip)))
.forEach(node -> unusedAddresses.removeAll(node.ipConfig().primary()));
return Collections.unmodifiableSet(unusedAddresses);
}
- public Set<String> asSet() {
- return addresses.asSet();
+ public IpAddresses.Protocol getProtocol() {
+ return ipAddresses.protocol;
}
- public boolean isEmpty() {
- return asSet().isEmpty();
+ public Set<String> getIpSet() {
+ return ipAddresses.asSet();
}
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- Pool that = (Pool) o;
- return Objects.equals(addresses, that.addresses);
+ public List<Address> getAddressList() {
+ return addresses;
}
- @Override
- public int hashCode() {
- return Objects.hash(addresses);
+ public boolean isEmpty() {
+ return getIpSet().isEmpty();
}
- /** Create a new pool containing given ipAddresses */
- public static Pool of(Set<String> ipAddresses) {
- var addresses = Addresses.of(ipAddresses);
- if (addresses.protocol() == Addresses.Protocol.ipv4) {
- return new Ipv4Pool(addresses);
- }
- return new Pool(addresses);
+ public Pool withIpAddresses(Set<String> ipAddresses) {
+ return Pool.of(ipAddresses, addresses);
}
- /** Validates and returns the given IP address pool */
- public static Set<String> require(Set<String> pool) {
- return of(pool).asSet();
+ public Pool withAddresses(List<Address> addresses) {
+ return Pool.of(ipAddresses.ipAddresses, addresses);
}
- }
-
- /** A pool of IPv4-only addresses from which an allocation can be made. */
- public static class Ipv4Pool extends Pool {
-
- private Ipv4Pool(Addresses addresses) {
- super(addresses);
- if (addresses.protocol() != Addresses.Protocol.ipv4) {
- throw new IllegalArgumentException("Protocol of addresses must be " + Addresses.Protocol.ipv4);
- }
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Pool that = (Pool) o;
+ return Objects.equals(ipAddresses, that.ipAddresses);
}
@Override
- public Optional<Allocation> findAllocation(LockedNodeList nodes, NameResolver resolver) {
- return findUnused(nodes).stream()
- .findFirst()
- .map(addr -> Allocation.ofIpv4(addr, resolver));
+ public int hashCode() {
+ return Objects.hash(ipAddresses);
}
}