summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorValerij Fredriksen <freva@users.noreply.github.com>2023-02-24 16:19:41 +0100
committerGitHub <noreply@github.com>2023-02-24 16:19:41 +0100
commit5f24c29f3f395b7c77ebc1d69bfdda07fcb2b5b0 (patch)
treee3b5b03c75b68b67779ce7a4258205862cee2a3b
parent1b4b5ce9ce9aaf6b9716c229360d0253948b0d46 (diff)
parent91d90da73c6847a8d321da8cfd5bb7af3fca945d (diff)
Merge pull request #26181 from vespa-engine/revert-26067-mpolden/ip-update-lock
Revert "Lock node when updating IP config"
-rw-r--r--athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/InstanceValidatorTest.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/Node.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java11
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/CapacityChecker.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostResumeProvisioner.java43
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Address.java17
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/IP.java232
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java10
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializer.java26
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostIpConfig.java40
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostProvisioner.java6
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidate.java6
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisionedHost.java30
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodePatcher.java22
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesResponse.java17
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java8
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockHostProvisioner.java29
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTester.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/CapacityCheckerTester.java10
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainerTest.java5
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostResumeProvisionerTest.java4
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java4
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java4
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/SpareCapacityMaintainerTest.java4
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/node/IPTest.java8
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializerTest.java14
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicAllocationTest.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicProvisioningTest.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicProvisioningTester.java4
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/HostCapacityTest.java7
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidateTest.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java8
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java12
34 files changed, 341 insertions, 260 deletions
diff --git a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/InstanceValidatorTest.java b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/InstanceValidatorTest.java
index b4b817da2f0..a7947aff283 100644
--- a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/InstanceValidatorTest.java
+++ b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/InstanceValidatorTest.java
@@ -278,7 +278,7 @@ public class InstanceValidatorTest {
MockNodeFlavors flavors = new MockNodeFlavors();
List<Node> nodeList = new ArrayList<>();
for (int i = 0; i < num; i++) {
- Node node = Node.create("foo" + i, IP.Config.of(Set.of("::1" + i, "::2" + i, "::3" + i), Set.of()),
+ Node node = Node.create("foo" + i, new IP.Config(Set.of("::1" + i, "::2" + i, "::3" + i), Set.of()),
"foo" + i, flavors.getFlavorOrThrow("default"), NodeType.tenant).build();
nodeList.add(node);
}
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 31283998702..79382a8bf5b 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
@@ -116,11 +116,11 @@ public final class Node implements Nodelike {
if (state == State.ready && type.isHost()) {
requireNonEmpty(ipConfig.primary(), "A " + type + " must have at least one primary IP address in state " + state);
- requireNonEmpty(ipConfig.pool().asSet(), "A " + type + " must have a non-empty IP address pool in state " + state);
+ requireNonEmpty(ipConfig.pool().ipSet(), "A " + type + " must have a non-empty IP address pool in state " + state);
}
if (parentHostname.isPresent()) {
- if (!ipConfig.pool().asSet().isEmpty()) throw new IllegalArgumentException("A child node cannot have an IP address pool");
+ if (!ipConfig.pool().ipSet().isEmpty()) throw new IllegalArgumentException("A child node cannot have an IP address pool");
if (modelName.isPresent()) throw new IllegalArgumentException("A child node cannot have model name set");
if (switchHostname.isPresent()) throw new IllegalArgumentException("A child node cannot have switch hostname set");
if (status.wantToRebuild()) throw new IllegalArgumentException("A child node cannot be rebuilt");
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java
index 1cf7bcfa4f2..800cf2150e9 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java
@@ -9,6 +9,7 @@ import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
import com.yahoo.vespa.hosted.provision.node.ClusterId;
+import com.yahoo.vespa.hosted.provision.node.IP;
import java.util.ArrayList;
import java.util.Comparator;
@@ -329,22 +330,22 @@ public class NodeList extends AbstractFilteringList<Node, NodeList> {
/**
* Returns the number of unused IP addresses in the pool, assuming any and all unaccounted for hostnames
- * in the pool are resolved to exactly 1 IP address (or 2 if dual-stack).
+ * in the pool are resolved to exactly 1 IP address (or 2 with {@link IP.IpAddresses.Protocol#dualStack}).
*/
public int eventuallyUnusedIpAddressCount(Node host) {
// The count in this method relies on the size of the IP address pool if that's non-empty,
// otherwise fall back to the address/hostname pool.
- if (host.ipConfig().pool().asSet().isEmpty()) {
+ if (host.ipConfig().pool().ipSet().isEmpty()) {
Set<String> allHostnames = cache().keySet();
- return (int) host.ipConfig().pool().hostnames().stream()
- .filter(hostname -> !allHostnames.contains(hostname.value()))
+ return (int) host.ipConfig().pool().getAddressList().stream()
+ .filter(address -> !allHostnames.contains(address.hostname()))
.count();
}
Set<String> allIps = ipCache.updateAndGet(old ->
old != null ? old : stream().flatMap(node -> node.ipConfig().primary().stream())
.collect(Collectors.toUnmodifiableSet())
);
- return (int) host.ipConfig().pool().asSet().stream()
+ return (int) host.ipConfig().pool().ipSet().stream()
.filter(address -> !allIps.contains(address))
.count();
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/CapacityChecker.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/CapacityChecker.java
index c8b736cb25b..603056856e2 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/CapacityChecker.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/CapacityChecker.java
@@ -127,12 +127,12 @@ public class CapacityChecker {
for (var host : hosts) {
NodeResources hostResources = host.flavor().resources();
int occupiedIps = 0;
- Set<String> ipPool = host.ipConfig().pool().asSet();
+ Set<String> ipPool = host.ipConfig().pool().ipSet();
for (var child : nodeChildren.get(host)) {
hostResources = hostResources.subtract(child.resources().justNumbers());
occupiedIps += child.ipConfig().primary().stream().filter(ipPool::contains).count();
}
- availableResources.put(host, new AllocationResources(hostResources, host.ipConfig().pool().asSet().size() - occupiedIps));
+ availableResources.put(host, new AllocationResources(hostResources, host.ipConfig().pool().ipSet().size() - occupiedIps));
}
return availableResources;
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostResumeProvisioner.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostResumeProvisioner.java
index 86c5a926900..c606ede05d1 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostResumeProvisioner.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostResumeProvisioner.java
@@ -9,14 +9,17 @@ import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.node.IP;
import com.yahoo.vespa.hosted.provision.provisioning.FatalProvisioningException;
-import com.yahoo.vespa.hosted.provision.provisioning.HostIpConfig;
import com.yahoo.vespa.hosted.provision.provisioning.HostProvisioner;
import com.yahoo.yolean.Exceptions;
import javax.naming.NamingException;
import java.time.Duration;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
+import java.util.stream.Collectors;
/**
* Resumes provisioning (requests additional IP addresses, updates DNS when IPs are ready) of hosts in state provisioned
@@ -38,13 +41,23 @@ public class HostResumeProvisioner extends NodeRepositoryMaintainer {
@Override
protected double maintain() {
NodeList allNodes = nodeRepository().nodes().list();
+ Map<String, Set<Node>> nodesByProvisionedParentHostname =
+ allNodes.nodeType(NodeType.tenant, NodeType.config, NodeType.controller)
+ .asList()
+ .stream()
+ .filter(node -> node.parentHostname().isPresent())
+ .collect(Collectors.groupingBy(node -> node.parentHostname().get(), Collectors.toSet()));
+
NodeList hosts = allNodes.state(Node.State.provisioned).nodeType(NodeType.host, NodeType.confighost, NodeType.controllerhost);
int failures = 0;
for (Node host : hosts) {
- NodeList children = allNodes.childrenOf(host);
- try {
- HostIpConfig hostIpConfig = hostProvisioner.provision(host, children.asSet());
- setIpConfig(host, children, hostIpConfig);
+ Set<Node> children = nodesByProvisionedParentHostname.getOrDefault(host.hostname(), Set.of());
+ // This doesn't actually require unallocated lock, but that is much easier than simultaneously holding
+ // the application locks of the host and all it's children.
+ try (var lock = nodeRepository().nodes().lockUnallocated()) {
+ List<Node> updatedNodes = hostProvisioner.provision(host, children);
+ verifyDns(updatedNodes);
+ nodeRepository().nodes().write(updatedNodes, lock);
} catch (IllegalArgumentException | IllegalStateException e) {
log.log(Level.INFO, "Could not provision " + host.hostname() + " with " + children.size() + " children, will retry in " +
interval() + ": " + Exceptions.toMessageString(e));
@@ -66,21 +79,13 @@ public class HostResumeProvisioner extends NodeRepositoryMaintainer {
return asSuccessFactor(hosts.size(), failures);
}
- private void setIpConfig(Node host, NodeList children, HostIpConfig hostIpConfig) {
- if (hostIpConfig.isEmpty()) return;
- NodeList nodes = NodeList.of(host).and(children);
+ /** Verify DNS configuration of given nodes */
+ private void verifyDns(List<Node> nodes) {
for (var node : nodes) {
- verifyDns(node, hostIpConfig.require(node.hostname()));
- }
- nodeRepository().nodes().setIpConfig(hostIpConfig);
- }
-
- /** Verify DNS configuration of given node */
- private void verifyDns(Node node, IP.Config ipConfig) {
- boolean enclave = node.cloudAccount().isEnclave(nodeRepository().zone());
- for (var ipAddress : ipConfig.primary()) {
- IP.verifyDns(node.hostname(), ipAddress, nodeRepository().nameResolver(), !enclave);
+ boolean enclave = node.cloudAccount().isEnclave(nodeRepository().zone());
+ for (var ipAddress : node.ipConfig().primary()) {
+ IP.verifyDns(node.hostname(), ipAddress, nodeRepository().nameResolver(), !enclave);
+ }
}
}
-
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Address.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Address.java
new file mode 100644
index 00000000000..d7ef2228960
--- /dev/null
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Address.java
@@ -0,0 +1,17 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.provision.node;
+
+import java.util.Objects;
+
+/**
+ * Address info about a container that might run on a host.
+ *
+ * @author hakon
+ */
+public record Address(String hostname) {
+ public Address {
+ Objects.requireNonNull(hostname, "hostname cannot be null");
+ if (hostname.isEmpty())
+ throw new IllegalArgumentException("hostname cannot be empty");
+ }
+}
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 708d84ba655..b2becc7ecfd 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
@@ -1,9 +1,9 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
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.config.provision.HostName;
import com.yahoo.vespa.hosted.provision.LockedNodeList;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;
@@ -31,7 +31,7 @@ import static com.yahoo.config.provision.NodeType.proxyhost;
*
* @author mpolden
*/
-public record IP() {
+public class IP {
/** Comparator for sorting IP addresses by their natural order */
public static final Comparator<InetAddress> NATURAL_ORDER = (ip1, ip2) -> {
@@ -59,26 +59,31 @@ public record IP() {
};
/** IP configuration of a node */
- public record Config(Set<String> primary, Pool pool) {
+ public static class Config {
public static final Config EMPTY = Config.ofEmptyPool(Set.of());
+ private final Set<String> primary;
+ private final Pool pool;
+
public static Config ofEmptyPool(Set<String> primary) {
- return new Config(primary, Pool.EMPTY);
+ return new Config(primary, Set.of(), List.of());
}
- public static Config of(Set<String> primary, Set<String> ipPool, List<HostName> hostnames) {
- return new Config(primary, new Pool(IpAddresses.of(ipPool), hostnames));
+ public static Config of(Set<String> primary, Set<String> ipPool, List<Address> addressPool) {
+ return new Config(primary, ipPool, addressPool);
}
- public static Config of(Set<String> primary, Set<String> pool) {
- return of(primary, pool, List.of());
+ /** 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, Pool pool) {
- this.primary = Collections.unmodifiableSet(new LinkedHashSet<>(Objects.requireNonNull(primary, "primary must be non-null")));
- this.pool = Objects.requireNonNull(pool, "pool must be non-null");
+ 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"),
+ Objects.requireNonNull(addresses, "addresses must be non-null"));
}
/** The primary addresses of this. These addresses are used when communicating with the node itself */
@@ -93,12 +98,31 @@ public record IP() {
/** Returns a copy of this with pool set to given value */
public Config withPool(Pool pool) {
- return new Config(primary, pool);
+ return new Config(primary, pool.ipSet(), pool.getAddressList());
}
/** Returns a copy of this with pool set to given value */
public Config withPrimary(Set<String> primary) {
- return new Config(primary, pool);
+ return new Config(primary, pool.ipSet(), pool.getAddressList());
+ }
+
+ @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.ipSet());
}
/**
@@ -116,8 +140,8 @@ public record 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().ipSet());
+ otherAddresses.addAll(other.ipConfig().pool().ipSet());
}
otherAddresses.retainAll(addresses);
if (!otherAddresses.isEmpty())
@@ -134,12 +158,12 @@ public record IP() {
if (node.parentHostname().isPresent() == existingNode.parentHostname().isPresent()) return false; // Not a parent-child node
if (node.parentHostname().isEmpty()) return canAssignIpOf(node, existingNode);
if (!node.parentHostname().get().equals(existingNode.hostname())) return false; // Wrong host
- return switch (node.type()) {
- case proxy -> existingNode.type() == proxyhost;
- case config -> existingNode.type() == confighost;
- case controller -> existingNode.type() == controllerhost;
- default -> false;
- };
+ switch (node.type()) {
+ case proxy: return existingNode.type() == proxyhost;
+ case config: return existingNode.type() == confighost;
+ case controller: return existingNode.type() == controllerhost;
+ }
+ return false;
}
public static Node verify(Node node, LockedNodeList allNodes) {
@@ -149,13 +173,25 @@ public record IP() {
}
/** A list of IP addresses and their protocol */
- record IpAddresses(Set<String> addresses, Protocol protocol) {
+ public static class IpAddresses {
- public IpAddresses(Set<String> addresses, Protocol protocol) {
- this.addresses = Collections.unmodifiableSet(new LinkedHashSet<>(Objects.requireNonNull(addresses, "addresses must be non-null")));
+ private final Set<String> ipAddresses;
+ private final Protocol protocol;
+
+ 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 ipAddresses;
+ }
+
+ /** The protocol of addresses in this */
+ public Protocol protocol() {
+ return protocol;
+ }
+
/** Create addresses of the given set */
private static IpAddresses of(Set<String> addresses) {
long ipv6AddrCount = addresses.stream().filter(IP::isV6).count();
@@ -180,7 +216,6 @@ public record IP() {
}
public enum Protocol {
-
dualStack("dual-stack"),
ipv4("IPv4-only"),
ipv6("IPv6-only");
@@ -189,8 +224,21 @@ public record IP() {
Protocol(String description) { this.description = description; }
+ public String getDescription() { return description; }
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ IpAddresses that = (IpAddresses) o;
+ return ipAddresses.equals(that.ipAddresses) && protocol == that.protocol;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(ipAddresses, protocol);
+ }
}
/**
@@ -198,23 +246,25 @@ public record IP() {
*
* Addresses in this are available for use by Linux containers.
*/
- public record Pool(IpAddresses ipAddresses, List<HostName> hostnames) {
+ public static class Pool {
- public static final Pool EMPTY = new Pool(IpAddresses.of(Set.of()), List.of());
+ private final IpAddresses ipAddresses;
+ private final List<Address> 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<HostName> hostnames) {
+ public static Pool of(Set<String> ipAddresses, List<Address> addresses) {
IpAddresses ips = IpAddresses.of(ipAddresses);
- return new Pool(ips, hostnames);
+ return new Pool(ips, addresses);
}
- public Pool(IpAddresses ipAddresses, List<HostName> hostnames) {
+ private Pool(IpAddresses ipAddresses, List<Address> addresses) {
this.ipAddresses = Objects.requireNonNull(ipAddresses, "ipAddresses must be non-null");
- this.hostnames = List.copyOf(Objects.requireNonNull(hostnames, "hostnames must be non-null"));
- }
-
- public Set<String> asSet() {
- return ipAddresses.addresses;
+ this.addresses = Objects.requireNonNull(addresses, "addresses must be non-null");
}
/**
@@ -224,15 +274,16 @@ public record IP() {
* @return an allocation from the pool, if any can be made
*/
public Optional<Allocation> findAllocation(LockedNodeList nodes, NameResolver resolver, boolean hasPtr) {
- if (ipAddresses.addresses.isEmpty()) {
+ if (ipAddresses.asSet().isEmpty()) {
// IP addresses have not yet been resolved and should be done later.
- return findUnusedHostnames(nodes).map(Allocation::ofHostname)
- .findFirst();
+ return findUnusedAddressStream(nodes)
+ .map(Allocation::ofAddress)
+ .findFirst();
}
if (!hasPtr) {
// Without PTR records (reverse IP mapping): Ensure only forward resolving from hostnames.
- return findUnusedHostnames(nodes).findFirst().map(address -> Allocation.fromHostname(address, resolver, ipAddresses.protocol));
+ return findUnusedAddressStream(nodes).findFirst().map(address -> Allocation.fromAddress(address, resolver, ipAddresses.protocol));
}
if (ipAddresses.protocol == IpAddresses.Protocol.ipv4) {
@@ -262,34 +313,64 @@ public record IP() {
* @param nodes a list of all nodes in the repository
*/
public Set<String> findUnusedIpAddresses(NodeList nodes) {
- Set<String> unusedAddresses = new LinkedHashSet<>(asSet());
- nodes.matching(node -> node.ipConfig().primary().stream().anyMatch(ip -> asSet().contains(ip)))
+ var unusedAddresses = new LinkedHashSet<>(ipSet());
+ nodes.matching(node -> node.ipConfig().primary().stream().anyMatch(ip -> ipSet().contains(ip)))
.forEach(node -> unusedAddresses.removeAll(node.ipConfig().primary()));
return Collections.unmodifiableSet(unusedAddresses);
}
- private Stream<HostName> findUnusedHostnames(NodeList nodes) {
- Set<String> usedHostnames = nodes.stream().map(Node::hostname).collect(Collectors.toSet());
- return hostnames.stream().filter(hostname -> !usedHostnames.contains(hostname.value()));
+ private Stream<Address> findUnusedAddressStream(NodeList nodes) {
+ Set<String> hostnames = nodes.stream().map(Node::hostname).collect(Collectors.toSet());
+ return addresses.stream().filter(address -> !hostnames.contains(address.hostname()));
+ }
+
+ public IpAddresses.Protocol getProtocol() {
+ return ipAddresses.protocol;
+ }
+
+ /** Returns the IP addresses in this pool as a set */
+ public Set<String> ipSet() {
+ return ipAddresses.asSet();
+ }
+
+ public List<Address> getAddressList() {
+ return addresses;
}
public Pool withIpAddresses(Set<String> ipAddresses) {
- return Pool.of(ipAddresses, hostnames);
+ return Pool.of(ipAddresses, addresses);
}
- public Pool withHostnames(List<HostName> hostnames) {
- return Pool.of(ipAddresses.addresses, hostnames);
+ public Pool withAddresses(List<Address> addresses) {
+ return Pool.of(ipAddresses.ipAddresses, addresses);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Pool pool = (Pool) o;
+ return ipAddresses.equals(pool.ipAddresses) && addresses.equals(pool.addresses);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(ipAddresses, addresses);
}
}
/** An address allocation from a pool */
- public record Allocation(String hostname, Optional<String> ipv4Address, Optional<String> ipv6Address) {
+ public static class Allocation {
+
+ private final String hostname;
+ private final Optional<String> ipv4Address;
+ private final Optional<String> ipv6Address;
- public Allocation {
- Objects.requireNonNull(hostname, "hostname must be non-null");
- Objects.requireNonNull(ipv4Address, "ipv4Address must be non-null");
- Objects.requireNonNull(ipv6Address, "ipv6Address must be non-null");
+ private Allocation(String hostname, Optional<String> ipv4Address, Optional<String> ipv6Address) {
+ this.hostname = Objects.requireNonNull(hostname, "hostname must be non-null");
+ this.ipv4Address = Objects.requireNonNull(ipv4Address, "ipv4Address must be non-null");
+ this.ipv6Address = Objects.requireNonNull(ipv6Address, "ipv6Address must be non-null");
}
/**
@@ -346,22 +427,22 @@ public record IP() {
return new Allocation(hostname4, Optional.of(addresses.get(0)), Optional.empty());
}
- private static Allocation fromHostname(HostName hostname, NameResolver resolver, IpAddresses.Protocol protocol) {
+ private static Allocation fromAddress(Address address, NameResolver resolver, IpAddresses.Protocol protocol) {
// Resolve both A and AAAA to verify they match the protocol and to avoid surprises later on.
- Optional<String> ipv4Address = resolveOptional(hostname.value(), resolver, RecordType.A);
+ Optional<String> ipv4Address = resolveOptional(address.hostname(), resolver, RecordType.A);
if (protocol != IpAddresses.Protocol.ipv6 && ipv4Address.isEmpty())
- throw new IllegalArgumentException(protocol.description + " hostname " + hostname.value() + " did not resolve to an IPv4 address");
+ throw new IllegalArgumentException(protocol.description + " hostname " + address.hostname() + " did not resolve to an IPv4 address");
if (protocol == IpAddresses.Protocol.ipv6 && ipv4Address.isPresent())
- throw new IllegalArgumentException(protocol.description + " hostname " + hostname.value() + " has an IPv4 address: " + ipv4Address.get());
+ throw new IllegalArgumentException(protocol.description + " hostname " + address.hostname() + " has an IPv4 address: " + ipv4Address.get());
- Optional<String> ipv6Address = resolveOptional(hostname.value(), resolver, RecordType.AAAA);
+ Optional<String> ipv6Address = resolveOptional(address.hostname(), resolver, RecordType.AAAA);
if (protocol != IpAddresses.Protocol.ipv4 && ipv6Address.isEmpty())
- throw new IllegalArgumentException(protocol.description + " hostname " + hostname.value() + " did not resolve to an IPv6 address");
+ throw new IllegalArgumentException(protocol.description + " hostname " + address.hostname() + " did not resolve to an IPv6 address");
if (protocol == IpAddresses.Protocol.ipv4 && ipv6Address.isPresent())
- throw new IllegalArgumentException(protocol.description + " hostname " + hostname.value() + " has an IPv6 address: " + ipv6Address.get());
+ throw new IllegalArgumentException(protocol.description + " hostname " + address.hostname() + " has an IPv6 address: " + ipv6Address.get());
- return new Allocation(hostname.value(), ipv4Address, ipv6Address);
+ return new Allocation(address.hostname(), ipv4Address, ipv6Address);
}
private static Optional<String> resolveOptional(String hostname, NameResolver resolver, RecordType recordType) {
@@ -373,14 +454,37 @@ public record IP() {
};
}
- private static Allocation ofHostname(HostName hostName) {
- return new Allocation(hostName.value(), Optional.empty(), Optional.empty());
+ private static Allocation ofAddress(Address address) {
+ return new Allocation(address.hostname(), Optional.empty(), Optional.empty());
+ }
+
+ /** Hostname pointing to the IP addresses in this */
+ public String hostname() {
+ return hostname;
+ }
+
+ /** IPv4 address of this allocation */
+ public Optional<String> ipv4Address() {
+ return ipv4Address;
+ }
+
+ /** IPv6 address of this allocation */
+ public Optional<String> ipv6Address() {
+ return ipv6Address;
}
/** All IP addresses in this */
public Set<String> addresses() {
- return Stream.concat(ipv4Address.stream(), ipv6Address.stream())
- .collect(Collectors.toUnmodifiableSet());
+ ImmutableSet.Builder<String> builder = ImmutableSet.builder();
+ ipv4Address.ifPresent(builder::add);
+ ipv6Address.ifPresent(builder::add);
+ return builder.build();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("Address allocation [hostname=%s, IPv4=%s, IPv6=%s]",
+ hostname, ipv4Address.orElse("<none>"), ipv6Address.orElse("<none>"));
}
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java
index 5690a685345..cf6473c6b1b 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java
@@ -21,7 +21,6 @@ import com.yahoo.vespa.hosted.provision.applications.Applications;
import com.yahoo.vespa.hosted.provision.maintenance.NodeFailer;
import com.yahoo.vespa.hosted.provision.node.filter.NodeFilter;
import com.yahoo.vespa.hosted.provision.persistence.CuratorDb;
-import com.yahoo.vespa.hosted.provision.provisioning.HostIpConfig;
import com.yahoo.vespa.orchestrator.HostNameNotFoundException;
import com.yahoo.vespa.orchestrator.Orchestrator;
@@ -355,15 +354,6 @@ public class Nodes {
}
}
- /** Update IP config for nodes in given config */
- public void setIpConfig(HostIpConfig hostIpConfig) {
- Predicate<Node> nodeInConfig = (node) -> hostIpConfig.contains(node.hostname());
- performOn(nodeInConfig, (node, lock) -> {
- IP.Config ipConfig = hostIpConfig.require(node.hostname());
- return write(node.with(ipConfig), lock);
- });
- }
-
/**
* Parks this node and returns it in its new state.
*
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 23ea14da4cc..39cccafb8ef 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
@@ -14,7 +14,6 @@ import com.yahoo.config.provision.ClusterMembership;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.DockerImage;
import com.yahoo.config.provision.Flavor;
-import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.InstanceName;
import com.yahoo.config.provision.NodeFlavors;
import com.yahoo.config.provision.NodeResources;
@@ -29,6 +28,7 @@ import com.yahoo.slime.Inspector;
import com.yahoo.slime.Slime;
import com.yahoo.slime.SlimeUtils;
import com.yahoo.vespa.hosted.provision.Node;
+import com.yahoo.vespa.hosted.provision.node.Address;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.node.Allocation;
import com.yahoo.vespa.hosted.provision.node.Generation;
@@ -167,8 +167,8 @@ public class NodeSerializer {
object.setString(hostnameKey, node.hostname());
object.setString(stateKey, toString(node.state()));
toSlime(node.ipConfig().primary(), object.setArray(ipAddressesKey));
- toSlime(node.ipConfig().pool().asSet(), object.setArray(ipAddressPoolKey));
- toSlime(node.ipConfig().pool().hostnames(), object);
+ toSlime(node.ipConfig().pool().ipSet(), object.setArray(ipAddressPoolKey));
+ toSlime(node.ipConfig().pool().getAddressList(), object);
object.setString(idKey, node.id());
node.parentHostname().ifPresent(hostname -> object.setString(parentHostnameKey, hostname));
toSlime(node.flavor(), object);
@@ -247,11 +247,11 @@ public class NodeSerializer {
ipAddresses.stream().map(IP::parse).sorted(IP.NATURAL_ORDER).map(IP::asString).forEach(array::addString);
}
- private void toSlime(List<HostName> hostnames, Cursor object) {
- if (hostnames.isEmpty()) return;
- Cursor containersArray = object.setArray(containersKey);
- hostnames.forEach(hostname -> {
- containersArray.addObject().setString(containerHostnameKey, hostname.value());
+ private void toSlime(List<Address> addresses, Cursor object) {
+ if (addresses.isEmpty()) return;
+ Cursor addressCursor = object.setArray(containersKey);
+ addresses.forEach(address -> {
+ addressCursor.addObject().setString(containerHostnameKey, address.hostname());
});
}
@@ -277,9 +277,9 @@ public class NodeSerializer {
private Node nodeFromSlime(Inspector object) {
Flavor flavor = flavorFromSlime(object);
return new Node(object.field(idKey).asString(),
- IP.Config.of(ipAddressesFromSlime(object, ipAddressesKey),
- ipAddressesFromSlime(object, ipAddressPoolKey),
- hostnamesFromSlime(object)),
+ new IP.Config(ipAddressesFromSlime(object, ipAddressesKey),
+ ipAddressesFromSlime(object, ipAddressPoolKey),
+ addressesFromSlime(object)),
object.field(hostnameKey).asString(),
SlimeUtils.optionalString(object.field(parentHostnameKey)),
flavor,
@@ -394,9 +394,9 @@ public class NodeSerializer {
return ipAddresses.build();
}
- private List<HostName> hostnamesFromSlime(Inspector object) {
+ private List<Address> addressesFromSlime(Inspector object) {
return SlimeUtils.entriesStream(object.field(containersKey))
- .map(elem -> HostName.of(elem.field(containerHostnameKey).asString()))
+ .map(elem -> new Address(elem.field(containerHostnameKey).asString()))
.toList();
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostIpConfig.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostIpConfig.java
deleted file mode 100644
index 891251fc892..00000000000
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostIpConfig.java
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.hosted.provision.provisioning;
-
-import com.yahoo.vespa.hosted.provision.node.IP;
-
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * IP config of a host and its children.
- *
- * @author mpolden
- */
-public record HostIpConfig(Map<String, IP.Config> ipConfigByHostname) {
-
- public static final HostIpConfig EMPTY = new HostIpConfig(Map.of());
-
- public HostIpConfig(Map<String, IP.Config> ipConfigByHostname) {
- this.ipConfigByHostname = Map.copyOf(Objects.requireNonNull(ipConfigByHostname));
- }
-
- public Map<String, IP.Config> asMap() {
- return ipConfigByHostname;
- }
-
- public boolean contains(String hostname) {
- return ipConfigByHostname.containsKey(hostname);
- }
-
- public IP.Config require(String hostname) {
- IP.Config ipConfig = this.ipConfigByHostname.get(hostname);
- if (ipConfig == null) throw new IllegalArgumentException("No IP config exists for node '" + hostname + "'");
- return ipConfig;
- }
-
- public boolean isEmpty() {
- return this.equals(EMPTY);
- }
-
-}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostProvisioner.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostProvisioner.java
index 3144f42a92c..38fa1abf8e2 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostProvisioner.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostProvisioner.java
@@ -10,6 +10,7 @@ import com.yahoo.config.provision.NodeAllocationException;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
import com.yahoo.vespa.hosted.provision.Node;
+import com.yahoo.vespa.hosted.provision.NodeRepository;
import java.util.List;
import java.util.Optional;
@@ -71,11 +72,12 @@ public interface HostProvisioner {
*
* @param host the host to provision
* @param children list of all the nodes that run on the given host
- * @return IP config for the provisioned host and its children
+ * @return a subset of {@code host} and {@code children} where the values have been modified and should
+ * be written back to node-repository.
* @throws FatalProvisioningException if the provisioning has irrecoverably failed and the input nodes
* should be deleted from node-repo.
*/
- HostIpConfig provision(Node host, Set<Node> children) throws FatalProvisioningException;
+ List<Node> provision(Node host, Set<Node> children) throws FatalProvisioningException;
/**
* Deprovisions a given host and resources associated with it and its children (such as DNS entries).
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidate.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidate.java
index b194730727f..fa07782057b 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidate.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidate.java
@@ -181,11 +181,11 @@ public abstract class NodeCandidate implements Nodelike, Comparable<NodeCandidat
if ( ! lessThanHalfTheHost(this) && lessThanHalfTheHost(other)) return 1;
}
- // Prefer host with the least skew
+ // Prefer host with least skew
int hostPriority = hostPriority(other);
if (hostPriority != 0) return hostPriority;
- // Prefer node with the cheapest flavor
+ // Prefer node with cheapest flavor
if (this.flavor().cost() < other.flavor().cost()) return -1;
if (other.flavor().cost() < this.flavor().cost()) return 1;
@@ -199,7 +199,7 @@ public abstract class NodeCandidate implements Nodelike, Comparable<NodeCandidat
return Integer.compare(this.allocation().get().membership().index(),
other.allocation().get().membership().index());
- // Prefer host with the latest OS version
+ // Prefer host with latest OS version
Version thisHostOsVersion = this.parent.flatMap(host -> host.status().osVersion().current()).orElse(Version.emptyVersion);
Version otherHostOsVersion = other.parent.flatMap(host -> host.status().osVersion().current()).orElse(Version.emptyVersion);
if (thisHostOsVersion.isAfter(otherHostOsVersion)) return -1;
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisionedHost.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisionedHost.java
index d083d81c196..15a6b6ba523 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisionedHost.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisionedHost.java
@@ -6,10 +6,10 @@ import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.CloudAccount;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.Flavor;
-import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
import com.yahoo.vespa.hosted.provision.Node;
+import com.yahoo.vespa.hosted.provision.node.Address;
import com.yahoo.vespa.hosted.provision.node.IP;
import com.yahoo.vespa.hosted.provision.node.OsVersion;
import com.yahoo.vespa.hosted.provision.node.Status;
@@ -32,38 +32,38 @@ public class ProvisionedHost {
private final NodeType hostType;
private final Optional<ApplicationId> exclusiveToApplicationId;
private final Optional<ClusterSpec.Type> exclusiveToClusterType;
- private final List<HostName> nodeHostnames;
+ private final List<Address> nodeAddresses;
private final NodeResources nodeResources;
private final Version osVersion;
private final CloudAccount cloudAccount;
public ProvisionedHost(String id, String hostHostname, Flavor hostFlavor, NodeType hostType,
Optional<ApplicationId> exclusiveToApplicationId, Optional<ClusterSpec.Type> exclusiveToClusterType,
- List<HostName> nodeHostnames, NodeResources nodeResources, Version osVersion, CloudAccount cloudAccount) {
+ List<Address> nodeAddresses, NodeResources nodeResources, Version osVersion, CloudAccount cloudAccount) {
this.id = Objects.requireNonNull(id, "Host id must be set");
this.hostHostname = Objects.requireNonNull(hostHostname, "Host hostname must be set");
this.hostFlavor = Objects.requireNonNull(hostFlavor, "Host flavor must be set");
this.hostType = Objects.requireNonNull(hostType, "Host type must be set");
this.exclusiveToApplicationId = Objects.requireNonNull(exclusiveToApplicationId, "exclusiveToApplicationId must be set");
this.exclusiveToClusterType = Objects.requireNonNull(exclusiveToClusterType, "exclusiveToClusterType must be set");
- this.nodeHostnames = validateNodeAddresses(nodeHostnames);
+ this.nodeAddresses = validateNodeAddresses(nodeAddresses);
this.nodeResources = Objects.requireNonNull(nodeResources, "Node resources must be set");
this.osVersion = Objects.requireNonNull(osVersion, "OS version must be set");
this.cloudAccount = Objects.requireNonNull(cloudAccount, "Cloud account must be set");
if (!hostType.isHost()) throw new IllegalArgumentException(hostType + " is not a host");
}
- private static List<HostName> validateNodeAddresses(List<HostName> nodeHostnames) {
- Objects.requireNonNull(nodeHostnames, "Node hostnames must be set");
- if (nodeHostnames.isEmpty()) {
- throw new IllegalArgumentException("There must be at least one node hostname");
+ private static List<Address> validateNodeAddresses(List<Address> nodeAddresses) {
+ Objects.requireNonNull(nodeAddresses, "Node addresses must be set");
+ if (nodeAddresses.isEmpty()) {
+ throw new IllegalArgumentException("There must be at least one node address");
}
- return nodeHostnames;
+ return nodeAddresses;
}
/** Generate {@link Node} instance representing the provisioned physical host */
public Node generateHost() {
- Node.Builder builder = Node.create(id, IP.Config.of(Set.of(), Set.of(), nodeHostnames), hostHostname, hostFlavor,
+ Node.Builder builder = Node.create(id, IP.Config.of(Set.of(), Set.of(), nodeAddresses), hostHostname, hostFlavor,
hostType)
.status(Status.initial().withOsVersion(OsVersion.EMPTY.withCurrent(Optional.of(osVersion))))
.cloudAccount(cloudAccount);
@@ -85,12 +85,12 @@ public class ProvisionedHost {
public NodeType hostType() { return hostType; }
public Optional<ApplicationId> exclusiveToApplicationId() { return exclusiveToApplicationId; }
public Optional<ClusterSpec.Type> exclusiveToClusterType() { return exclusiveToClusterType; }
- public List<HostName> nodeHostnames() { return nodeHostnames; }
+ public List<Address> nodeAddresses() { return nodeAddresses; }
public NodeResources nodeResources() { return nodeResources; }
public Version osVersion() { return osVersion; }
public CloudAccount cloudAccount() { return cloudAccount; }
- public String nodeHostname() { return nodeHostnames.get(0).value(); }
+ public String nodeHostname() { return nodeAddresses.get(0).hostname(); }
@Override
public boolean equals(Object o) {
@@ -103,7 +103,7 @@ public class ProvisionedHost {
hostType == that.hostType &&
exclusiveToApplicationId.equals(that.exclusiveToApplicationId) &&
exclusiveToClusterType.equals(that.exclusiveToClusterType) &&
- nodeHostnames.equals(that.nodeHostnames) &&
+ nodeAddresses.equals(that.nodeAddresses) &&
nodeResources.equals(that.nodeResources) &&
osVersion.equals(that.osVersion) &&
cloudAccount.equals(that.cloudAccount);
@@ -111,7 +111,7 @@ public class ProvisionedHost {
@Override
public int hashCode() {
- return Objects.hash(id, hostHostname, hostFlavor, hostType, exclusiveToApplicationId, exclusiveToClusterType, nodeHostnames, nodeResources, osVersion, cloudAccount);
+ return Objects.hash(id, hostHostname, hostFlavor, hostType, exclusiveToApplicationId, exclusiveToClusterType, nodeAddresses, nodeResources, osVersion, cloudAccount);
}
@Override
@@ -123,7 +123,7 @@ public class ProvisionedHost {
", hostType=" + hostType +
", exclusiveToApplicationId=" + exclusiveToApplicationId +
", exclusiveToClusterType=" + exclusiveToClusterType +
- ", nodeAddresses=" + nodeHostnames +
+ ", nodeAddresses=" + nodeAddresses +
", nodeResources=" + nodeResources +
", osVersion=" + osVersion +
", cloudAccount=" + cloudAccount +
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodePatcher.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodePatcher.java
index dfe01f5f1c3..582d5963cfd 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodePatcher.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodePatcher.java
@@ -6,7 +6,6 @@ import com.yahoo.component.Version;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.DockerImage;
-import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.NodeFlavors;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.TenantName;
@@ -20,6 +19,7 @@ import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeMutex;
import com.yahoo.vespa.hosted.provision.NodeRepository;
+import com.yahoo.vespa.hosted.provision.node.Address;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.node.Allocation;
import com.yahoo.vespa.hosted.provision.node.IP;
@@ -245,15 +245,12 @@ public class NodePatcher {
private Node applyIpconfigField(Node node, String name, Inspector value, LockedNodeList nodes) {
switch (name) {
- case "ipAddresses" -> {
+ case "ipAddresses":
return IP.Config.verify(node.with(node.ipConfig().withPrimary(asStringSet(value))), nodes);
- }
- case "additionalIpAddresses" -> {
+ case "additionalIpAddresses":
return IP.Config.verify(node.with(node.ipConfig().withPool(node.ipConfig().pool().withIpAddresses(asStringSet(value)))), nodes);
- }
- case "additionalHostnames" -> {
- return IP.Config.verify(node.with(node.ipConfig().withPool(node.ipConfig().pool().withHostnames(asHostnames(value)))), nodes);
- }
+ case "additionalHostnames":
+ return IP.Config.verify(node.with(node.ipConfig().withPool(node.ipConfig().pool().withAddresses(asAddressList(value)))), nodes);
}
throw new IllegalArgumentException("Could not apply field '" + name + "' on a node: No such modifiable field");
}
@@ -320,19 +317,20 @@ public class NodePatcher {
return strings;
}
- private List<HostName> asHostnames(Inspector field) {
+ private List<Address> asAddressList(Inspector field) {
if ( ! field.type().equals(Type.ARRAY))
throw new IllegalArgumentException("Expected an ARRAY value, got a " + field.type());
- List<HostName> hostnames = new ArrayList<>(field.entries());
+ List<Address> addresses = new ArrayList<>(field.entries());
for (int i = 0; i < field.entries(); i++) {
Inspector entry = field.entry(i);
if ( ! entry.type().equals(Type.STRING))
throw new IllegalArgumentException("Expected a STRING value, got a " + entry.type());
- hostnames.add(HostName.of(entry.asString()));
+ Address address = new Address(entry.asString());
+ addresses.add(address);
}
- return hostnames;
+ return addresses;
}
private Node patchRequiredDiskSpeed(Node node, String value) {
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesResponse.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesResponse.java
index f98c4ba1199..49e6265b6da 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesResponse.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesResponse.java
@@ -6,17 +6,18 @@ import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.CloudAccount;
import com.yahoo.config.provision.ClusterMembership;
import com.yahoo.config.provision.DockerImage;
-import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.serialization.NetworkPortsSerializer;
import com.yahoo.container.jdisc.HttpRequest;
import com.yahoo.restapi.SlimeJsonResponse;
import com.yahoo.slime.Cursor;
+import com.yahoo.vespa.applicationmodel.HostName;
import com.yahoo.vespa.flags.FetchVector;
import com.yahoo.vespa.flags.PermanentFlags;
import com.yahoo.vespa.flags.StringFlag;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeRepository;
+import com.yahoo.vespa.hosted.provision.node.Address;
import com.yahoo.vespa.hosted.provision.node.Allocation;
import com.yahoo.vespa.hosted.provision.node.History;
import com.yahoo.vespa.hosted.provision.node.TrustStoreItem;
@@ -51,7 +52,7 @@ class NodesResponse extends SlimeJsonResponse {
private final NodeFilter filter;
private final boolean recursive;
- private final Function<com.yahoo.vespa.applicationmodel.HostName, Optional<HostInfo>> orchestrator;
+ private final Function<HostName, Optional<HostInfo>> orchestrator;
private final NodeRepository nodeRepository;
private final StringFlag wantedDockerTagFlag;
@@ -150,7 +151,7 @@ class NodesResponse extends SlimeJsonResponse {
object.setString("wantedVespaVersion", allocation.membership().cluster().vespaVersion().toFullString());
NodeResourcesSerializer.toSlime(allocation.requestedResources(), object.setObject("requestedResources"));
allocation.networkPorts().ifPresent(ports -> NetworkPortsSerializer.toSlime(ports, object.setArray("networkPorts")));
- orchestrator.apply(new com.yahoo.vespa.applicationmodel.HostName(node.hostname()))
+ orchestrator.apply(new HostName(node.hostname()))
.ifPresent(info -> {
if (info.status() != HostStatus.NO_REMARKS) {
object.setString("orchestratorStatus", info.status().asString());
@@ -179,8 +180,8 @@ class NodesResponse extends SlimeJsonResponse {
toSlime(node.history().events(), object.setArray("history"));
toSlime(node.history().log(), object.setArray("log"));
ipAddressesToSlime(node.ipConfig().primary(), object.setArray("ipAddresses"));
- ipAddressesToSlime(node.ipConfig().pool().asSet(), object.setArray("additionalIpAddresses"));
- hostnamesToSlime(node.ipConfig().pool().hostnames(), object);
+ ipAddressesToSlime(node.ipConfig().pool().ipSet(), object.setArray("additionalIpAddresses"));
+ addressesToSlime(node.ipConfig().pool().getAddressList(), object);
node.reports().toSlime(object, "reports");
node.modelName().ifPresent(modelName -> object.setString("modelName", modelName));
node.switchHostname().ifPresent(switchHostname -> object.setString("switchHostname", switchHostname));
@@ -248,11 +249,11 @@ class NodesResponse extends SlimeJsonResponse {
ipAddresses.forEach(array::addString);
}
- private void hostnamesToSlime(List<HostName> hostnames, Cursor object) {
- if (hostnames.isEmpty()) return;
+ private void addressesToSlime(List<Address> addresses, Cursor object) {
+ if (addresses.isEmpty()) return;
// When/if Address becomes richer: add another field (e.g. "addresses") and expand to array of objects
Cursor addressesArray = object.setArray("additionalHostnames");
- hostnames.forEach(hostname -> addressesArray.addString(hostname.value()));
+ addresses.forEach(address -> addressesArray.addString(address.hostname()));
}
private void trustedCertsToSlime(List<TrustStoreItem> trustStoreItems, Cursor object) {
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java
index dadef5ce243..543901621d0 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java
@@ -7,7 +7,6 @@ import com.yahoo.config.provision.ApplicationLockException;
import com.yahoo.config.provision.CloudAccount;
import com.yahoo.config.provision.Flavor;
import com.yahoo.config.provision.HostFilter;
-import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.NodeFlavors;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
@@ -34,6 +33,7 @@ import com.yahoo.vespa.hosted.provision.NodeMutex;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.applications.Application;
import com.yahoo.vespa.hosted.provision.autoscale.Load;
+import com.yahoo.vespa.hosted.provision.node.Address;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.node.IP;
import com.yahoo.vespa.hosted.provision.node.filter.ApplicationFilter;
@@ -280,12 +280,12 @@ public class NodesV2ApiHandler extends ThreadedHttpRequestHandler {
Set<String> ipAddressPool = new HashSet<>();
inspector.field("additionalIpAddresses").traverse((ArrayTraverser) (i, item) -> ipAddressPool.add(item.asString()));
- List<HostName> hostnames = new ArrayList<>();
+ List<Address> addressPool = new ArrayList<>();
inspector.field("additionalHostnames").traverse((ArrayTraverser) (i, item) ->
- hostnames.add(HostName.of(item.asString())));
+ addressPool.add(new Address(item.asString())));
Node.Builder builder = Node.create(inspector.field("id").asString(),
- IP.Config.of(ipAddresses, ipAddressPool, hostnames),
+ IP.Config.of(ipAddresses, ipAddressPool, addressPool),
inspector.field("hostname").asString(),
flavorFromSlime(inspector),
nodeTypeFromSlime(inspector.field("type")))
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockHostProvisioner.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockHostProvisioner.java
index ad53dc8727d..b0ff82bb809 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockHostProvisioner.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockHostProvisioner.java
@@ -3,19 +3,19 @@ package com.yahoo.vespa.hosted.provision.testutils;
import com.yahoo.component.Version;
import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.Cloud;
import com.yahoo.config.provision.CloudAccount;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.Flavor;
import com.yahoo.config.provision.HostEvent;
-import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.NodeAllocationException;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
import com.yahoo.vespa.hosted.provision.Node;
+import com.yahoo.vespa.hosted.provision.node.Address;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.node.IP;
import com.yahoo.vespa.hosted.provision.provisioning.FatalProvisioningException;
-import com.yahoo.vespa.hosted.provision.provisioning.HostIpConfig;
import com.yahoo.vespa.hosted.provision.provisioning.HostProvisioner;
import com.yahoo.vespa.hosted.provision.provisioning.HostResourcesCalculator;
import com.yahoo.vespa.hosted.provision.provisioning.ProvisionedHost;
@@ -24,13 +24,12 @@ import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
+import java.util.stream.Collectors;
import java.util.stream.IntStream;
/**
@@ -85,7 +84,7 @@ public class MockHostProvisioner implements HostProvisioner {
hostType,
sharing == HostSharing.exclusive ? Optional.of(applicationId) : Optional.empty(),
Optional.empty(),
- createHostnames(hostType, hostFlavor, index),
+ createAddressesForHost(hostType, hostFlavor, index),
resources,
osVersion,
cloudAccount));
@@ -95,16 +94,16 @@ public class MockHostProvisioner implements HostProvisioner {
}
@Override
- public HostIpConfig provision(Node host, Set<Node> children) throws FatalProvisioningException {
+ public List<Node> provision(Node host, Set<Node> children) throws FatalProvisioningException {
if (behaviours.contains(Behaviour.failProvisioning)) throw new FatalProvisioningException("Failed to provision node(s)");
if (host.state() != Node.State.provisioned) throw new IllegalStateException("Host to provision must be in " + Node.State.provisioned);
- Map<String, IP.Config> result = new HashMap<>();
- result.put(host.hostname(), createIpConfig(host));
+ List<Node> result = new ArrayList<>();
+ result.add(withIpAssigned(host));
for (var child : children) {
if (child.state() != Node.State.reserved) throw new IllegalStateException("Child to provisioned must be in " + Node.State.reserved);
- result.put(child.hostname(), createIpConfig(child));
+ result.add(withIpAssigned(child));
}
- return new HostIpConfig(result);
+ return result;
}
@Override
@@ -196,21 +195,21 @@ public class MockHostProvisioner implements HostProvisioner {
return flavor.resources().compatibleWith(resourcesToVerify);
}
- private List<HostName> createHostnames(NodeType hostType, Flavor flavor, int hostIndex) {
+ private List<Address> createAddressesForHost(NodeType hostType, Flavor flavor, int hostIndex) {
long numAddresses = Math.max(2, Math.round(flavor.resources().bandwidthGbps()));
return IntStream.range(1, (int) numAddresses)
.mapToObj(i -> {
String hostname = hostType == NodeType.host
? "host" + hostIndex + "-" + i
: hostType.childNodeType().name() + i;
- return HostName.of(hostname);
+ return new Address(hostname);
})
.toList();
}
- public IP.Config createIpConfig(Node node) {
+ public Node withIpAssigned(Node node) {
if (!node.type().isHost()) {
- return node.ipConfig().withPrimary(nameResolver.resolveAll(node.hostname()));
+ return node.with(node.ipConfig().withPrimary(nameResolver.resolveAll(node.hostname())));
}
int hostIndex = Integer.parseInt(node.hostname().replaceAll("^[a-z]+|-\\d+$", ""));
Set<String> addresses = Set.of("::" + hostIndex + ":0");
@@ -224,7 +223,7 @@ public class MockHostProvisioner implements HostProvisioner {
}
}
IP.Pool pool = node.ipConfig().pool().withIpAddresses(ipAddressPool);
- return node.ipConfig().withPrimary(addresses).withPool(pool);
+ return node.with(node.ipConfig().withPrimary(addresses).withPool(pool));
}
public enum Behaviour {
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTester.java
index 4d0b3e75740..b964bf871c1 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTester.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTester.java
@@ -74,7 +74,7 @@ public class NodeRepositoryTester {
private Node addNode(String id, String hostname, String parentHostname, Flavor flavor, NodeType type) {
Set<String> ips = nodeRepository.nameResolver().resolveAll(hostname);
- IP.Config ipConfig = IP.Config.of(ips, type.isHost() ? ips : Set.of());
+ IP.Config ipConfig = new IP.Config(ips, type.isHost() ? ips : Set.of());
Node node = Node.create(id, ipConfig, hostname, flavor, type).parentHostname(parentHostname).build();
return nodeRepository.nodes().addNodes(List.of(node), Agent.system).get(0);
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/CapacityCheckerTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/CapacityCheckerTester.java
index f8ec271ce5f..606bc55fdd2 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/CapacityCheckerTester.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/CapacityCheckerTester.java
@@ -156,8 +156,8 @@ public class CapacityCheckerTester {
.collect(Collectors.toSet());
NodeResources nr = containingNodeResources(childResources, excessCapacity);
- Node node = Node.create(hostname, IP.Config.of(Set.of("::"), availableIps), hostname,
- new Flavor(nr), NodeType.host).build();
+ Node node = Node.create(hostname, new IP.Config(Set.of("::"), availableIps), hostname,
+ new Flavor(nr), NodeType.host).build();
hosts.computeIfAbsent(tenantHostApp, (ignored) -> new ArrayList<>())
.add(node);
}
@@ -175,8 +175,8 @@ public class CapacityCheckerTester {
Set<String> availableIps = IntStream.range(2000, 2000 + ips)
.mapToObj(n -> String.format("%04X::%04X", hostId, n))
.collect(Collectors.toSet());
- Node node = Node.create(hostname, IP.Config.of(Set.of("::" + (1000 + hostId)), availableIps), hostname,
- new Flavor(capacity), NodeType.host).build();
+ Node node = Node.create(hostname, new IP.Config(Set.of("::" + (1000 + hostId)), availableIps), hostname,
+ new Flavor(capacity), NodeType.host).build();
hosts.add(node);
}
return hosts;
@@ -290,7 +290,7 @@ public class CapacityCheckerTester {
Flavor f = new Flavor(nr);
Node.Builder builder = Node.create(nodeModel.id, nodeModel.hostname, f, nodeModel.state, nodeModel.type)
- .ipConfig(IP.Config.of(nodeModel.ipAddresses, nodeModel.additionalIpAddresses));
+ .ipConfig(new IP.Config(nodeModel.ipAddresses, nodeModel.additionalIpAddresses));
nodeModel.parentHostname.ifPresent(builder::parentHostname);
Node node = builder.build();
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainerTest.java
index a8f5b652366..50e19b78905 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainerTest.java
@@ -26,6 +26,7 @@ import com.yahoo.vespa.flags.custom.ClusterCapacity;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeRepository;
+import com.yahoo.vespa.hosted.provision.node.Address;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.node.Allocation;
import com.yahoo.vespa.hosted.provision.node.Generation;
@@ -649,9 +650,9 @@ public class HostCapacityMaintainerTest {
flavor.resources(),
Generation.initial(),
false));
- List<com.yahoo.config.provision.HostName> hostnames = Stream.of(additionalHostnames).map(com.yahoo.config.provision.HostName::of).toList();
+ List<Address> addresses = Stream.of(additionalHostnames).map(Address::new).toList();
Node.Builder builder = Node.create("fake-id-" + hostname, hostname, flavor, state, nodeType)
- .ipConfig(IP.Config.of(state == Node.State.active ? Set.of("::1") : Set.of(), Set.of(), hostnames));
+ .ipConfig(new IP.Config(state == Node.State.active ? Set.of("::1") : Set.of(), Set.of(), addresses));
parentHostname.ifPresent(builder::parentHostname);
allocation.ifPresent(builder::allocation);
if (hostname.equals("host2-1"))
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostResumeProvisionerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostResumeProvisionerTest.java
index 8280c0e33fc..5e507d447ab 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostResumeProvisionerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostResumeProvisionerTest.java
@@ -78,12 +78,12 @@ public class HostResumeProvisionerTest {
hostResumeProvisioner.maintain();
assertTrue("No IP addresses written as DNS updates are failing",
- provisioning.get().stream().allMatch(host -> host.ipConfig().pool().asSet().isEmpty()));
+ provisioning.get().stream().allMatch(host -> host.ipConfig().pool().ipSet().isEmpty()));
hostProvisioner.without(MockHostProvisioner.Behaviour.failDnsUpdate);
hostResumeProvisioner.maintain();
assertTrue("IP addresses written as DNS updates are succeeding",
- provisioning.get().stream().noneMatch(host -> host.ipConfig().pool().asSet().isEmpty()));
+ provisioning.get().stream().noneMatch(host -> host.ipConfig().pool().ipSet().isEmpty()));
}
@Test
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java
index 2187611b702..44050fa747c 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java
@@ -176,7 +176,7 @@ public class MetricsReporterTest {
// Allow 4 containers
Set<String> ipAddressPool = Set.of("::2", "::3", "::4", "::5");
- Node dockerHost = Node.create("node-id-1", IP.Config.of(Set.of("::1"), ipAddressPool), "dockerHost",
+ Node dockerHost = Node.create("node-id-1", new IP.Config(Set.of("::1"), ipAddressPool), "dockerHost",
nodeFlavors.getFlavorOrThrow("host"), NodeType.host).build();
nodeRepository.nodes().addNodes(List.of(dockerHost), Agent.system);
nodeRepository.nodes().deallocateRecursively("dockerHost", Agent.system, getClass().getSimpleName());
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java
index a07a4f2c72a..1b0826a8323 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java
@@ -244,8 +244,8 @@ public class NodeFailTester {
for (int i = startIndex; i < startIndex + count; i++) {
String hostname = "host" + i;
Set<String> ipPool = nodeType.isHost() ? Set.of("127.0." + i + "." + (++lastOctetOfPoolAddress)) : Set.of();
- IP.Config ipConfig = IP.Config.of(nodeRepository.nameResolver().resolveAll(hostname),
- ipPool);
+ IP.Config ipConfig = new IP.Config(nodeRepository.nameResolver().resolveAll(hostname),
+ ipPool);
Node.Builder builder = Node.create("node" + i, ipConfig, hostname, flavor, nodeType);
parentHostname.ifPresent(builder::parentHostname);
nodes.add(builder.build());
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java
index 58f4be18992..f5e524a90cc 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java
@@ -239,8 +239,8 @@ public class RetiredExpirerTest {
MockNameResolver nameResolver = (MockNameResolver) tester.nodeRepository().nameResolver();
String ipv4 = "127.0.1.4";
nameResolver.addRecord(retiredNode.hostname(), ipv4);
- Node node = Node.create(retiredNode.hostname(), IP.Config.of(Set.of(ipv4), Set.of()), retiredNode.hostname(),
- tester.asFlavor("default", NodeType.config), NodeType.config).build();
+ Node node = Node.create(retiredNode.hostname(), new IP.Config(Set.of(ipv4), Set.of()), retiredNode.hostname(),
+ tester.asFlavor("default", NodeType.config), NodeType.config).build();
var nodes = List.of(node);
nodes = nodeRepository.nodes().addNodes(nodes, Agent.system);
nodes = nodeRepository.nodes().deallocate(nodes, Agent.system, getClass().getSimpleName());
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/SpareCapacityMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/SpareCapacityMaintainerTest.java
index b54975cbf41..c9421f098e7 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/SpareCapacityMaintainerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/SpareCapacityMaintainerTest.java
@@ -327,8 +327,8 @@ public class SpareCapacityMaintainerTest {
}
private IP.Config ipConfig(int id, boolean host) {
- return IP.Config.of(Set.of(String.format("%04X::%04X", id, 0)),
- host ? IntStream.range(0, 10)
+ return new IP.Config(Set.of(String.format("%04X::%04X", id, 0)),
+ host ? IntStream.range(0, 10)
.mapToObj(n -> String.format("%04X::%04X", id, n))
.collect(Collectors.toSet())
: Set.of());
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 88fe88dbaad..c26ffdaa023 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
@@ -2,7 +2,6 @@
package com.yahoo.vespa.hosted.provision.node;
import com.google.common.collect.ImmutableSet;
-import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.NodeFlavors;
import com.yahoo.config.provision.NodeType;
import com.yahoo.vespa.hosted.provision.LockedNodeList;
@@ -15,6 +14,7 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
+import java.util.stream.Collectors;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -156,7 +156,7 @@ public class IPTest {
IP.Config config = IP.Config.of(Set.of("2600:1f10:::1"),
Set.of("2600:1f10:::2", "2600:1f10:::3"),
- List.of(HostName.of("node1"), HostName.of("node2")));
+ List.of(new Address("node1"), new Address("node2")));
IP.Pool pool = config.pool();
Optional<IP.Allocation> allocation = pool.findAllocation(emptyList, resolver, false);
}
@@ -193,12 +193,12 @@ public class IPTest {
}
IP.Pool pool = node.ipConfig().pool();
- assertNotEquals(dualStack, pool.ipAddresses().protocol() == IP.IpAddresses.Protocol.ipv4);
+ assertNotEquals(dualStack, pool.getProtocol() == IP.IpAddresses.Protocol.ipv4);
return pool;
}
private static Node createNode(Set<String> ipAddresses) {
- return Node.create("id1", IP.Config.of(Set.of("127.0.0.1"), ipAddresses),
+ return Node.create("id1", new IP.Config(Set.of("127.0.0.1"), ipAddresses),
"host1", nodeFlavors.getFlavorOrThrow("default"), NodeType.host).build();
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializerTest.java
index 1086f2026a8..d61a3d95a65 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializerTest.java
@@ -9,7 +9,6 @@ import com.yahoo.config.provision.ApplicationName;
import com.yahoo.config.provision.CloudAccount;
import com.yahoo.config.provision.ClusterMembership;
import com.yahoo.config.provision.ClusterSpec;
-import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.InstanceName;
import com.yahoo.config.provision.NetworkPorts;
import com.yahoo.config.provision.NodeFlavors;
@@ -24,6 +23,7 @@ import com.yahoo.test.ManualClock;
import com.yahoo.text.Utf8;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.Node.State;
+import com.yahoo.vespa.hosted.provision.node.Address;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.node.Generation;
import com.yahoo.vespa.hosted.provision.node.History;
@@ -249,7 +249,7 @@ public class NodeSerializerTest {
@Test
public void serialize_parent_hostname() {
final String parentHostname = "parent.yahoo.com";
- Node node = Node.create("myId", IP.Config.of(Set.of("127.0.0.1"), Set.of()), "myHostname", nodeFlavors.getFlavorOrThrow("default"), NodeType.tenant)
+ Node node = Node.create("myId", new IP.Config(Set.of("127.0.0.1"), Set.of()), "myHostname", nodeFlavors.getFlavorOrThrow("default"), NodeType.tenant)
.parentHostname(parentHostname)
.build();
@@ -272,14 +272,16 @@ public class NodeSerializerTest {
// Test round-trip with address pool
node = node.with(node.ipConfig().withPool(IP.Pool.of(
Set.of("::1", "::2", "::3"),
- List.of(HostName.of("a"), HostName.of("b"), HostName.of("c")))));
+ List.of(new Address("a"), new Address("b"), new Address("c")))));
Node copy = nodeSerializer.fromJson(nodeSerializer.toJson(node));
- assertEquals(node.ipConfig(), copy.ipConfig());
+ assertEquals(node.ipConfig().pool().ipSet(), copy.ipConfig().pool().ipSet());
+ assertEquals(Set.copyOf(node.ipConfig().pool().getAddressList()), Set.copyOf(copy.ipConfig().pool().getAddressList()));
// Test round-trip without address pool (handle empty pool)
node = createNode();
copy = nodeSerializer.fromJson(nodeSerializer.toJson(node));
- assertEquals(node.ipConfig(), copy.ipConfig());
+ assertEquals(node.ipConfig().pool().ipSet(), copy.ipConfig().pool().ipSet());
+ assertEquals(Set.copyOf(node.ipConfig().pool().getAddressList()), Set.copyOf(copy.ipConfig().pool().getAddressList()));
}
@Test
@@ -527,7 +529,7 @@ public class NodeSerializerTest {
private Node createNode() {
return Node.create("myId",
- IP.Config.of(Set.of("127.0.0.1"), Set.of()),
+ new IP.Config(Set.of("127.0.0.1"), Set.of()),
"myHostname",
nodeFlavors.getFlavorOrThrow("default"),
NodeType.tenant).build();
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicAllocationTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicAllocationTest.java
index 47d34a76dd6..23c2d0fc47a 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicAllocationTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicAllocationTest.java
@@ -534,7 +534,7 @@ public class DynamicAllocationTest {
}
private void addAndAssignNode(ApplicationId id, String hostname, String parentHostname, ClusterSpec clusterSpec, NodeResources flavor, int index, ProvisioningTester tester) {
- Node node1a = Node.create("open1", IP.Config.of(Set.of("127.0.233." + index), Set.of()), hostname,
+ Node node1a = Node.create("open1", new IP.Config(Set.of("127.0.233." + index), Set.of()), hostname,
new Flavor(flavor), NodeType.tenant).parentHostname(parentHostname).build();
ClusterMembership clusterMembership1 = ClusterMembership.from(
clusterSpec.with(Optional.of(ClusterSpec.Group.from(0))), index); // Need to add group here so that group is serialized in node allocation
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicProvisioningTest.java
index 6ea5b424d03..6362a07ae00 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicProvisioningTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicProvisioningTest.java
@@ -453,7 +453,7 @@ public class DynamicProvisioningTest {
if (!provisionedHosts.isEmpty()) {
List<Node> hosts = provisionedHosts.asList()
.stream()
- .map(h -> h.with(((MockHostProvisioner) tester.hostProvisioner()).createIpConfig(h)))
+ .map(h -> ((MockHostProvisioner)tester.hostProvisioner()).withIpAssigned(h))
.toList();
tester.move(Node.State.ready, hosts);
tester.activateTenantHosts();
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicProvisioningTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicProvisioningTester.java
index e59b628ccfd..5beb4b11c0c 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicProvisioningTester.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicProvisioningTester.java
@@ -124,9 +124,9 @@ public class DynamicProvisioningTester {
public void makeReady(String hostname) {
Node node = nodeRepository().nodes().node(hostname).get();
- provisioningTester.patchNode(node, (n) -> n.with(IP.Config.of(Set.of("::" + 0 + ":0"), Set.of())));
+ provisioningTester.patchNode(node, (n) -> n.with(new IP.Config(Set.of("::" + 0 + ":0"), Set.of())));
Node host = nodeRepository().nodes().node(node.parentHostname().get()).get();
- host = host.with(IP.Config.of(Set.of("::" + 0 + ":0"), Set.of("::" + 0 + ":2")));
+ host = host.with(new IP.Config(Set.of("::" + 0 + ":0"), Set.of("::" + 0 + ":2")));
if (host.state() == Node.State.provisioned)
provisioningTester.move(Node.State.ready, host);
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/HostCapacityTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/HostCapacityTest.java
index 12a8e4d9386..ea2af5f3fca 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/HostCapacityTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/HostCapacityTest.java
@@ -2,12 +2,12 @@
package com.yahoo.vespa.hosted.provision.provisioning;
import com.yahoo.config.provision.Flavor;
-import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.NodeFlavors;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
import com.yahoo.vespa.hosted.provision.LockedNodeList;
import com.yahoo.vespa.hosted.provision.Node;
+import com.yahoo.vespa.hosted.provision.node.Address;
import com.yahoo.vespa.hosted.provision.node.IP;
import org.junit.Before;
import org.junit.Test;
@@ -16,6 +16,7 @@ import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.junit.Assert.assertEquals;
@@ -166,7 +167,7 @@ public class HostCapacityTest {
}
private Node setupHostWithAdditionalHostnames(String hostHostname, String... additionalHostnames) {
- List<HostName> hostnames = Stream.of(additionalHostnames).map(HostName::of).toList();
+ List<Address> addresses = Stream.of(additionalHostnames).map(Address::new).toList();
doAnswer(invocation -> ((Flavor)invocation.getArguments()[0]).resources())
.when(hostResourcesCalculator).advertisedResourcesOf(any());
@@ -175,7 +176,7 @@ public class HostCapacityTest {
"host", // 7-100-120-5
"docker"); // 2- 40- 40-0.5 = resources1
- return Node.create(hostHostname, IP.Config.of(Set.of("::1"), Set.of(), hostnames), hostHostname,
+ return Node.create(hostHostname, IP.Config.of(Set.of("::1"), Set.of(), addresses), hostHostname,
nodeFlavors.getFlavorOrThrow("host"), NodeType.host).build();
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidateTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidateTest.java
index 32db213c445..20819daf356 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidateTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidateTest.java
@@ -146,7 +146,7 @@ public class NodeCandidateTest {
.parentHostname(hostname + "parent")
.ipConfigWithEmptyPool(Set.of("::1")).build();
Node parent = Node.create(hostname + "parent", hostname, new Flavor(totalHostResources), Node.State.ready, NodeType.host)
- .ipConfig(IP.Config.of(Set.of("::1"), Set.of("::2")))
+ .ipConfig(new IP.Config(Set.of("::1"), Set.of("::2")))
.build();
return new NodeCandidate.ConcreteNodeCandidate(node, totalHostResources.subtract(allocatedHostResources), Optional.of(parent),
false, exclusiveSwitch, false, true, false);
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java
index 978edf3f7e4..4c404e3030c 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java
@@ -919,10 +919,10 @@ public class ProvisioningTest {
// Add 2 config server hosts and 2 config servers
Flavor flavor = tester.nodeRepository().flavors().getFlavorOrThrow("default");
List<Node> nodes = List.of(
- Node.create("cfghost1", IP.Config.of(Set.of("::1:0"), Set.of("::1:1")), "cfghost1", flavor, NodeType.confighost).build(),
- Node.create("cfghost2", IP.Config.of(Set.of("::2:0"), Set.of("::2:1")), "cfghost2", flavor, NodeType.confighost).ipConfig(IP.Config.of(Set.of("::2:0"), Set.of("::2:1"), List.of())).build(),
- Node.create("cfg1", IP.Config.of(Set.of("::1:1"), Set.of()), "cfg1", flavor, NodeType.config).parentHostname("cfghost1").build(),
- Node.create("cfg2", IP.Config.of(Set.of("::2:1"), Set.of()), "cfg2", flavor, NodeType.config).parentHostname("cfghost2").build());
+ Node.create("cfghost1", new IP.Config(Set.of("::1:0"), Set.of("::1:1")), "cfghost1", flavor, NodeType.confighost).build(),
+ Node.create("cfghost2", new IP.Config(Set.of("::2:0"), Set.of("::2:1")), "cfghost2", flavor, NodeType.confighost).ipConfig(IP.Config.of(Set.of("::2:0"), Set.of("::2:1"), List.of())).build(),
+ Node.create("cfg1", new IP.Config(Set.of("::1:1"), Set.of()), "cfg1", flavor, NodeType.config).parentHostname("cfghost1").build(),
+ Node.create("cfg2", new IP.Config(Set.of("::2:1"), Set.of()), "cfg2", flavor, NodeType.config).parentHostname("cfghost2").build());
tester.move(Node.State.ready, tester.nodeRepository().nodes().addNodes(nodes, Agent.system));
InfraApplication cfgHostApp = new ConfigServerHostApplication();
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java
index d0ff11fde0c..06f26bc1d8b 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java
@@ -201,7 +201,7 @@ public class ProvisioningTester {
try (var lock = nodeRepository.nodes().lockAndGetRequired(prepared.hostname())) {
Node node = lock.node();
if (node.ipConfig().primary().isEmpty()) {
- node = node.with(IP.Config.of(Set.of("::" + 0 + ":0"), Set.of()));
+ node = node.with(new IP.Config(Set.of("::" + 0 + ":0"), Set.of()));
nodeRepository.nodes().write(node, lock);
}
if (node.parentHostname().isEmpty()) continue;
@@ -209,7 +209,7 @@ public class ProvisioningTester {
if (parent.state() == Node.State.active) continue;
NestedTransaction t = new NestedTransaction();
if (parent.ipConfig().primary().isEmpty())
- parent = parent.with(IP.Config.of(Set.of("::" + 0 + ":0"), Set.of("::" + 0 + ":2")));
+ parent = parent.with(new IP.Config(Set.of("::" + 0 + ":0"), Set.of("::" + 0 + ":2")));
nodeRepository.nodes().activate(List.of(parent), t);
t.commit();
}
@@ -447,7 +447,7 @@ public class ProvisioningTester {
nameResolver.addRecord(nodeHostname, ipv4Addr);
}
}
- Node.Builder builder = Node.create(hostname, IP.Config.of(hostIps, ipAddressPool), hostname, flavor, type);
+ Node.Builder builder = Node.create(hostname, new IP.Config(hostIps, ipAddressPool), hostname, flavor, type);
reservedTo.ifPresent(builder::reservedTo);
nodes.add(builder.build());
}
@@ -464,8 +464,8 @@ public class ProvisioningTester {
String ipv4 = "127.0.1." + i;
nameResolver.addRecord(hostname, ipv4);
- Node node = Node.create(hostname, IP.Config.of(Set.of(ipv4), Set.of()), hostname,
- nodeFlavors.getFlavorOrThrow(flavor), NodeType.config).build();
+ Node node = Node.create(hostname, new IP.Config(Set.of(ipv4), Set.of()), hostname,
+ nodeFlavors.getFlavorOrThrow(flavor), NodeType.config).build();
nodes.add(node);
}
@@ -532,7 +532,7 @@ public class ProvisioningTester {
List<Node> nodes = new ArrayList<>(count);
for (int i = startIndex; i < count + startIndex; i++) {
String hostname = nodeNamer.apply(i);
- IP.Config ipConfig = IP.Config.of(nodeRepository.nameResolver().resolveAll(hostname), Set.of());
+ IP.Config ipConfig = new IP.Config(nodeRepository.nameResolver().resolveAll(hostname), Set.of());
Node node = Node.create("node-id", ipConfig, hostname, new Flavor(resources), nodeType)
.parentHostname(parentHostname)
.build();