diff options
author | Martin Polden <mpolden@mpolden.no> | 2019-05-15 10:29:05 +0200 |
---|---|---|
committer | Martin Polden <mpolden@mpolden.no> | 2019-05-15 14:41:23 +0200 |
commit | 3906d228fc5204b34e105b91aa5aad68b8d813ce (patch) | |
tree | 6c23ab1ea3f818f59c6b4c4aa47fc580168a88d8 /node-repository | |
parent | 7834918c224fce3ab427810ce298917b3729f37b (diff) |
Move all IP configuration to IP.Config
Diffstat (limited to 'node-repository')
12 files changed, 177 insertions, 118 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/Node.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/Node.java index 188829a24ba..803939c33c3 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/Node.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/Node.java @@ -1,7 +1,6 @@ // Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.provision; -import com.google.common.collect.ImmutableSet; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.ClusterMembership; import com.yahoo.config.provision.Flavor; @@ -30,9 +29,8 @@ import java.util.Set; */ public final class Node { - private final Set<String> ipAddresses; - private final IP.AddressPool ipAddressPool; private final String hostname; + private final IP.Config ipConfig; private final String id; private final Optional<String> parentHostname; private final Flavor flavor; @@ -50,22 +48,23 @@ public final class Node { /** Temporary method until we can merge it with the other create method */ public static Node createDockerNode(Set<String> ipAddresses, Set<String> ipAddressPool, String hostname, Optional<String> parentHostname, NodeResources resources, NodeType type) { - return new Node("fake-" + hostname, ipAddresses, ipAddressPool, hostname, parentHostname, new Flavor(resources), Status.initial(), State.reserved, + return new Node("fake-" + hostname, new IP.Config(ipAddresses, ipAddressPool), hostname, parentHostname, new Flavor(resources), Status.initial(), State.reserved, Optional.empty(), History.empty(), type, new Reports(), Optional.empty()); } /** Creates a node in the initial state (provisioned) */ public static Node create(String openStackId, Set<String> ipAddresses, Set<String> ipAddressPool, String hostname, Optional<String> parentHostname, Optional<String> modelName, Flavor flavor, NodeType type) { - return new Node(openStackId, ipAddresses, ipAddressPool, hostname, parentHostname, flavor, Status.initial(), State.provisioned, + return new Node(openStackId, new IP.Config(ipAddresses, ipAddressPool), hostname, parentHostname, flavor, Status.initial(), State.provisioned, Optional.empty(), History.empty(), type, new Reports(), modelName); } /** Creates a node. See also the {@code create} helper methods. */ - public Node(String id, Set<String> ipAddresses, Set<String> ipAddressPool, String hostname, Optional<String> parentHostname, + public Node(String id, IP.Config ipConfig, String hostname, Optional<String> parentHostname, Flavor flavor, Status status, State state, Optional<Allocation> allocation, History history, NodeType type, Reports reports, Optional<String> modelName) { Objects.requireNonNull(id, "A node must have an ID"); requireNonEmptyString(hostname, "A node must have a hostname"); + Objects.requireNonNull(ipConfig, "A node must a have an IP config"); requireNonEmptyString(parentHostname, "A parent host name must be a proper value"); Objects.requireNonNull(flavor, "A node must have a flavor"); Objects.requireNonNull(status, "A node must have a status"); @@ -77,13 +76,12 @@ public final class Node { Objects.requireNonNull(modelName, "A null modelName is not permitted"); if (state == State.active) - requireNonEmpty(ipAddresses, "An active node must have at least one valid IP address"); - if (parentHostname.isPresent() && !ipAddressPool.isEmpty()) + requireNonEmpty(ipConfig.primary(), "An active node must have at least one valid IP address"); + if (parentHostname.isPresent() && !ipConfig.pool().asSet().isEmpty()) throw new IllegalArgumentException("A child node cannot have an IP address pool"); - this.ipAddresses = ImmutableSet.copyOf(ipAddresses); - this.ipAddressPool = new IP.AddressPool(this, ipAddressPool); this.hostname = hostname; + this.ipConfig = ipConfig; this.parentHostname = parentHostname; this.id = id; this.flavor = flavor; @@ -97,11 +95,16 @@ public final class Node { } /** Returns the IP addresses of this node */ - public Set<String> ipAddresses() { return ipAddresses; } + // TODO: Remove and make callers access this through ipConfig() + public Set<String> ipAddresses() { return ipConfig.primary(); } /** Returns the IP address pool available on this node. These IP addresses are available for use by containers * running on this node */ - public IP.AddressPool ipAddressPool() { return ipAddressPool; } + // TODO: Remove and make callers access this through ipConfig() + public IP.Pool ipAddressPool() { return ipConfig.pool(); } + + /** Returns the IP config of this node */ + public IP.Config ipConfig() { return ipConfig; } /** Returns the host name of this node */ public String hostname() { return hostname; } @@ -196,31 +199,31 @@ public final class Node { /** Returns a node with the status assigned to the given value */ public Node with(Status status) { - return new Node(id, ipAddresses, ipAddressPool.asSet(), hostname, parentHostname, flavor, status, state, allocation, history, type, reports, modelName); + return new Node(id, ipConfig, hostname, parentHostname, flavor, status, state, allocation, history, type, reports, modelName); } /** Returns a node with the type assigned to the given value */ public Node with(NodeType type) { - return new Node(id, ipAddresses, ipAddressPool.asSet(), hostname, parentHostname, flavor, status, state, allocation, history, type, reports, modelName); + return new Node(id, ipConfig, hostname, parentHostname, flavor, status, state, allocation, history, type, reports, modelName); } /** Returns a node with the flavor assigned to the given value */ public Node with(Flavor flavor) { - return new Node(id, ipAddresses, ipAddressPool.asSet(), hostname, parentHostname, flavor, status, state, allocation, history, type, reports, modelName); + return new Node(id, ipConfig, hostname, parentHostname, flavor, status, state, allocation, history, type, reports, modelName); } /** Returns a copy of this with the reboot generation set to generation */ public Node withReboot(Generation generation) { - return new Node(id, ipAddresses, ipAddressPool.asSet(), hostname, parentHostname, flavor, status.withReboot(generation), state, allocation, history, type, reports, modelName); + return new Node(id, ipConfig, hostname, parentHostname, flavor, status.withReboot(generation), state, allocation, history, type, reports, modelName); } /** Returns a copy of this with the openStackId set */ public Node withOpenStackId(String openStackId) { - return new Node(openStackId, ipAddresses, ipAddressPool.asSet(), hostname, parentHostname, flavor, status, state, allocation, history, type, reports, modelName); + return new Node(openStackId, ipConfig, hostname, parentHostname, flavor, status, state, allocation, history, type, reports, modelName); } public Node withModelName(String modelName) { - return new Node(id, ipAddresses, ipAddressPool.asSet(), hostname, parentHostname, flavor, status, state, allocation, history, type, reports, Optional.of(modelName)); + return new Node(id, ipConfig, hostname, parentHostname, flavor, status, state, allocation, history, type, reports, Optional.of(modelName)); } /** Returns a copy of this with a history record saying it was detected to be down at this instant */ @@ -244,33 +247,27 @@ public final class Node { * Do not use this to allocate a node. */ public Node with(Allocation allocation) { - return new Node(id, ipAddresses, ipAddressPool.asSet(), hostname, parentHostname, flavor, status, state, - Optional.of(allocation), history, type, reports, modelName); + return new Node(id, ipConfig, hostname, parentHostname, flavor, status, state, + Optional.of(allocation), history, type, reports, modelName); } /** Returns a new Node without an allocation. */ public Node withoutAllocation() { - return new Node(id, ipAddresses, ipAddressPool.asSet(), hostname, parentHostname, flavor, status, state, - Optional.empty(), history, type, reports, modelName); + return new Node(id, ipConfig, hostname, parentHostname, flavor, status, state, + Optional.empty(), history, type, reports, modelName); } - /** Returns a copy of this node with the IP addresses set to the given value. */ - public Node withIpAddresses(Set<String> ipAddresses) { - return new Node(id, ipAddresses, ipAddressPool.asSet(), hostname, parentHostname, flavor, status, state, - allocation, history, type, reports, modelName); - } - - /** Returns a copy of this node with IP address pool set to the given value. */ - public Node withIpAddressPool(Set<String> ipAddressPool) { - return new Node(id, ipAddresses, ipAddressPool, hostname, parentHostname, flavor, status, state, - allocation, history, type, reports, modelName); + /** Returns a copy of this node with IP config set to the given value. */ + public Node with(IP.Config ipConfig) { + return new Node(id, ipConfig, hostname, parentHostname, flavor, status, state, + allocation, history, type, reports, modelName); } /** Returns a copy of this node with the parent hostname assigned to the given value. */ public Node withParentHostname(String parentHostname) { - return new Node(id, ipAddresses, ipAddressPool.asSet(), hostname, Optional.of(parentHostname), flavor, status, state, - allocation, history, type, reports, modelName); + return new Node(id, ipConfig, hostname, Optional.of(parentHostname), flavor, status, state, + allocation, history, type, reports, modelName); } /** Returns a copy of this node with the current reboot generation set to the given number at the given instant */ @@ -284,11 +281,11 @@ public final class Node { /** Returns a copy of this node with the given history. */ public Node with(History history) { - return new Node(id, ipAddresses, ipAddressPool.asSet(), hostname, parentHostname, flavor, status, state, allocation, history, type, reports, modelName); + return new Node(id, ipConfig, hostname, parentHostname, flavor, status, state, allocation, history, type, reports, modelName); } public Node with(Reports reports) { - return new Node(id, ipAddresses, ipAddressPool.asSet(), hostname, parentHostname, flavor, status, state, allocation, history, type, reports, modelName); + return new Node(id, ipConfig, hostname, parentHostname, flavor, status, state, allocation, history, type, reports, modelName); } private static void requireNonEmptyString(Optional<String> value, String message) { 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 7433b92e1fa..221f40239eb 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 @@ -4,7 +4,6 @@ package com.yahoo.vespa.hosted.provision.node; import com.google.common.collect.ImmutableSet; import com.google.common.net.InetAddresses; import com.google.common.primitives.UnsignedBytes; -import com.yahoo.vespa.hosted.provision.Node; import com.yahoo.vespa.hosted.provision.NodeList; import com.yahoo.vespa.hosted.provision.persistence.NameResolver; @@ -20,14 +19,14 @@ import java.util.Set; import java.util.stream.Collectors; /** - * Represents IP addresses owned by a node. + * This handles IP address configuration and allocation. * * @author mpolden */ public class IP { /** Comparator for sorting IP addresses by their natural order */ - public static final Comparator<String> naturalOrder = (ip1, ip2) -> { + public static final Comparator<String> NATURAL_ORDER = (ip1, ip2) -> { byte[] address1 = InetAddresses.forString(ip1).getAddress(); byte[] address2 = InetAddresses.forString(ip2).getAddress(); @@ -51,14 +50,77 @@ public class IP { return 0; }; - /** A pool of available IP addresses */ - public static class AddressPool { + /** IP configuration of a node */ + public static class Config { + + public static final Config EMPTY = new Config(Set.of(), Set.of()); + + private final Set<String> primary; + private final Pool pool; + + /** DO NOT USE in non-test code. Public for serialization purposes. */ + public Config(Set<String> primary, Set<String> pool) { + this.primary = ImmutableSet.copyOf(Objects.requireNonNull(primary, "primary must be non-null")); + this.pool = new Pool(Objects.requireNonNull(pool, "pool must be non-null")); + } + + /** The primary addresses of this. These addresses are used when communicating with the node itself */ + public Set<String> primary() { + return primary; + } + + /** Returns the IP address pool available on a node */ + public Pool pool() { + return pool; + } + + /** Returns a copy of this with pool set to given value */ + public Config with(Pool pool) { + return new Config(primary, pool.asSet()); + } + + /** Returns a copy of this with pool set to given value */ + public Config with(Set<String> primary) { + return new Config(require(primary), pool.asSet()); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Config config = (Config) o; + return primary.equals(config.primary) && + pool.equals(config.pool); + } + + @Override + public int hashCode() { + return Objects.hash(primary, pool); + } + + @Override + public String toString() { + return String.format("ip config primary=%s pool=%s", primary, pool.asSet()); + } + + /** Validates and returns the given addresses */ + public static Set<String> require(Set<String> addresses) { + try { + addresses.forEach(InetAddresses::forString); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("Found one or more invalid addresses in " + addresses, e); + } + return addresses; + } + + } + + /** A pool of IP addresses. Addresses in this are destined for use by Docker containers */ + public static class Pool { - private final Node owner; private final Set<String> addresses; - public AddressPool(Node owner, Set<String> addresses) { - this.owner = Objects.requireNonNull(owner, "owner must be non-null"); + private Pool(Set<String> addresses) { this.addresses = ImmutableSet.copyOf(Objects.requireNonNull(addresses, "addresses must be non-null")); } @@ -69,18 +131,17 @@ public class IP { * @return An allocation from the pool, if any can be made */ public Optional<Allocation> findAllocation(NodeList nodes, NameResolver resolver) { - Set<String> unusedAddresses = findUnused(nodes); - Optional<Allocation> allocation = unusedAddresses.stream() - .filter(IP::isV6) - .findFirst() - .map(addr -> Allocation.resolveFrom(addr, resolver)); + var unusedAddresses = findUnused(nodes); + var allocation = unusedAddresses.stream() + .filter(IP::isV6) + .findFirst() + .map(addr -> Allocation.resolveFrom(addr, resolver)); allocation.flatMap(Allocation::ipv4Address).ifPresent(ipv4Address -> { - if (!unusedAddresses.contains(ipv4Address)) { - throw new IllegalArgumentException("Allocation resolved " + ipv4Address + " from hostname " + - allocation.get().hostname + - ", but that address is not available in the address pool of " + - owner.hostname()); - } + if (!unusedAddresses.contains(ipv4Address)) { + throw new IllegalArgumentException("Allocation resolved " + ipv4Address + " from hostname " + + allocation.get().hostname + + ", but that address is not owned by this node"); + } }); return allocation; } @@ -91,8 +152,9 @@ public class IP { * @param nodes All nodes in the repository */ public Set<String> findUnused(NodeList nodes) { - Set<String> unusedAddresses = new LinkedHashSet<>(addresses); - nodes.childrenOf(owner).asList().forEach(node -> unusedAddresses.removeAll(node.ipAddresses())); + var unusedAddresses = new LinkedHashSet<>(addresses); + nodes.filter(node -> node.ipConfig().primary().stream().anyMatch(addresses::contains)) + .forEach(node -> unusedAddresses.removeAll(node.ipConfig().primary())); return Collections.unmodifiableSet(unusedAddresses); } @@ -104,7 +166,7 @@ public class IP { public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - AddressPool that = (AddressPool) o; + Pool that = (Pool) o; return Objects.equals(addresses, that.addresses); } @@ -113,6 +175,28 @@ public class IP { return Objects.hash(addresses); } + public static Pool of(Set<String> pool) { + return new Pool(require(pool)); + } + + /** Validates and returns the given IP address pool */ + public static Set<String> require(Set<String> pool) { + long ipv6AddrCount = pool.stream().filter(IP::isV6).count(); + if (ipv6AddrCount == pool.size()) { + return pool; // IPv6-only pool is valid + } + + long ipv4AddrCount = pool.stream().filter(IP::isV4).count(); + if (ipv4AddrCount == ipv6AddrCount) { + return pool; + } + + throw new IllegalArgumentException(String.format("Dual-stacked IP address list must have an " + + "equal number of addresses of each version " + + "[IPv6 address count = %d, IPv4 address count = %d]", + ipv6AddrCount, ipv4AddrCount)); + } + } /** An IP address allocation from a pool */ @@ -206,32 +290,4 @@ public class IP { return InetAddresses.forString(ipAddress) instanceof Inet6Address; } - /** Validates and returns the given set of IP addresses */ - public static Set<String> requireAddresses(Set<String> addresses) { - try { - addresses.forEach(InetAddresses::forString); - } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("A node must have at least one valid IP address", e); - } - return addresses; - } - - /** Validates and returns the given IP address pool */ - public static Set<String> requireAddressPool(Set<String> addresses) { - long ipv6AddrCount = addresses.stream().filter(IP::isV6).count(); - if (ipv6AddrCount == addresses.size()) { - return addresses; // IPv6-only pool is valid - } - - long ipv4AddrCount = addresses.stream().filter(IP::isV4).count(); - if (ipv4AddrCount == ipv6AddrCount) { - return addresses; - } - - throw new IllegalArgumentException(String.format("Dual-stacked IP address list must have an " + - "equal number of addresses of each version " + - "[IPv6 address count = %d, IPv4 address count = %d]", - ipv6AddrCount, ipv4AddrCount)); - } - } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java index 0d86abeb736..371ed4d2496 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java @@ -202,7 +202,7 @@ public class CuratorDatabaseClient { CuratorTransaction curatorTransaction = curatorDatabase.newCuratorTransactionIn(transaction); for (Node node : nodes) { - Node newNode = new Node(node.id(), node.ipAddresses(), node.ipAddressPool().asSet(), node.hostname(), + Node newNode = new Node(node.id(), node.ipConfig(), node.hostname(), node.parentHostname(), node.flavor(), newNodeStatus(node, toState), toState, diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializer.java index c6e72fc591e..cbc84f44a48 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializer.java @@ -124,8 +124,8 @@ public class NodeSerializer { private void toSlime(Node node, Cursor object) { object.setString(hostnameKey, node.hostname()); - toSlime(node.ipAddresses(), object.setArray(ipAddressesKey), IP::requireAddresses); - toSlime(node.ipAddressPool().asSet(), object.setArray(ipAddressPoolKey), IP::requireAddressPool); + toSlime(node.ipConfig().primary(), object.setArray(ipAddressesKey), IP.Config::require); + toSlime(node.ipConfig().pool().asSet(), object.setArray(ipAddressPoolKey), IP.Pool::require); object.setString(idKey, node.id()); node.parentHostname().ifPresent(hostname -> object.setString(parentHostnameKey, hostname)); toSlime(node.flavor(), object); @@ -186,7 +186,7 @@ public class NodeSerializer { private void toSlime(Set<String> ipAddresses, Cursor array, UnaryOperator<Set<String>> validator) { // Validating IP address format expensive, so we do it at serialization time instead of Node construction time - validator.apply(ipAddresses).stream().sorted(IP.naturalOrder).forEach(array::addString); + validator.apply(ipAddresses).stream().sorted(IP.NATURAL_ORDER).forEach(array::addString); } // ---------------- Deserialization -------------------------------------------------- @@ -197,8 +197,8 @@ public class NodeSerializer { private Node nodeFromSlime(Node.State state, Inspector object) { return new Node(object.field(idKey).asString(), - ipAddressesFromSlime(object, ipAddressesKey), - ipAddressesFromSlime(object, ipAddressPoolKey), + new IP.Config(ipAddressesFromSlime(object, ipAddressesKey), + ipAddressesFromSlime(object, ipAddressPoolKey)), object.field(hostnameKey).asString(), parentHostnameFromSlime(object), flavorFromSlime(object), diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodePatcher.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodePatcher.java index f9234af7fb4..2d9d22794cf 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodePatcher.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodePatcher.java @@ -14,6 +14,7 @@ import com.yahoo.vespa.hosted.provision.Node; import com.yahoo.vespa.hosted.provision.NodeRepository; import com.yahoo.vespa.hosted.provision.node.Agent; import com.yahoo.vespa.hosted.provision.node.Allocation; +import com.yahoo.vespa.hosted.provision.node.IP; import com.yahoo.vespa.hosted.provision.node.Report; import com.yahoo.vespa.hosted.provision.node.Reports; @@ -130,9 +131,9 @@ public class NodePatcher { case "parentHostname" : return node.withParentHostname(asString(value)); case "ipAddresses" : - return node.withIpAddresses(asStringSet(value)); + return node.with(node.ipConfig().with(asStringSet(value))); case "additionalIpAddresses" : - return node.withIpAddressPool(asStringSet(value)); + return node.with(node.ipConfig().with(IP.Pool.of(asStringSet(value)))); case WANT_TO_RETIRE : return node.withWantToRetire(asBoolean(value), Agent.operator, nodeRepository.clock().instant()); case WANT_TO_DEPROVISION : diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostProvisionMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostProvisionMaintainerTest.java index a943637bade..a70bd323b63 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostProvisionMaintainerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostProvisionMaintainerTest.java @@ -19,6 +19,7 @@ import com.yahoo.vespa.hosted.provision.NodeRepository; import com.yahoo.vespa.hosted.provision.node.Allocation; import com.yahoo.vespa.hosted.provision.node.Generation; import com.yahoo.vespa.hosted.provision.node.History; +import com.yahoo.vespa.hosted.provision.node.IP; import com.yahoo.vespa.hosted.provision.node.Reports; import com.yahoo.vespa.hosted.provision.node.Status; import com.yahoo.vespa.hosted.provision.provisioning.FatalProvisioningException; @@ -69,8 +70,8 @@ public class HostProvisionMaintainerTest { Node host4 = tester.addNode("host4", Optional.empty(), NodeType.host, Node.State.provisioned, Optional.empty()); Node host41 = tester.addNode("host4-1", Optional.of("host4"), NodeType.tenant, Node.State.reserved, Optional.of(tenantApp)); - Node host4new = host4.withIpAddresses(Set.of("::2")); - Node host41new = host41.withIpAddresses(Set.of("::4", "10.0.0.1")); + Node host4new = host4.with(host4.ipConfig().with(Set.of("::2"))); + Node host41new = host41.with(host4.ipConfig().with(Set.of("::4", "10.0.0.1"))); assertTrue(Stream.of(host4, host41).map(Node::ipAddresses).allMatch(Set::isEmpty)); when(hostProvisioner.provision(eq(host4), eq(Set.of(host41)))).thenReturn(List.of(host4new, host41new)); @@ -146,13 +147,13 @@ public class HostProvisionMaintainerTest { ClusterMembership.from("container/default/0/0", Version.fromString("7.3")), Generation.initial(), false)); - Set<String> ips = state == Node.State.active ? Set.of("::1") : Set.of(); - return new Node("fake-id-" + hostname, ips, Set.of(), hostname, - parentHostname, flavor, Status.initial(), state, allocation, History.empty(), nodeType, new Reports(), Optional.empty()); + var ipConfig = new IP.Config(state == Node.State.active ? Set.of("::1") : Set.of(), Set.of()); + return new Node("fake-id-" + hostname, ipConfig, hostname, parentHostname, flavor, Status.initial(), + state, allocation, History.empty(), nodeType, new Reports(), Optional.empty()); } NodeRepository nodeRepository() { return nodeRepository; } } -}
\ No newline at end of file +} diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRetirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRetirerTest.java index 399ff8582bd..407747785eb 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRetirerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRetirerTest.java @@ -78,7 +78,7 @@ public class NodeRetirerTest { public void testRetireAllocated() { // Update IP addresses on ready nodes so that when they are deployed to, we wont retire them tester.nodeRepository.getNodes(Node.State.ready) - .forEach(node -> tester.nodeRepository.write(node.withIpAddresses(Collections.singleton("::2")))); + .forEach(node -> tester.nodeRepository.write(node.with(node.ipConfig().with(Set.of("::2"))))); tester.assertCountsForStateByFlavor(Node.State.active, 9, 4, 8, 11, -1); @@ -136,7 +136,7 @@ public class NodeRetirerTest { Node nodeToFail = tester.nodeRepository.getNode("host5.test.yahoo.com").orElseThrow(RuntimeException::new); tester.nodeRepository.fail(nodeToFail.hostname(), Agent.system, "Failed for unit testing"); Node nodeToUpdate = tester.nodeRepository.getNode("host8.test.yahoo.com").orElseThrow(RuntimeException::new); - tester.nodeRepository.write(nodeToUpdate.withIpAddresses(Collections.singleton("::2"))); + tester.nodeRepository.write(nodeToUpdate.with(nodeToUpdate.ipConfig().with(Set.of("::2")))); nodes = tester.nodeRepository.getNodes(app); Set<String> excluded = Stream.of(nodeWantToRetire, nodeToFail, nodeToUpdate).map(Node::hostname).collect(Collectors.toSet()); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/node/IPTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/node/IPTest.java index a7ffa68d821..36a4737b3e1 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/node/IPTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/node/IPTest.java @@ -67,17 +67,17 @@ public class IPTest { "2001:db8:0:0:0:0:0:ffff", "2001:db8:85a3:0:0:8a2e:370:7334", "2001:db8:95a3:0:0:0:0:7334"), - new ArrayList<>(ImmutableSortedSet.copyOf(IP.naturalOrder, ipAddresses)) + new ArrayList<>(ImmutableSortedSet.copyOf(IP.NATURAL_ORDER, ipAddresses)) ); } @Test public void test_find_allocation_single_stack() { - IP.AddressPool pool = createNode(ImmutableSet.of( + IP.Pool pool = createNode(ImmutableSet.of( "::1", "::2", "::3" - )).ipAddressPool(); + )).ipConfig().pool(); resolver.addRecord("host1", "::2"); resolver.addRecord("host2", "::3"); @@ -103,7 +103,7 @@ public class IPTest { @Test public void test_find_allocation_dual_stack() { - IP.AddressPool pool = dualStackPool(); + IP.Pool pool = dualStackPool(); Optional<IP.Allocation> allocation = pool.findAllocation(emptyList, resolver); assertEquals("::1", allocation.get().ipv6Address()); assertEquals("127.0.0.2", allocation.get().ipv4Address().get()); @@ -112,7 +112,7 @@ public class IPTest { @Test public void test_find_allocation_multiple_ipv4_addresses() { - IP.AddressPool pool = dualStackPool(); + IP.Pool pool = dualStackPool(); resolver.addRecord("host3", "127.0.0.127"); try { pool.findAllocation(emptyList, resolver); @@ -125,7 +125,7 @@ public class IPTest { @Test public void test_find_allocation_invalid_ipv4_reverse_record() { - IP.AddressPool pool = dualStackPool(); + IP.Pool pool = dualStackPool(); resolver.removeRecord("127.0.0.2") .addReverseRecord("127.0.0.2", "host5"); try { @@ -137,7 +137,7 @@ public class IPTest { } } - private IP.AddressPool dualStackPool() { + private IP.Pool dualStackPool() { Node node = createNode(ImmutableSet.of( "127.0.0.1", "127.0.0.2", @@ -163,7 +163,7 @@ public class IPTest { .addReverseRecord("::1", "host3") .addReverseRecord("::2", "host1"); - return node.ipAddressPool(); + return node.ipConfig().pool(); } private static Node createNode(Set<String> ipAddresses) { diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/SerializationTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/SerializationTest.java index 188dd5fcaee..b2966ccb91a 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/SerializationTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/SerializationTest.java @@ -22,6 +22,7 @@ import com.yahoo.vespa.hosted.provision.Node.State; import com.yahoo.vespa.hosted.provision.node.Agent; import com.yahoo.vespa.hosted.provision.node.Generation; import com.yahoo.vespa.hosted.provision.node.History; +import com.yahoo.vespa.hosted.provision.node.IP; import com.yahoo.vespa.hosted.provision.node.Report; import com.yahoo.vespa.hosted.provision.node.Reports; import com.yahoo.vespa.hosted.provision.provisioning.FlavorConfigBuilder; @@ -36,6 +37,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; import static java.time.temporal.ChronoUnit.MILLIS; @@ -252,7 +254,7 @@ public class SerializationTest { Node node = createNode(); // Test round-trip with IP address pool - node = node.withIpAddressPool(ImmutableSet.of("::1", "::2", "::3")); + node = node.with(node.ipConfig().with(IP.Pool.of(Set.of("::1", "::2", "::3")))); Node copy = nodeSerializer.fromJson(node.state(), nodeSerializer.toJson(node)); assertEquals(node.ipAddressPool(), copy.ipAddressPool()); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AllocationSimulator.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AllocationSimulator.java index 242bb7df146..1275ad0781a 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AllocationSimulator.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AllocationSimulator.java @@ -13,6 +13,7 @@ import com.yahoo.vespa.hosted.provision.NodeList; import com.yahoo.vespa.hosted.provision.node.Allocation; import com.yahoo.vespa.hosted.provision.node.Generation; import com.yahoo.vespa.hosted.provision.node.History; +import com.yahoo.vespa.hosted.provision.node.IP; import com.yahoo.vespa.hosted.provision.node.Reports; import com.yahoo.vespa.hosted.provision.node.Status; @@ -80,10 +81,10 @@ public class AllocationSimulator { } private Node node(String hostname, Flavor flavor, Optional<String> parent, Optional<String> tenant) { - return new Node("fake", Collections.singleton("127.0.0.1"), - parent.isPresent() ? Collections.emptySet() : getAdditionalIP(), hostname, parent, flavor, Status.initial(), - parent.isPresent() ? Node.State.ready : Node.State.active, allocation(tenant), History.empty(), - parent.isPresent() ? NodeType.tenant : NodeType.host, new Reports(), Optional.empty()); + var ipConfig = new IP.Config(Set.of("127.0.0.1"), parent.isPresent() ? Set.of() : getAdditionalIP()); + return new Node("fake", ipConfig, hostname, parent, flavor, Status.initial(), + parent.isPresent() ? Node.State.ready : Node.State.active, allocation(tenant), History.empty(), + parent.isPresent() ? NodeType.tenant : NodeType.host, new Reports(), Optional.empty()); } private Set<String> getAdditionalIP() { diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerProvisionTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerProvisionTest.java index 280eab44db3..a5a6f3e678b 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerProvisionTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerProvisionTest.java @@ -14,6 +14,7 @@ import com.yahoo.vespa.flags.Flags; import com.yahoo.vespa.flags.InMemoryFlagSource; import com.yahoo.vespa.hosted.provision.Node; import com.yahoo.vespa.hosted.provision.node.Agent; +import com.yahoo.vespa.hosted.provision.node.IP; import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver; import org.junit.Test; @@ -85,8 +86,8 @@ public class DynamicDockerProvisionTest { // Ready the provisioned hosts, add an IP addreses to pool and activate them for (Integer i : expectedProvisionIndexes) { String hostname = "host-" + i; - Node host = tester.nodeRepository().getNode(hostname).orElseThrow() - .withIpAddressPool(Set.of("::" + i + ":2")).withIpAddresses(Set.of("::" + i + ":0")); + var ipConfig = new IP.Config(Set.of("::" + i + ":0"), Set.of("::" + i + ":2")); + Node host = tester.nodeRepository().getNode(hostname).orElseThrow().with(ipConfig); tester.nodeRepository().setReady(List.of(host), Agent.system, getClass().getSimpleName()); nameResolver.addRecord(hostname + "-2", "::" + i + ":2"); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java index 0c403777f3e..80d8ffb7c60 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java @@ -270,7 +270,7 @@ public class RestApiTest { ("[" + asNodeJson("host-with-ip.yahoo.com", "default", "foo") + "]"). getBytes(StandardCharsets.UTF_8), Request.Method.POST); - assertResponse(req, 400, "{\"error-code\":\"BAD_REQUEST\",\"message\":\"A node must have at least one valid IP address: 'foo' is not an IP string literal.\"}"); + assertResponse(req, 400, "{\"error-code\":\"BAD_REQUEST\",\"message\":\"Found one or more invalid addresses in [foo]: 'foo' is not an IP string literal.\"}"); } @Test |