diff options
90 files changed, 1535 insertions, 1494 deletions
diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/identitydocument/IdentityDocumentGenerator.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/identitydocument/IdentityDocumentGenerator.java index 123a9bc7449..cf4ca85ecfd 100644 --- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/identitydocument/IdentityDocumentGenerator.java +++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/identitydocument/IdentityDocumentGenerator.java @@ -47,7 +47,7 @@ public class IdentityDocumentGenerator { public SignedIdentityDocument generateSignedIdentityDocument(String hostname, IdentityType identityType) { try { - Node node = nodeRepository.getNode(hostname).orElseThrow(() -> new RuntimeException("Unable to find node " + hostname)); + Node node = nodeRepository.nodes().getNode(hostname).orElseThrow(() -> new RuntimeException("Unable to find node " + hostname)); Allocation allocation = node.allocation().orElseThrow(() -> new RuntimeException("No allocation for node " + node.hostname())); VespaUniqueInstanceId providerUniqueId = new VespaUniqueInstanceId( allocation.membership().index(), diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceValidator.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceValidator.java index c258e1be466..40782455025 100644 --- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceValidator.java +++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceValidator.java @@ -137,7 +137,7 @@ public class InstanceValidator { } // Find node matching vespa unique id - Node node = nodeRepository.getNodes().stream() + Node node = nodeRepository.nodes().getNodes().stream() .filter(n -> n.allocation().isPresent()) .filter(n -> nodeMatchesVespaUniqueId(n, vespaUniqueInstanceId)) .findFirst() // Should be only one diff --git a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/identitydocument/IdentityDocumentGeneratorTest.java b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/identitydocument/IdentityDocumentGeneratorTest.java index 0a757b5b17b..a6dfc6e9b9e 100644 --- a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/identitydocument/IdentityDocumentGeneratorTest.java +++ b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/identitydocument/IdentityDocumentGeneratorTest.java @@ -24,6 +24,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.IP; +import com.yahoo.vespa.hosted.provision.node.Nodes; import com.yahoo.vespa.hosted.provision.testutils.MockNodeFlavors; import org.junit.Test; @@ -68,8 +69,11 @@ public class IdentityDocumentGeneratorTest { NodeType.tenant) .allocation(allocation).build(); NodeRepository nodeRepository = mock(NodeRepository.class); - when(nodeRepository.getNode(eq(parentHostname))).thenReturn(Optional.of(parentNode)); - when(nodeRepository.getNode(eq(containerHostname))).thenReturn(Optional.of(containerNode)); + Nodes nodes = mock(Nodes.class); + when(nodeRepository.nodes()).thenReturn(nodes); + + when(nodes.getNode(eq(parentHostname))).thenReturn(Optional.of(parentNode)); + when(nodes.getNode(eq(containerHostname))).thenReturn(Optional.of(containerNode)); AutoGeneratedKeyProvider keyProvider = new AutoGeneratedKeyProvider(); String dnsSuffix = "vespa.dns.suffix"; diff --git a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceValidatorTest.java b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceValidatorTest.java index c5dbd9dd7b2..80bfda811d0 100644 --- a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceValidatorTest.java +++ b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceValidatorTest.java @@ -23,6 +23,7 @@ import com.yahoo.vespa.hosted.athenz.instanceproviderservice.KeyProvider; import com.yahoo.vespa.hosted.provision.Node; import com.yahoo.vespa.hosted.provision.NodeRepository; import com.yahoo.vespa.hosted.provision.node.IP; +import com.yahoo.vespa.hosted.provision.node.Nodes; import com.yahoo.vespa.hosted.provision.testutils.MockNodeFlavors; import org.junit.Test; @@ -119,12 +120,14 @@ public class InstanceValidatorTest { @Test public void accepts_valid_refresh_requests() { NodeRepository nodeRepository = mock(NodeRepository.class); + Nodes nodes = mock(Nodes.class); + when(nodeRepository.nodes()).thenReturn(nodes); InstanceValidator instanceValidator = new InstanceValidator(null, null, nodeRepository, new IdentityDocumentSigner(), vespaTenantDomain); List<Node> nodeList = createNodes(10); Node node = nodeList.get(0); nodeList = allocateNode(nodeList, node, applicationId); - when(nodeRepository.getNodes()).thenReturn(nodeList); + when(nodes.getNodes()).thenReturn(nodeList); String nodeIp = node.ipConfig().primary().stream().findAny().orElseThrow(() -> new RuntimeException("No ipaddress for mocked node")); InstanceConfirmation instanceConfirmation = createRefreshInstanceConfirmation(applicationId, domain, service, ImmutableList.of(nodeIp)); @@ -134,12 +137,15 @@ public class InstanceValidatorTest { @Test public void rejects_refresh_on_ip_mismatch() { NodeRepository nodeRepository = mock(NodeRepository.class); + Nodes nodes = mock(Nodes.class); + when(nodeRepository.nodes()).thenReturn(nodes); + InstanceValidator instanceValidator = new InstanceValidator(null, null, nodeRepository, new IdentityDocumentSigner(), vespaTenantDomain); List<Node> nodeList = createNodes(10); Node node = nodeList.get(0); nodeList = allocateNode(nodeList, node, applicationId); - when(nodeRepository.getNodes()).thenReturn(nodeList); + when(nodes.getNodes()).thenReturn(nodeList); String nodeIp = node.ipConfig().primary().stream().findAny().orElseThrow(() -> new RuntimeException("No ipaddress for mocked node")); // Add invalid ip to list of ip addresses @@ -151,10 +157,14 @@ public class InstanceValidatorTest { @Test public void rejects_refresh_when_node_is_not_allocated() { NodeRepository nodeRepository = mock(NodeRepository.class); + Nodes nodes = mock(Nodes.class); + when(nodeRepository.nodes()).thenReturn(nodes); + InstanceValidator instanceValidator = new InstanceValidator(null, null, nodeRepository, new IdentityDocumentSigner(), vespaTenantDomain); List<Node> nodeList = createNodes(10); - when(nodeRepository.getNodes()).thenReturn(nodeList); + + when(nodes.getNodes()).thenReturn(nodeList); InstanceConfirmation instanceConfirmation = createRefreshInstanceConfirmation(applicationId, domain, service, ImmutableList.of("::11")); assertFalse(instanceValidator.isValidRefresh(instanceConfirmation)); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java index 2642983dd2a..beec04b3b29 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java @@ -2,36 +2,22 @@ package com.yahoo.vespa.hosted.provision; import com.google.inject.Inject; -import com.yahoo.collections.ListMap; import com.yahoo.component.AbstractComponent; -import com.yahoo.component.Version; import com.yahoo.concurrent.maintenance.JobControl; -import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.ApplicationTransaction; import com.yahoo.config.provision.DockerImage; -import com.yahoo.config.provision.Flavor; import com.yahoo.config.provision.NodeFlavors; -import com.yahoo.config.provision.NodeType; import com.yahoo.config.provision.Zone; import com.yahoo.config.provisioning.NodeRepositoryConfig; -import com.yahoo.transaction.Mutex; -import com.yahoo.transaction.NestedTransaction; import com.yahoo.vespa.curator.Curator; import com.yahoo.vespa.flags.FlagSource; import com.yahoo.vespa.hosted.provision.Node.State; import com.yahoo.vespa.hosted.provision.applications.Applications; import com.yahoo.vespa.hosted.provision.lb.LoadBalancers; import com.yahoo.vespa.hosted.provision.maintenance.InfrastructureVersions; -import com.yahoo.vespa.hosted.provision.maintenance.NodeFailer; -import com.yahoo.vespa.hosted.provision.maintenance.PeriodicApplicationMaintainer; import com.yahoo.vespa.hosted.provision.node.Agent; -import com.yahoo.vespa.hosted.provision.node.Allocation; -import com.yahoo.vespa.hosted.provision.node.History; -import com.yahoo.vespa.hosted.provision.node.IP; import com.yahoo.vespa.hosted.provision.node.NodeAcl; -import com.yahoo.vespa.hosted.provision.node.filter.NodeFilter; -import com.yahoo.vespa.hosted.provision.node.filter.NodeListFilter; -import com.yahoo.vespa.hosted.provision.node.filter.StateFilter; +import com.yahoo.vespa.hosted.provision.node.Nodes; import com.yahoo.vespa.hosted.provision.os.OsVersions; import com.yahoo.vespa.hosted.provision.persistence.CuratorDatabaseClient; import com.yahoo.vespa.hosted.provision.persistence.DnsNameResolver; @@ -41,53 +27,21 @@ import com.yahoo.vespa.hosted.provision.provisioning.ContainerImages; import com.yahoo.vespa.hosted.provision.provisioning.FirmwareChecks; import com.yahoo.vespa.hosted.provision.provisioning.HostResourcesCalculator; import com.yahoo.vespa.hosted.provision.provisioning.ProvisionServiceProvider; -import com.yahoo.vespa.hosted.provision.restapi.NotFoundException; import java.time.Clock; import java.time.Duration; import java.time.Instant; -import java.util.ArrayList; -import java.util.EnumSet; import java.util.List; -import java.util.Map; -import java.util.Objects; import java.util.Optional; -import java.util.Set; -import java.util.function.BiFunction; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; -import java.util.stream.Stream; /** - * The hosted Vespa production node repository, which stores its state in Zookeeper. - * The node repository knows about all nodes in a zone, their states and manages all transitions between - * node states. - * <p> - * Node repo locking: Locks must be acquired before making changes to the set of nodes, or to the content - * of the nodes. - * Unallocated states use a single lock, while application level locks are used for all allocated states - * such that applications can mostly change in parallel. - * If both locks are needed acquire the application lock first, then the unallocated lock. - * <p> - * Changes to the set of active nodes must be accompanied by changes to the config model of the application. - * Such changes are not handled by the node repository but by the classes calling it - see - * {@link com.yahoo.vespa.hosted.provision.provisioning.NodeRepositoryProvisioner} for such changes initiated - * by the application package and {@link PeriodicApplicationMaintainer} - * for changes initiated by the node repository. - * Refer to {@link com.yahoo.vespa.hosted.provision.maintenance.NodeRepositoryMaintenance} for timing details - * of the node state transitions. + * The top level singleton in the node repo, providing access to all its state as child objects. * * @author bratseth */ -// Node state transitions: -// 1) (new) | deprovisioned - > provisioned -> (dirty ->) ready -> reserved -> active -> inactive -> dirty -> ready -// 2) inactive -> reserved | parked -// 3) reserved -> dirty -// 4) * -> failed | parked -> (breakfixed) -> dirty | active | deprovisioned -// 5) deprovisioned -> (forgotten) -// Nodes have an application assigned when in states reserved, active and inactive. -// Nodes might have an application assigned in dirty. public class NodeRepository extends AbstractComponent { private static final Logger log = Logger.getLogger(NodeRepository.class.getName()); @@ -95,6 +49,7 @@ public class NodeRepository extends AbstractComponent { private final CuratorDatabaseClient db; private final Clock clock; private final Zone zone; + private final Nodes nodes; private final NodeFlavors flavors; private final HostResourcesCalculator resourcesCalculator; private final NameResolver nameResolver; @@ -156,6 +111,7 @@ public class NodeRepository extends AbstractComponent { this.db = new CuratorDatabaseClient(flavors, curator, clock, zone, useCuratorClientCache, nodeCacheSize); this.zone = zone; this.clock = clock; + this.nodes = new Nodes(db, zone, clock); this.flavors = flavors; this.resourcesCalculator = provisionServiceProvider.getHostResourcesCalculator(); this.nameResolver = nameResolver; @@ -187,7 +143,10 @@ public class NodeRepository extends AbstractComponent { /** Returns the curator database client used by this */ public CuratorDatabaseClient database() { return db; } - /** @return The name resolver used to resolve hostname and ip addresses */ + /** Returns the nodes of the node repo. */ + public Nodes nodes() { return nodes; } + + /** Returns the name resolver used to resolve hostname and ip addresses */ public NameResolver nameResolver() { return nameResolver; } /** Returns the OS versions to use for nodes in this */ @@ -226,205 +185,17 @@ public class NodeRepository extends AbstractComponent { */ public List<NodeAcl> getChildAcls(Node host) { if ( ! host.type().isHost()) throw new IllegalArgumentException("Only hosts have children"); - NodeList allNodes = list(); - return list().childrenOf(host).asList().stream() + NodeList allNodes = nodes().list(); + return nodes().list().childrenOf(host).asList().stream() .map(childNode -> childNode.acl(allNodes, loadBalancers)) .collect(Collectors.toUnmodifiableList()); } - // ---------------- Query API ---------------------------------------------------------------- - - /** - * Finds and returns the node with the hostname in any of the given states, or empty if not found - * - * @param hostname the full host name of the node - * @param inState the states the node may be in. If no states are given, it will be returned from any state - * @return the node, or empty if it was not found in any of the given states - */ - public Optional<Node> getNode(String hostname, State ... inState) { - return db.readNode(hostname, inState); - } - - /** - * Returns all nodes in any of the given states. - * - * @param inState the states to return nodes from. If no states are given, all nodes of the given type are returned - * @return the node, or empty if it was not found in any of the given states - */ - public List<Node> getNodes(State ... inState) { - return new ArrayList<>(db.readNodes(inState)); - } - /** - * Finds and returns the nodes of the given type in any of the given states. - * - * @param type the node type to return - * @param inState the states to return nodes from. If no states are given, all nodes of the given type are returned - * @return the node, or empty if it was not found in any of the given states - */ - public List<Node> getNodes(NodeType type, State ... inState) { - return db.readNodes(inState).stream().filter(node -> node.type().equals(type)).collect(Collectors.toList()); - } - - /** Returns a filterable list of nodes in this repository in any of the given states */ - public NodeList list(State ... inState) { - return NodeList.copyOf(getNodes(inState)); - } - - public NodeList list(ApplicationId application, State ... inState) { - return NodeList.copyOf(getNodes(application, inState)); - } - - /** Returns a filterable list of all nodes of an application */ - public NodeList list(ApplicationId application) { - return NodeList.copyOf(getNodes(application)); - } - - /** Returns a locked list of all nodes in this repository */ - public LockedNodeList list(Mutex lock) { - return new LockedNodeList(getNodes(), lock); - } - - public List<Node> getNodes(ApplicationId id, State ... inState) { return db.readNodes(id, inState); } - public List<Node> getInactive() { return db.readNodes(State.inactive); } - public List<Node> getFailed() { return db.readNodes(State.failed); } - - /** - * Returns whether the zone managed by this node repository seems to be working. - * If too many nodes are not responding, there is probably some zone-wide issue - * and we should probably refrain from making changes to it. - */ - public boolean isWorking() { - NodeList activeNodes = list(State.active); - if (activeNodes.size() <= 5) return true; // Not enough data to decide - NodeList downNodes = activeNodes.down(); - return ! ( (double)downNodes.size() / (double)activeNodes.size() > 0.2 ); - } - - // ----------------- Node lifecycle ----------------------------------------------------------- - - /** Adds a list of newly created docker container nodes to the node repository as <i>reserved</i> nodes */ - public List<Node> addDockerNodes(LockedNodeList nodes) { - for (Node node : nodes) { - if ( ! node.flavor().getType().equals(Flavor.Type.DOCKER_CONTAINER)) - illegal("Cannot add " + node + ": This is not a docker node"); - if (node.allocation().isEmpty()) - illegal("Cannot add " + node + ": Docker containers needs to be allocated"); - Optional<Node> existing = getNode(node.hostname()); - if (existing.isPresent()) - illegal("Cannot add " + node + ": A node with this name already exists (" + - existing.get() + ", " + existing.get().history() + "). Node to be added: " + - node + ", " + node.history()); - } - return db.addNodesInState(nodes.asList(), State.reserved, Agent.system); - } - - /** - * Adds a list of (newly created) nodes to the node repository as <i>provisioned</i> nodes. - * If any of the nodes already exists in the deprovisioned state, the new node will be merged - * with the history of that node. - */ - public List<Node> addNodes(List<Node> nodes, Agent agent) { - try (Mutex lock = lockUnallocated()) { - List<Node> nodesToAdd = new ArrayList<>(); - List<Node> nodesToRemove = new ArrayList<>(); - for (int i = 0; i < nodes.size(); i++) { - var node = nodes.get(i); - - // Check for duplicates - for (int j = 0; j < i; j++) { - if (node.equals(nodes.get(j))) - illegal("Cannot add nodes: " + node + " is duplicated in the argument list"); - } - - Optional<Node> existing = getNode(node.hostname()); - if (existing.isPresent()) { - if (existing.get().state() != State.deprovisioned) - illegal("Cannot add " + node + ": A node with this name already exists"); - node = node.with(existing.get().history()); - node = node.with(existing.get().reports()); - node = node.with(node.status().withFailCount(existing.get().status().failCount())); - if (existing.get().status().firmwareVerifiedAt().isPresent()) - node = node.with(node.status().withFirmwareVerifiedAt(existing.get().status().firmwareVerifiedAt().get())); - nodesToRemove.add(existing.get()); - } - - nodesToAdd.add(node); - } - List<Node> resultingNodes = db.addNodesInState(IP.Config.verify(nodesToAdd, list(lock)), State.provisioned, agent); - db.removeNodes(nodesToRemove); - return resultingNodes; - } - } - - /** Sets a list of nodes ready and returns the nodes in the ready state */ - public List<Node> setReady(List<Node> nodes, Agent agent, String reason) { - try (Mutex lock = lockUnallocated()) { - List<Node> nodesWithResetFields = nodes.stream() - .map(node -> { - if (node.state() != State.provisioned && node.state() != State.dirty) - illegal("Can not set " + node + " ready. It is not provisioned or dirty."); - if (node.type() == NodeType.host && node.ipConfig().pool().getIpSet().isEmpty()) - illegal("Can not set host " + node + " ready. Its IP address pool is empty."); - return node.withWantToRetire(false, false, Agent.system, clock.instant()); - }) - .collect(Collectors.toList()); - - return db.writeTo(State.ready, nodesWithResetFields, agent, Optional.of(reason)); - } - } - - public Node setReady(String hostname, Agent agent, String reason) { - Node nodeToReady = getNode(hostname).orElseThrow(() -> - new NoSuchNodeException("Could not move " + hostname + " to ready: Node not found")); - - if (nodeToReady.state() == State.ready) return nodeToReady; - return setReady(List.of(nodeToReady), agent, reason).get(0); - } - - /** Reserve nodes. This method does <b>not</b> lock the node repository */ - public List<Node> reserve(List<Node> nodes) { - return db.writeTo(State.reserved, nodes, Agent.application, Optional.empty()); - } - - /** Activate nodes. This method does <b>not</b> lock the node repository */ - public List<Node> activate(List<Node> nodes, NestedTransaction transaction) { - return db.writeTo(State.active, nodes, Agent.application, Optional.empty(), transaction); - } - - /** - * Sets a list of nodes to have their allocation removable (active to inactive) in the node repository. - * - * @param application the application the nodes belong to - * @param nodes the nodes to make removable. These nodes MUST be in the active state. - */ - public void setRemovable(ApplicationId application, List<Node> nodes) { - try (Mutex lock = lock(application)) { - List<Node> removableNodes = - nodes.stream().map(node -> node.with(node.allocation().get().removable(true))) - .collect(Collectors.toList()); - write(removableNodes, lock); - } - } - - /** - * Deactivates these nodes in a transaction and returns the nodes in the new state which will hold if the - * transaction commits. - */ - public List<Node> deactivate(List<Node> nodes, ApplicationTransaction transaction) { - var stateless = NodeList.copyOf(nodes).stateless(); - var stateful = NodeList.copyOf(nodes).stateful(); - List<Node> written = new ArrayList<>(); - written.addAll(deallocate(stateless.asList(), Agent.application, "Deactivated by application", transaction.nested())); - written.addAll(db.writeTo(State.inactive, stateful.asList(), Agent.application, Optional.empty(), transaction.nested())); - return written; - - } - /** Removes this application: Active nodes are deactivated while all non-active nodes are set dirty. */ public void remove(ApplicationTransaction transaction) { - NodeList applicationNodes = list(transaction.application()); + NodeList applicationNodes = nodes().list(transaction.application()); NodeList activeNodes = applicationNodes.state(State.active); - deactivate(activeNodes.asList(), transaction); + nodes().deactivate(activeNodes.asList(), transaction); db.writeTo(State.dirty, applicationNodes.except(activeNodes.asSet()).asList(), Agent.system, @@ -433,497 +204,10 @@ public class NodeRepository extends AbstractComponent { applications.remove(transaction); } - /** Move nodes to the dirty state */ - public List<Node> deallocate(List<Node> nodes, Agent agent, String reason) { - return performOn(NodeListFilter.from(nodes), (node, lock) -> deallocate(node, agent, reason)); - } - - public List<Node> deallocateRecursively(String hostname, Agent agent, String reason) { - Node nodeToDirty = getNode(hostname).orElseThrow(() -> - new IllegalArgumentException("Could not deallocate " + hostname + ": Node not found")); - - List<Node> nodesToDirty = - (nodeToDirty.type().isHost() ? - Stream.concat(list().childrenOf(hostname).asList().stream(), Stream.of(nodeToDirty)) : - Stream.of(nodeToDirty)) - .filter(node -> node.state() != State.dirty) - .collect(Collectors.toList()); - - List<String> hostnamesNotAllowedToDirty = nodesToDirty.stream() - .filter(node -> node.state() != State.provisioned) - .filter(node -> node.state() != State.failed) - .filter(node -> node.state() != State.parked) - .filter(node -> node.state() != State.breakfixed) - .map(Node::hostname) - .collect(Collectors.toList()); - if ( ! hostnamesNotAllowedToDirty.isEmpty()) - illegal("Could not deallocate " + nodeToDirty + ": " + - hostnamesNotAllowedToDirty + " are not in states [provisioned, failed, parked, breakfixed]"); - - return nodesToDirty.stream().map(node -> deallocate(node, agent, reason)).collect(Collectors.toList()); - } - - /** - * Set a node dirty or parked, allowed if it is in the provisioned, inactive, failed or parked state. - * Use this to clean newly provisioned nodes or to recycle failed nodes which have been repaired or put on hold. - */ - public Node deallocate(Node node, Agent agent, String reason) { - NestedTransaction transaction = new NestedTransaction(); - Node deallocated = deallocate(node, agent, reason, transaction); - transaction.commit(); - return deallocated; - } - - public List<Node> deallocate(List<Node> nodes, Agent agent, String reason, NestedTransaction transaction) { - return nodes.stream().map(node -> deallocate(node, agent, reason, transaction)).collect(Collectors.toList()); - } - - public Node deallocate(Node node, Agent agent, String reason, NestedTransaction transaction) { - if (node.state() != State.parked && agent != Agent.operator - && (node.status().wantToDeprovision() || retiredByOperator(node))) - return park(node.hostname(), false, agent, reason, transaction); - else - return db.writeTo(State.dirty, List.of(node), agent, Optional.of(reason), transaction).get(0); - } - - private static boolean retiredByOperator(Node node) { - return node.status().wantToRetire() && node.history().event(History.Event.Type.wantToRetire) - .map(History.Event::agent) - .map(agent -> agent == Agent.operator) - .orElse(false); - } - - /** - * Fails this node and returns it in its new state. - * - * @return the node in its new state - * @throws NoSuchNodeException if the node is not found - */ - public Node fail(String hostname, Agent agent, String reason) { - return move(hostname, true, State.failed, agent, Optional.of(reason)); - } - - /** - * Fails all the nodes that are children of hostname before finally failing the hostname itself. - * - * @return List of all the failed nodes in their new state - */ - public List<Node> failRecursively(String hostname, Agent agent, String reason) { - return moveRecursively(hostname, State.failed, agent, Optional.of(reason)); - } - - /** - * Parks this node and returns it in its new state. - * - * @return the node in its new state - * @throws NoSuchNodeException if the node is not found - */ - public Node park(String hostname, boolean keepAllocation, Agent agent, String reason) { - NestedTransaction transaction = new NestedTransaction(); - Node parked = park(hostname, keepAllocation, agent, reason, transaction); - transaction.commit(); - return parked; - } - - public Node park(String hostname, boolean keepAllocation, Agent agent, String reason, NestedTransaction transaction) { - return move(hostname, keepAllocation, State.parked, agent, Optional.of(reason), transaction); - } - - /** - * Parks all the nodes that are children of hostname before finally parking the hostname itself. - * - * @return List of all the parked nodes in their new state - */ - public List<Node> parkRecursively(String hostname, Agent agent, String reason) { - return moveRecursively(hostname, State.parked, agent, Optional.of(reason)); - } - - /** - * Moves a previously failed or parked node back to the active state. - * - * @return the node in its new state - * @throws NoSuchNodeException if the node is not found - */ - public Node reactivate(String hostname, Agent agent, String reason) { - return move(hostname, true, State.active, agent, Optional.of(reason)); - } - - /** - * Moves a host to breakfixed state, removing any children. - */ - public List<Node> breakfixRecursively(String hostname, Agent agent, String reason) { - Node node = getNode(hostname).orElseThrow(() -> - new NoSuchNodeException("Could not breakfix " + hostname + ": Node not found")); - - try (Mutex lock = lockUnallocated()) { - requireBreakfixable(node); - List<Node> removed = removeChildren(node, false); - removed.add(move(node, State.breakfixed, agent, Optional.of(reason))); - return removed; - } - } - - private List<Node> moveRecursively(String hostname, State toState, Agent agent, Optional<String> reason) { - List<Node> moved = list().childrenOf(hostname).asList().stream() - .map(child -> move(child, toState, agent, reason)) - .collect(Collectors.toList()); - - moved.add(move(hostname, true, toState, agent, reason)); - return moved; - } - - private Node move(String hostname, boolean keepAllocation, State toState, Agent agent, Optional<String> reason) { - NestedTransaction transaction = new NestedTransaction(); - Node moved = move(hostname, keepAllocation, toState, agent, reason, transaction); - transaction.commit(); - return moved; - } - - private Node move(String hostname, boolean keepAllocation, State toState, Agent agent, Optional<String> reason, - NestedTransaction transaction) { - Node node = getNode(hostname).orElseThrow(() -> - new NoSuchNodeException("Could not move " + hostname + " to " + toState + ": Node not found")); - - if (!keepAllocation && node.allocation().isPresent()) { - node = node.withoutAllocation(); - } - - return move(node, toState, agent, reason, transaction); - } - - private Node move(Node node, State toState, Agent agent, Optional<String> reason) { - NestedTransaction transaction = new NestedTransaction(); - Node moved = move(node, toState, agent, reason, transaction); - transaction.commit(); - return moved; - } - - private Node move(Node node, State toState, Agent agent, Optional<String> reason, NestedTransaction transaction) { - if (toState == Node.State.active && node.allocation().isEmpty()) - illegal("Could not set " + node + " active. It has no allocation."); - - // TODO: Work out a safe lock acquisition strategy for moves, e.g. migrate to lockNode. - try (Mutex lock = lock(node)) { - if (toState == State.active) { - for (Node currentActive : getNodes(node.allocation().get().owner(), State.active)) { - if (node.allocation().get().membership().cluster().equals(currentActive.allocation().get().membership().cluster()) - && node.allocation().get().membership().index() == currentActive.allocation().get().membership().index()) - illegal("Could not set " + node + " active: Same cluster and index as " + currentActive); - } - } - return db.writeTo(toState, List.of(node), agent, reason, transaction).get(0); - } - } - - /* - * This method is used by the REST API to handle readying nodes for new allocations. For tenant docker - * containers this will remove the node from node repository, otherwise the node will be moved to state ready. - */ - public Node markNodeAvailableForNewAllocation(String hostname, Agent agent, String reason) { - Node node = getNode(hostname).orElseThrow(() -> new NotFoundException("No node with hostname '" + hostname + "'")); - if (node.flavor().getType() == Flavor.Type.DOCKER_CONTAINER && node.type() == NodeType.tenant) { - if (node.state() != State.dirty) - illegal("Cannot make " + node + " available for new allocation as it is not in state [dirty]"); - return removeRecursively(node, true).get(0); - } - - if (node.state() == State.ready) return node; - - Node parentHost = node.parentHostname().flatMap(this::getNode).orElse(node); - List<String> failureReasons = NodeFailer.reasonsToFailParentHost(parentHost); - if ( ! failureReasons.isEmpty()) - illegal(node + " cannot be readied because it has hard failures: " + failureReasons); - - return setReady(List.of(node), agent, reason).get(0); - } - - /** - * Removes all the nodes that are children of hostname before finally removing the hostname itself. - * - * @return a List of all the nodes that have been removed or (for hosts) deprovisioned - */ - public List<Node> removeRecursively(String hostname) { - Node node = getNode(hostname).orElseThrow(() -> new NotFoundException("No node with hostname '" + hostname + "'")); - return removeRecursively(node, false); - } - - public List<Node> removeRecursively(Node node, boolean force) { - try (Mutex lock = lockUnallocated()) { - requireRemovable(node, false, force); - - if (node.type().isHost()) { - List<Node> removed = removeChildren(node, force); - if (zone.getCloud().dynamicProvisioning() || node.type() != NodeType.host) - db.removeNodes(List.of(node)); - else { - node = node.with(IP.Config.EMPTY); - move(node, State.deprovisioned, Agent.system, Optional.empty()); - } - removed.add(node); - return removed; - } - else { - List<Node> removed = List.of(node); - db.removeNodes(removed); - return removed; - } - } - } - - /** Forgets a deprovisioned node. This removes all traces of the node in the node repository. */ - public void forget(Node node) { - if (node.state() != State.deprovisioned) - throw new IllegalArgumentException(node + " must be deprovisioned before it can be forgotten"); - db.removeNodes(List.of(node)); - } - - private List<Node> removeChildren(Node node, boolean force) { - List<Node> children = list().childrenOf(node).asList(); - children.forEach(child -> requireRemovable(child, true, force)); - db.removeNodes(children); - return new ArrayList<>(children); - } - - /** - * Throws if the given node cannot be removed. Removal is allowed if: - * - Tenant node: node is unallocated - * - Host node: iff in state provisioned|failed|parked - * - Child node: - * If only removing the container node: node in state ready - * If also removing the parent node: child is in state provisioned|failed|parked|dirty|ready - */ - private void requireRemovable(Node node, boolean removingAsChild, boolean force) { - if (force) return; - - if (node.type() == NodeType.tenant && node.allocation().isPresent()) - illegal(node + " is currently allocated and cannot be removed"); - - if (!node.type().isHost() && !removingAsChild) { - if (node.state() != State.ready) - illegal(node + " can not be removed as it is not in the state " + State.ready); - } - else if (!node.type().isHost()) { // removing a child node - Set<State> legalStates = EnumSet.of(State.provisioned, State.failed, State.parked, State.dirty, State.ready); - if ( ! legalStates.contains(node.state())) - illegal(node + " can not be removed as it is not in the states " + legalStates); - } - else { // a host - Set<State> legalStates = EnumSet.of(State.provisioned, State.failed, State.parked); - if (! legalStates.contains(node.state())) - illegal(node + " can not be removed as it is not in the states " + legalStates); - } - } - - /** - * Throws if given node cannot be breakfixed. - * Breakfix is allowed if the following is true: - * - Node is tenant host - * - Node is in zone without dynamic provisioning - * - Node is in parked or failed state - */ - private void requireBreakfixable(Node node) { - if (zone().getCloud().dynamicProvisioning()) { - illegal("Can not breakfix in zone: " + zone()); - } - - if (node.type() != NodeType.host) { - illegal(node + " can not be breakfixed as it is not a tenant host"); - } - - Set<State> legalStates = EnumSet.of(State.failed, State.parked); - if (! legalStates.contains(node.state())) { - illegal(node + " can not be removed as it is not in the states " + legalStates); - } - } - - /** - * Increases the restart generation of the active nodes matching the filter. - * - * @return the nodes in their new state - */ - public List<Node> restart(NodeFilter filter) { - return performOn(StateFilter.from(State.active, filter), - (node, lock) -> write(node.withRestart(node.allocation().get().restartGeneration().withIncreasedWanted()), - lock)); - } - - /** - * Increases the reboot generation of the nodes matching the filter. - * - * @return the nodes in their new state - */ - public List<Node> reboot(NodeFilter filter) { - return performOn(filter, (node, lock) -> write(node.withReboot(node.status().reboot().withIncreasedWanted()), lock)); - } - - /** - * Set target OS version of all nodes matching given filter. - * - * @return the nodes in their new state - */ - public List<Node> upgradeOs(NodeFilter filter, Optional<Version> version) { - return performOn(filter, (node, lock) -> { - var newStatus = node.status().withOsVersion(node.status().osVersion().withWanted(version)); - return write(node.with(newStatus), lock); - }); - } - - /** Retire nodes matching given filter */ - public List<Node> retire(NodeFilter filter, Agent agent, Instant instant) { - return performOn(filter, (node, lock) -> write(node.withWantToRetire(true, agent, instant), lock)); - } - - /** - * Writes this node after it has changed some internal state but NOT changed its state field. - * This does NOT lock the node repository implicitly, but callers are expected to already hold the lock. - * - * @param lock already acquired lock - * @return the written node for convenience - */ - public Node write(Node node, Mutex lock) { return write(List.of(node), lock).get(0); } - - /** - * Writes these nodes after they have changed some internal state but NOT changed their state field. - * This does NOT lock the node repository implicitly, but callers are expected to already hold the lock. - * - * @param lock already acquired lock - * @return the written nodes for convenience - */ - public List<Node> write(List<Node> nodes, @SuppressWarnings("unused") Mutex lock) { - return db.writeTo(nodes, Agent.system, Optional.empty()); - } - - /** - * Performs an operation requiring locking on all nodes matching some filter. - * - * @param filter the filter determining the set of nodes where the operation will be performed - * @param action the action to perform - * @return the set of nodes on which the action was performed, as they became as a result of the operation - */ - private List<Node> performOn(NodeFilter filter, BiFunction<Node, Mutex, Node> action) { - List<Node> unallocatedNodes = new ArrayList<>(); - ListMap<ApplicationId, Node> allocatedNodes = new ListMap<>(); - - // Group matching nodes by the lock needed - for (Node node : db.readNodes()) { - if ( ! filter.matches(node)) continue; - if (node.allocation().isPresent()) - allocatedNodes.put(node.allocation().get().owner(), node); - else - unallocatedNodes.add(node); - } - - // perform operation while holding locks - List<Node> resultingNodes = new ArrayList<>(); - try (Mutex lock = lockUnallocated()) { - for (Node node : unallocatedNodes) { - Optional<Node> currentNode = db.readNode(node.hostname()); // Re-read while holding lock - if (currentNode.isEmpty()) continue; - resultingNodes.add(action.apply(currentNode.get(), lock)); - } - } - for (Map.Entry<ApplicationId, List<Node>> applicationNodes : allocatedNodes.entrySet()) { - try (Mutex lock = lock(applicationNodes.getKey())) { - for (Node node : applicationNodes.getValue()) { - Optional<Node> currentNode = db.readNode(node.hostname()); // Re-read while holding lock - if (currentNode.isEmpty()) continue; - resultingNodes.add(action.apply(currentNode.get(), lock)); - } - } - } - return resultingNodes; - } - - public boolean canAllocateTenantNodeTo(Node host) { - return canAllocateTenantNodeTo(host, zone.getCloud().dynamicProvisioning()); - } - - public static boolean canAllocateTenantNodeTo(Node host, boolean dynamicProvisioning) { - if ( ! host.type().canRun(NodeType.tenant)) return false; - if (host.status().wantToRetire()) return false; - if (host.allocation().map(alloc -> alloc.membership().retired()).orElse(false)) return false; - - if (dynamicProvisioning) - return EnumSet.of(State.active, State.ready, State.provisioned).contains(host.state()); - else - return host.state() == State.active; - } - /** Returns the time keeper of this system */ public Clock clock() { return clock; } /** Returns the zone of this system */ public Zone zone() { return zone; } - /** Create a lock which provides exclusive rights to making changes to the given application */ - public Mutex lock(ApplicationId application) { - return db.lock(application); - } - - /** Create a lock with a timeout which provides exclusive rights to making changes to the given application */ - public Mutex lock(ApplicationId application, Duration timeout) { - return db.lock(application, timeout); - } - - /** Create a lock which provides exclusive rights to modifying unallocated nodes */ - public Mutex lockUnallocated() { return db.lockInactive(); } - - /** Returns the unallocated/application lock, and the node acquired under that lock. */ - public Optional<NodeMutex> lockAndGet(Node node) { - Node staleNode = node; - - final int maxRetries = 4; - for (int i = 0; i < maxRetries; ++i) { - Mutex lockToClose = lock(staleNode); - try { - // As an optimization we first try finding the node in the same state - Optional<Node> freshNode = getNode(staleNode.hostname(), staleNode.state()); - if (freshNode.isEmpty()) { - freshNode = getNode(staleNode.hostname()); - if (freshNode.isEmpty()) { - return Optional.empty(); - } - } - - if (Objects.equals(freshNode.get().allocation().map(Allocation::owner), - staleNode.allocation().map(Allocation::owner))) { - NodeMutex nodeMutex = new NodeMutex(freshNode.get(), lockToClose); - lockToClose = null; - return Optional.of(nodeMutex); - } - - // The wrong lock was held when the fresh node was fetched, so try again - staleNode = freshNode.get(); - } finally { - if (lockToClose != null) lockToClose.close(); - } - } - - throw new IllegalStateException("Giving up (after " + maxRetries + " attempts) " + - "fetching an up to date node under lock: " + node.hostname()); - } - - /** Returns the unallocated/application lock, and the node acquired under that lock. */ - public Optional<NodeMutex> lockAndGet(String hostname) { - return getNode(hostname).flatMap(this::lockAndGet); - } - - /** Returns the unallocated/application lock, and the node acquired under that lock. */ - public NodeMutex lockAndGetRequired(Node node) { - return lockAndGet(node).orElseThrow(() -> new IllegalArgumentException("No such node: " + node.hostname())); - } - - /** Returns the unallocated/application lock, and the node acquired under that lock. */ - public NodeMutex lockAndGetRequired(String hostname) { - return lockAndGet(hostname).orElseThrow(() -> new IllegalArgumentException("No such node: " + hostname)); - } - - private Mutex lock(Node node) { - return node.allocation().isPresent() ? lock(node.allocation().get().owner()) : lockUnallocated(); - } - - private void illegal(String message) { - throw new IllegalArgumentException(message); - } - } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocationOptimizer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocationOptimizer.java index 7064a7d2e6a..84634b26c4a 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocationOptimizer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocationOptimizer.java @@ -49,7 +49,7 @@ public class AllocationOptimizer { limits = atLeast(minimumNodes, limits); Optional<AllocatableClusterResources> bestAllocation = Optional.empty(); - NodeList hosts = nodeRepository.list().hosts(); + NodeList hosts = nodeRepository.nodes().list().hosts(); for (int groups = limits.min().groups(); groups <= limits.max().groups(); groups++) { for (int nodes = limits.min().nodes(); nodes <= limits.max().nodes(); nodes++) { if (nodes % groups != 0) continue; diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java index c4ff86a5390..81fa7ed2d4b 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java @@ -176,7 +176,7 @@ public class Autoscaler { return false; // A deployment is ongoing - if (nodeRepository.getNodes(nodes.first().get().allocation().get().owner(), Node.State.reserved).size() > 0) + if (nodeRepository.nodes().getNodes(nodes.first().get().allocation().get().owner(), Node.State.reserved).size() > 0) return false; return true; diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MemoryMetricsDb.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MemoryMetricsDb.java index 999acad7ab0..a881bde2a33 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MemoryMetricsDb.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MemoryMetricsDb.java @@ -75,7 +75,7 @@ public class MemoryMetricsDb implements MetricsDb { private void add(String hostname, MetricSnapshot snapshot) { NodeTimeseries timeseries = db.get(hostname); if (timeseries == null) { // new node - Optional<Node> node = nodeRepository.getNode(hostname); + Optional<Node> node = nodeRepository.nodes().getNode(hostname); if (node.isEmpty()) return; if (node.get().allocation().isEmpty()) return; timeseries = new NodeTimeseries(hostname, new ArrayList<>()); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcher.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcher.java index 961c1393550..b93c7930b5b 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcher.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcher.java @@ -51,7 +51,7 @@ public class MetricsV2MetricsFetcher extends AbstractComponent implements Metric @Override public CompletableFuture<MetricsResponse> fetchMetrics(ApplicationId application) { - NodeList applicationNodes = nodeRepository.list(application).state(Node.State.active); + NodeList applicationNodes = nodeRepository.nodes().list(application).state(Node.State.active); Optional<Node> metricsV2Container = applicationNodes.container() .matching(node -> expectedUp(node)) diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/SharedLoadBalancerService.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/SharedLoadBalancerService.java index 559dbe63cba..da5591e0800 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/SharedLoadBalancerService.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/SharedLoadBalancerService.java @@ -34,7 +34,7 @@ public class SharedLoadBalancerService implements LoadBalancerService { @Override public LoadBalancerInstance create(LoadBalancerSpec spec, boolean force) { - var proxyNodes = new ArrayList<>(nodeRepository.getNodes(NodeType.proxy)); + var proxyNodes = new ArrayList<>(nodeRepository.nodes().getNodes(NodeType.proxy)); proxyNodes.sort(hostnameComparator); if (proxyNodes.size() == 0) { diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java index 8eb92217356..1d2938742aa 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java @@ -52,7 +52,7 @@ public class AutoscalingMaintainer extends NodeRepositoryMaintainer { @Override protected boolean maintain() { - if ( ! nodeRepository().isWorking()) return false; + if ( ! nodeRepository().nodes().isWorking()) return false; boolean success = true; if ( ! nodeRepository().zone().environment().isProduction()) return success; diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DirtyExpirer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DirtyExpirer.java index 88bf3426ee0..22c8e49825d 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DirtyExpirer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DirtyExpirer.java @@ -30,7 +30,7 @@ public class DirtyExpirer extends Expirer { @Override protected void expire(List<Node> expired) { for (Node expiredNode : expired) - nodeRepository().fail(expiredNode.hostname(), Agent.DirtyExpirer, "Node is stuck in dirty"); + nodeRepository().nodes().fail(expiredNode.hostname(), Agent.DirtyExpirer, "Node is stuck in dirty"); } } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainer.java index 509b0e1352f..5e54f09f7a3 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainer.java @@ -28,6 +28,7 @@ import com.yahoo.vespa.hosted.provision.NodeRepository; import com.yahoo.vespa.hosted.provision.node.Agent; import com.yahoo.vespa.hosted.provision.node.History; import com.yahoo.vespa.hosted.provision.node.IP; +import com.yahoo.vespa.hosted.provision.node.Nodes; import com.yahoo.vespa.hosted.provision.provisioning.FatalProvisioningException; import com.yahoo.vespa.hosted.provision.provisioning.HostProvisioner; import com.yahoo.vespa.hosted.provision.provisioning.HostProvisioner.HostSharing; @@ -81,8 +82,8 @@ public class DynamicProvisioningMaintainer extends NodeRepositoryMaintainer { @Override protected boolean maintain() { - try (Mutex lock = nodeRepository().lockUnallocated()) { - NodeList nodes = nodeRepository().list(); + try (Mutex lock = nodeRepository().nodes().lockUnallocated()) { + NodeList nodes = nodeRepository().nodes().list(); resumeProvisioning(nodes, lock); convergeToCapacity(nodes); } @@ -102,7 +103,7 @@ public class DynamicProvisioningMaintainer extends NodeRepositoryMaintainer { try { List<Node> updatedNodes = hostProvisioner.provision(host, children); verifyDns(updatedNodes); - nodeRepository().write(updatedNodes, lock); + nodeRepository().nodes().write(updatedNodes, lock); } catch (IllegalArgumentException | IllegalStateException e) { log.log(Level.INFO, "Failed to provision " + host.hostname() + " with " + children.size() + " children: " + Exceptions.toMessageString(e)); @@ -110,7 +111,7 @@ public class DynamicProvisioningMaintainer extends NodeRepositoryMaintainer { log.log(Level.SEVERE, "Failed to provision " + host.hostname() + " with " + children.size() + " children, failing out the host recursively", e); // Fail out as operator to force a quick redeployment - nodeRepository().failRecursively( + nodeRepository().nodes().failRecursively( host.hostname(), Agent.operator, "Failed by HostProvisioner due to provisioning failure"); } catch (RuntimeException e) { if (e.getCause() instanceof NameNotFoundException) @@ -137,7 +138,7 @@ public class DynamicProvisioningMaintainer extends NodeRepositoryMaintainer { excessHosts.forEach(host -> { try { hostProvisioner.deprovision(host); - nodeRepository().removeRecursively(host, true); + nodeRepository().nodes().removeRecursively(host, true); } catch (RuntimeException e) { log.log(Level.WARNING, "Failed to deprovision " + host.hostname() + ", will retry in " + interval(), e); } @@ -199,7 +200,7 @@ public class DynamicProvisioningMaintainer extends NodeRepositoryMaintainer { private Map<String, Node> findSharedHosts(NodeList nodeList) { return nodeList.stream() - .filter(node -> NodeRepository.canAllocateTenantNodeTo(node, true)) + .filter(node -> Nodes.canAllocateTenantNodeTo(node, true)) .filter(node -> node.reservedTo().isEmpty()) .filter(node -> node.exclusiveTo().isEmpty()) .collect(Collectors.toMap(Node::hostname, Function.identity())); @@ -244,7 +245,7 @@ public class DynamicProvisioningMaintainer extends NodeRepositoryMaintainer { .stream() .map(ProvisionedHost::generateHost) .collect(Collectors.toList()); - nodeRepository().addNodes(hosts, Agent.DynamicProvisioningMaintainer); + nodeRepository().nodes().addNodes(hosts, Agent.DynamicProvisioningMaintainer); return hosts; } catch (OutOfCapacityException | IllegalArgumentException | IllegalStateException e) { throw new OutOfCapacityException("Failed to provision " + count + " " + nodeResources + ": " + e.getMessage()); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/Expirer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/Expirer.java index ba59ab02780..8ccb8980a71 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/Expirer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/Expirer.java @@ -41,7 +41,7 @@ public abstract class Expirer extends NodeRepositoryMaintainer { @Override protected boolean maintain() { - List<Node> expired = nodeRepository().getNodes(fromState).stream() + List<Node> expired = nodeRepository().nodes().getNodes(fromState).stream() .filter(this::isExpired) .collect(Collectors.toList()); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirer.java index 1a47af6b929..08edee0be8b 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirer.java @@ -68,7 +68,7 @@ public class FailedExpirer extends NodeRepositoryMaintainer { @Override protected boolean maintain() { - List<Node> remainingNodes = nodeRepository.getNodes(Node.State.failed).stream() + List<Node> remainingNodes = nodeRepository.nodes().getNodes(Node.State.failed).stream() .filter(node -> node.type() == NodeType.tenant || node.type() == NodeType.host) .collect(Collectors.toList()); @@ -95,14 +95,14 @@ public class FailedExpirer extends NodeRepositoryMaintainer { for (Node candidate : nodes) { if (NodeFailer.hasHardwareIssue(candidate, nodeRepository)) { List<String> unparkedChildren = !candidate.type().isHost() ? List.of() : - nodeRepository.list() + nodeRepository.nodes().list() .childrenOf(candidate) .matching(node -> node.state() != Node.State.parked) .mapToList(Node::hostname); if (unparkedChildren.isEmpty()) { - nodeRepository.park(candidate.hostname(), false, Agent.FailedExpirer, - "Parked by FailedExpirer due to hardware issue"); + nodeRepository.nodes().park(candidate.hostname(), false, Agent.FailedExpirer, + "Parked by FailedExpirer due to hardware issue"); } else { log.info(String.format("Expired failed node %s with hardware issue was not parked because of " + "unparked children: %s", candidate.hostname(), @@ -112,7 +112,7 @@ public class FailedExpirer extends NodeRepositoryMaintainer { nodesToRecycle.add(candidate); } } - nodeRepository.deallocate(nodesToRecycle, Agent.FailedExpirer, "Expired by FailedExpirer"); + nodeRepository.nodes().deallocate(nodesToRecycle, Agent.FailedExpirer, "Expired by FailedExpirer"); } /** Returns whether the current node fail count should be used as an indicator of hardware issue */ diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveExpirer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveExpirer.java index 231d2ac08b1..ae6e716bffe 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveExpirer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveExpirer.java @@ -39,7 +39,7 @@ public class InactiveExpirer extends Expirer { @Override protected void expire(List<Node> expired) { expired.forEach(node -> { - nodeRepository.deallocate(node, Agent.InactiveExpirer, "Expired by InactiveExpirer"); + nodeRepository.nodes().deallocate(node, Agent.InactiveExpirer, "Expired by InactiveExpirer"); }); } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirer.java index febdbbd4dc1..2ef12177eaf 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirer.java @@ -133,7 +133,7 @@ public class LoadBalancerExpirer extends NodeRepositoryMaintainer { } private List<Node> allocatedNodes(LoadBalancerId loadBalancer) { - return nodeRepository().list().owner(loadBalancer.application()).cluster(loadBalancer.cluster()).asList(); + return nodeRepository().nodes().list().owner(loadBalancer.application()).cluster(loadBalancer.cluster()).asList(); } } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceDeployment.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceDeployment.java index 52c487c28cf..e8f216c793a 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceDeployment.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceDeployment.java @@ -104,7 +104,7 @@ class MaintenanceDeployment implements Closeable { private Optional<Mutex> tryLock(ApplicationId application, NodeRepository nodeRepository) { try { // Use a short lock to avoid interfering with change deployments - return Optional.of(nodeRepository.lock(application, Duration.ofSeconds(1))); + return Optional.of(nodeRepository.nodes().lock(application, Duration.ofSeconds(1))); } catch (ApplicationLockException e) { return Optional.empty(); @@ -116,7 +116,7 @@ class MaintenanceDeployment implements Closeable { Deployer deployer, NodeRepository nodeRepository) { if (lock.isEmpty()) return Optional.empty(); - if (nodeRepository.getNodes(application, Node.State.active).isEmpty()) return Optional.empty(); + if (nodeRepository.nodes().getNodes(application, Node.State.active).isEmpty()) return Optional.empty(); return deployer.deployFromLocalActive(application); } @@ -168,7 +168,7 @@ class MaintenanceDeployment implements Closeable { if ( ! deployment.prepare()) return false; if (verifyTarget) { expectedNewNode = - nodeRepository.getNodes(application, Node.State.reserved).stream() + nodeRepository.nodes().getNodes(application, Node.State.reserved).stream() .filter(n -> !n.hostname().equals(node.hostname())) .filter(n -> n.allocation().get().membership().cluster().id().equals(node.allocation().get().membership().cluster().id())) .findAny(); @@ -185,15 +185,15 @@ class MaintenanceDeployment implements Closeable { markWantToRetire(node, false, agent, nodeRepository); // Necessary if this failed, no-op otherwise // Immediately clean up if we reserved the node but could not activate or reserved a node on the wrong host - expectedNewNode.flatMap(node -> nodeRepository.getNode(node.hostname(), Node.State.reserved)) - .ifPresent(node -> nodeRepository.deallocate(node, agent, "Expired by " + agent)); + expectedNewNode.flatMap(node -> nodeRepository.nodes().getNode(node.hostname(), Node.State.reserved)) + .ifPresent(node -> nodeRepository.nodes().deallocate(node, agent, "Expired by " + agent)); } } } /** Returns true only if this operation changes the state of the wantToRetire flag */ private boolean markWantToRetire(Node node, boolean wantToRetire, Agent agent, NodeRepository nodeRepository) { - Optional<NodeMutex> nodeMutex = nodeRepository.lockAndGet(node); + Optional<NodeMutex> nodeMutex = nodeRepository.nodes().lockAndGet(node); if (nodeMutex.isEmpty()) return false; try (var nodeLock = nodeMutex.get()) { @@ -201,7 +201,7 @@ class MaintenanceDeployment implements Closeable { if (nodeLock.node().status().wantToRetire() == wantToRetire) return false; - nodeRepository.write(nodeLock.node().withWantToRetire(wantToRetire, agent, nodeRepository.clock().instant()), nodeLock); + nodeRepository.nodes().write(nodeLock.node().withWantToRetire(wantToRetire, agent, nodeRepository.clock().instant()), nodeLock); return true; } } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporter.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporter.java index c14210bf5a7..9504a73f21e 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporter.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporter.java @@ -66,7 +66,7 @@ public class MetricsReporter extends NodeRepositoryMaintainer { @Override public boolean maintain() { - NodeList nodes = nodeRepository().list(); + NodeList nodes = nodeRepository().nodes().list(); ServiceModel serviceModel = serviceMonitor.getServiceModelSnapshot(); updateZoneMetrics(); @@ -126,7 +126,7 @@ public class MetricsReporter extends NodeRepositoryMaintainer { } private void updateZoneMetrics() { - metric.set("zone.working", nodeRepository().isWorking() ? 1 : 0, null); + metric.set("zone.working", nodeRepository().nodes().isWorking() ? 1 : 0, null); } private void updateCacheMetrics() { diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java index 2999655e5fa..7c3e3eb4553 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java @@ -75,13 +75,13 @@ public class NodeFailer extends NodeRepositoryMaintainer { @Override protected boolean maintain() { - if ( ! nodeRepository().isWorking()) return false; + if ( ! nodeRepository().nodes().isWorking()) return false; int throttledHostFailures = 0; int throttledNodeFailures = 0; // Ready nodes - try (Mutex lock = nodeRepository().lockUnallocated()) { + try (Mutex lock = nodeRepository().nodes().lockUnallocated()) { for (Map.Entry<Node, String> entry : getReadyNodesByFailureReason().entrySet()) { Node node = entry.getKey(); if (throttle(node)) { @@ -90,7 +90,7 @@ public class NodeFailer extends NodeRepositoryMaintainer { continue; } String reason = entry.getValue(); - nodeRepository().fail(node.hostname(), Agent.NodeFailer, reason); + nodeRepository().nodes().fail(node.hostname(), Agent.NodeFailer, reason); } } @@ -129,11 +129,11 @@ public class NodeFailer extends NodeRepositoryMaintainer { clock().instant().minus(downTimeLimit).minus(nodeRequestInterval); Map<Node, String> nodesByFailureReason = new HashMap<>(); - for (Node node : nodeRepository().getNodes(Node.State.ready)) { + for (Node node : nodeRepository().nodes().getNodes(Node.State.ready)) { if (expectConfigRequests(node) && ! hasNodeRequestedConfigAfter(node, oldestAcceptableRequestTime)) { nodesByFailureReason.put(node, "Not receiving config requests from node"); } else { - Node hostNode = node.parentHostname().flatMap(parent -> nodeRepository().getNode(parent)).orElse(node); + Node hostNode = node.parentHostname().flatMap(parent -> nodeRepository().nodes().getNode(parent)).orElse(node); List<String> failureReports = reasonsToFailParentHost(hostNode); if (failureReports.size() > 0) { if (hostNode.equals(node)) { @@ -148,7 +148,7 @@ public class NodeFailer extends NodeRepositoryMaintainer { } private Map<Node, String> getActiveNodesByFailureReason() { - List<Node> activeNodes = nodeRepository().getNodes(Node.State.active); + List<Node> activeNodes = nodeRepository().nodes().getNodes(Node.State.active); Instant graceTimeEnd = clock().instant().minus(downTimeLimit); Map<Node, String> nodesByFailureReason = new HashMap<>(); for (Node node : activeNodes) { @@ -158,7 +158,7 @@ public class NodeFailer extends NodeRepositoryMaintainer { nodesByFailureReason.put(node, "Node has been down longer than " + downTimeLimit); } else if (hostSuspended(node, activeNodes)) { - Node hostNode = node.parentHostname().flatMap(parent -> nodeRepository().getNode(parent)).orElse(node); + Node hostNode = node.parentHostname().flatMap(parent -> nodeRepository().nodes().getNode(parent)).orElse(node); if (hostNode.type().isHost()) { List<String> failureReports = reasonsToFailParentHost(hostNode); if (failureReports.size() > 0) { @@ -184,7 +184,7 @@ public class NodeFailer extends NodeRepositoryMaintainer { /** Returns whether node has any kind of hardware issue */ static boolean hasHardwareIssue(Node node, NodeRepository nodeRepository) { - Node hostNode = node.parentHostname().flatMap(parent -> nodeRepository.getNode(parent)).orElse(node); + Node hostNode = node.parentHostname().flatMap(parent -> nodeRepository.nodes().getNode(parent)).orElse(node); return reasonsToFailParentHost(hostNode).size() > 0; } @@ -246,7 +246,7 @@ public class NodeFailer extends NodeRepositoryMaintainer { return true; case proxy: case proxyhost: - return nodeRepository().getNodes(nodeType, Node.State.failed).size() == 0; + return nodeRepository().nodes().getNodes(nodeType, Node.State.failed).size() == 0; default: return false; } @@ -264,21 +264,21 @@ public class NodeFailer extends NodeRepositoryMaintainer { deployer.deployFromLocalActive(node.allocation().get().owner(), Duration.ofMinutes(30)); if (deployment.isEmpty()) return false; - try (Mutex lock = nodeRepository().lock(node.allocation().get().owner())) { + try (Mutex lock = nodeRepository().nodes().lock(node.allocation().get().owner())) { // If the active node that we are trying to fail is of type host, we need to successfully fail all // the children nodes running on it before we fail the host boolean allTenantNodesFailedOutSuccessfully = true; String reasonForChildFailure = "Failing due to parent host " + node.hostname() + " failure: " + reason; - for (Node failingTenantNode : nodeRepository().list().childrenOf(node)) { + for (Node failingTenantNode : nodeRepository().nodes().list().childrenOf(node)) { if (failingTenantNode.state() == Node.State.active) { allTenantNodesFailedOutSuccessfully &= failActive(failingTenantNode, reasonForChildFailure); } else { - nodeRepository().fail(failingTenantNode.hostname(), Agent.NodeFailer, reasonForChildFailure); + nodeRepository().nodes().fail(failingTenantNode.hostname(), Agent.NodeFailer, reasonForChildFailure); } } if (! allTenantNodesFailedOutSuccessfully) return false; - node = nodeRepository().fail(node.hostname(), Agent.NodeFailer, reason); + node = nodeRepository().nodes().fail(node.hostname(), Agent.NodeFailer, reason); try { deployment.get().activate(); return true; @@ -290,8 +290,8 @@ public class NodeFailer extends NodeRepositoryMaintainer { } catch (RuntimeException e) { // The expected reason for deployment to fail here is that there is no capacity available to redeploy. // In that case we should leave the node in the active state to avoid failing additional nodes. - nodeRepository().reactivate(node.hostname(), Agent.NodeFailer, - "Failed to redeploy after being failed by NodeFailer"); + nodeRepository().nodes().reactivate(node.hostname(), Agent.NodeFailer, + "Failed to redeploy after being failed by NodeFailer"); log.log(Level.WARNING, "Attempted to fail " + node + " for " + node.allocation().get().owner() + ", but redeploying without the node failed", e); return false; @@ -303,7 +303,7 @@ public class NodeFailer extends NodeRepositoryMaintainer { private boolean throttle(Node node) { if (throttlePolicy == ThrottlePolicy.disabled) return false; Instant startOfThrottleWindow = clock().instant().minus(throttlePolicy.throttleWindow); - List<Node> nodes = nodeRepository().getNodes(); + List<Node> nodes = nodeRepository().nodes().getNodes(); NodeList recentlyFailedNodes = nodes.stream() .filter(n -> n.state() == Node.State.failed) .filter(n -> n.history().hasEventAfter(History.Event.Type.failed, startOfThrottleWindow)) diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeHealthTracker.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeHealthTracker.java index 24af0d60cf6..92131a1cd74 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeHealthTracker.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeHealthTracker.java @@ -57,15 +57,15 @@ public class NodeHealthTracker extends NodeRepositoryMaintainer { private void updateReadyNodeLivenessEvents() { // Update node last request events through ZooKeeper to collect request to all config servers. // We do this here ("lazily") to avoid writing to zk for each config request. - try (Mutex lock = nodeRepository().lockUnallocated()) { - for (Node node : nodeRepository().getNodes(Node.State.ready)) { + try (Mutex lock = nodeRepository().nodes().lockUnallocated()) { + for (Node node : nodeRepository().nodes().getNodes(Node.State.ready)) { Optional<Instant> lastLocalRequest = hostLivenessTracker.lastRequestFrom(node.hostname()); if (lastLocalRequest.isEmpty()) continue; if (!node.history().hasEventAfter(History.Event.Type.requested, lastLocalRequest.get())) { History updatedHistory = node.history() .with(new History.Event(History.Event.Type.requested, Agent.NodeHealthTracker, lastLocalRequest.get())); - nodeRepository().write(node.with(updatedHistory), lock); + nodeRepository().nodes().write(node.with(updatedHistory), lock); } } } @@ -76,7 +76,7 @@ public class NodeHealthTracker extends NodeRepositoryMaintainer { * Otherwise we remove any "down" history record. */ private void updateActiveNodeDownState() { - NodeList activeNodes = nodeRepository().list(Node.State.active); + NodeList activeNodes = nodeRepository().nodes().list(Node.State.active); serviceMonitor.getServiceModelSnapshot().getServiceInstancesByHostName().forEach((hostname, serviceInstances) -> { Optional<Node> node = activeNodes.matching(n -> n.hostname().equals(hostname.toString())).first(); if (node.isEmpty()) return; @@ -87,7 +87,7 @@ public class NodeHealthTracker extends NodeRepositoryMaintainer { // Lock and update status ApplicationId owner = node.get().allocation().get().owner(); - try (var lock = nodeRepository().lock(owner)) { + try (var lock = nodeRepository().nodes().lock(owner)) { node = getNode(hostname.toString(), owner, lock); // Re-get inside lock if (node.isEmpty()) return; // Node disappeared or changed allocation if (isDown) { @@ -116,7 +116,7 @@ public class NodeHealthTracker extends NodeRepositoryMaintainer { /** Get node by given hostname and application. The applicationLock must be held when calling this */ private Optional<Node> getNode(String hostname, ApplicationId application, @SuppressWarnings("unused") Mutex applicationLock) { - return nodeRepository().getNode(hostname, Node.State.active) + return nodeRepository().nodes().getNode(hostname, Node.State.active) .filter(node -> node.allocation().isPresent()) .filter(node -> node.allocation().get().owner().equals(application)); } @@ -124,13 +124,13 @@ public class NodeHealthTracker extends NodeRepositoryMaintainer { /** Record a node as down if not already recorded */ private void recordAsDown(Node node, Mutex lock) { if (node.history().event(History.Event.Type.down).isPresent()) return; // already down: Don't change down timestamp - nodeRepository().write(node.downAt(clock().instant(), Agent.NodeHealthTracker), lock); + nodeRepository().nodes().write(node.downAt(clock().instant(), Agent.NodeHealthTracker), lock); } /** Clear down record for node, if any */ private void clearDownRecord(Node node, Mutex lock) { if (node.history().event(History.Event.Type.down).isEmpty()) return; - nodeRepository().write(node.up(), lock); + nodeRepository().nodes().write(node.up(), lock); } } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeMover.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeMover.java index 0ab5611327b..58711e14d7f 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeMover.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeMover.java @@ -44,7 +44,7 @@ public abstract class NodeMover<MOVE> extends NodeRepositoryMaintainer { ApplicationId applicationId = node.allocation().get().owner(); if (applicationId.instance().isTester()) continue; if (deployedRecently(applicationId)) continue; - for (Node toHost : allNodes.matching(nodeRepository()::canAllocateTenantNodeTo)) { + for (Node toHost : allNodes.matching(nodeRepository().nodes()::canAllocateTenantNodeTo)) { if (toHost.hostname().equals(node.parentHostname().get())) continue; if ( ! capacity.freeCapacityOf(toHost).satisfies(node.resources())) continue; diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooter.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooter.java index 96d10415e63..e2cafbb9406 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooter.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooter.java @@ -39,13 +39,13 @@ public class NodeRebooter extends NodeRepositoryMaintainer { @Override protected boolean maintain() { // Reboot candidates: Nodes in long-term states, where we know we can safely orchestrate a reboot - List<Node> nodesToReboot = nodeRepository().getNodes(Node.State.active, Node.State.ready).stream() + List<Node> nodesToReboot = nodeRepository().nodes().getNodes(Node.State.active, Node.State.ready).stream() .filter(node -> node.type().isHost()) .filter(this::shouldReboot) .collect(Collectors.toList()); if (!nodesToReboot.isEmpty()) - nodeRepository().reboot(NodeListFilter.from(nodesToReboot)); + nodeRepository().nodes().reboot(NodeListFilter.from(nodesToReboot)); return true; } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintainer.java index 6d93b54229f..e6338d73a17 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintainer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintainer.java @@ -42,7 +42,7 @@ public abstract class NodeRepositoryMaintainer extends Maintainer { /** A utility to group active tenant nodes by application */ protected Map<ApplicationId, List<Node>> activeNodesByApplication() { - return nodeRepository().list(Node.State.active) + return nodeRepository().nodes().list(Node.State.active) .nodeType(NodeType.tenant) .asList() .stream() diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/OperatorChangeApplicationMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/OperatorChangeApplicationMaintainer.java index b5933196ecc..49a33c4d120 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/OperatorChangeApplicationMaintainer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/OperatorChangeApplicationMaintainer.java @@ -38,7 +38,7 @@ public class OperatorChangeApplicationMaintainer extends ApplicationMaintainer { @Override protected Set<ApplicationId> applicationsNeedingMaintenance() { - Map<ApplicationId, List<Node>> nodesByApplication = nodeRepository().list() + Map<ApplicationId, List<Node>> nodesByApplication = nodeRepository().nodes().list() .nodeType(NodeType.tenant, NodeType.proxy).asList().stream() .filter(node -> node.allocation().isPresent()) .collect(Collectors.groupingBy(node -> node.allocation().get().owner(), Collectors.toList())); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/OsUpgradeActivator.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/OsUpgradeActivator.java index 68c1c98d8ba..3ff4ca89ad4 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/OsUpgradeActivator.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/OsUpgradeActivator.java @@ -34,7 +34,8 @@ public class OsUpgradeActivator extends NodeRepositoryMaintainer { /** Returns whether to allow OS upgrade of nodes of given type */ private boolean canUpgradeOsOf(NodeType type) { - return nodeRepository().list(Node.State.ready, Node.State.active) + return nodeRepository().nodes() + .list(Node.State.ready, Node.State.active) .nodeType(type) .changingVersion() .asList() diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainer.java index d20b06becaf..8253b3def0a 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainer.java @@ -76,7 +76,7 @@ public class PeriodicApplicationMaintainer extends ApplicationMaintainer { } protected List<Node> nodesNeedingMaintenance() { - return nodeRepository().getNodes(Node.State.active); + return nodeRepository().nodes().getNodes(Node.State.active); } } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ProvisionedExpirer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ProvisionedExpirer.java index 00cccab6f74..c5a2bc97ef2 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ProvisionedExpirer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ProvisionedExpirer.java @@ -24,7 +24,7 @@ public class ProvisionedExpirer extends Expirer { @Override protected void expire(List<Node> expired) { for (Node expiredNode : expired) - nodeRepository().parkRecursively(expiredNode.hostname(), Agent.ProvisionedExpirer, "Node is stuck in provisioned"); + nodeRepository().nodes().parkRecursively(expiredNode.hostname(), Agent.ProvisionedExpirer, "Node is stuck in provisioned"); } } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/Rebalancer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/Rebalancer.java index 1651c494f4a..88e64331c82 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/Rebalancer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/Rebalancer.java @@ -34,14 +34,14 @@ public class Rebalancer extends NodeMover<Rebalancer.Move> { @Override protected boolean maintain() { - if ( ! nodeRepository().isWorking()) return false; + if ( ! nodeRepository().nodes().isWorking()) return false; boolean success = true; if (nodeRepository().zone().getCloud().dynamicProvisioning()) return success; // Rebalancing not necessary if (nodeRepository().zone().environment().isTest()) return success; // Short lived deployments; no need to rebalance // Work with an unlocked snapshot as this can take a long time and full consistency is not needed - NodeList allNodes = nodeRepository().list(); + NodeList allNodes = nodeRepository().nodes().list(); updateSkewMetric(allNodes); if ( ! zoneIsStable(allNodes)) return success; findBestMove(allNodes).execute(true, Agent.Rebalancer, deployer, metric, nodeRepository()); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ReservationExpirer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ReservationExpirer.java index 1967615de02..e55e735bda6 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ReservationExpirer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ReservationExpirer.java @@ -25,6 +25,6 @@ public class ReservationExpirer extends Expirer { } @Override - protected void expire(List<Node> expired) { nodeRepository().deallocate(expired, Agent.ReservationExpirer, "Expired by ReservationExpirer"); } + protected void expire(List<Node> expired) { nodeRepository().nodes().deallocate(expired, Agent.ReservationExpirer, "Expired by ReservationExpirer"); } } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirer.java index abda7ed6120..337d25ca732 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirer.java @@ -45,7 +45,7 @@ public class RetiredExpirer extends NodeRepositoryMaintainer { @Override protected boolean maintain() { - List<Node> activeNodes = nodeRepository().getNodes(Node.State.active); + List<Node> activeNodes = nodeRepository().nodes().getNodes(Node.State.active); Map<ApplicationId, List<Node>> retiredNodesByApplication = activeNodes.stream() .filter(node -> node.allocation().isPresent()) @@ -62,7 +62,7 @@ public class RetiredExpirer extends NodeRepositoryMaintainer { List<Node> nodesToRemove = retiredNodes.stream().filter(this::canRemove).collect(Collectors.toList()); if (nodesToRemove.isEmpty()) continue; - nodeRepository().setRemovable(application, nodesToRemove); + nodeRepository().nodes().setRemovable(application, nodesToRemove); boolean success = deployment.activate().isPresent(); if ( ! success) return success; @@ -83,7 +83,7 @@ public class RetiredExpirer extends NodeRepositoryMaintainer { */ private boolean canRemove(Node node) { if (node.type().isHost()) { - if (nodeRepository() + if (nodeRepository().nodes() .list().childrenOf(node).asList().stream() .allMatch(child -> child.state() == Node.State.parked || child.state() == Node.State.failed)) { diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainer.java index 3bbebd7798d..4f7ab498599 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainer.java @@ -69,7 +69,7 @@ public class ScalingSuggestionsMaintainer extends NodeRepositoryMaintainer { var suggestion = autoscaler.suggest(cluster.get(), clusterNodes); if (suggestion.isEmpty()) return false; // Wait only a short time for the lock to avoid interfering with change deployments - try (Mutex lock = nodeRepository().lock(applicationId, Duration.ofSeconds(1))) { + try (Mutex lock = nodeRepository().nodes().lock(applicationId, Duration.ofSeconds(1))) { // empty suggested resources == keep the current allocation, so we record that var suggestedResources = suggestion.target().orElse(clusterNodes.not().retired().toResources()); applications().get(applicationId).ifPresent(a -> updateSuggestion(suggestedResources, clusterId, a, lock)); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SpareCapacityMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SpareCapacityMaintainer.java index ce2ab1dfa87..debc1484e58 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SpareCapacityMaintainer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SpareCapacityMaintainer.java @@ -67,13 +67,13 @@ public class SpareCapacityMaintainer extends NodeRepositoryMaintainer { @Override protected boolean maintain() { - if ( ! nodeRepository().isWorking()) return false; + if ( ! nodeRepository().nodes().isWorking()) return false; boolean success = true; // Don't need to maintain spare capacity in dynamically provisioned zones; can provision more on demand. if (nodeRepository().zone().getCloud().dynamicProvisioning()) return success; - NodeList allNodes = nodeRepository().list(); + NodeList allNodes = nodeRepository().nodes().list(); CapacityChecker capacityChecker = new CapacityChecker(allNodes); List<Node> overcommittedHosts = capacityChecker.findOvercommittedHosts(); @@ -116,7 +116,7 @@ public class SpareCapacityMaintainer extends NodeRepositoryMaintainer { if (nodeWhichCantMove.isEmpty()) return List.of(); Node node = nodeWhichCantMove.get(); - NodeList allNodes = nodeRepository().list(); + NodeList allNodes = nodeRepository().nodes().list(); // Allocation will assign the spareCount most empty nodes as "spares", which will not be allocated on // unless needed for node failing. Our goal here is to make room on these spares for the given node HostCapacity hostCapacity = new HostCapacity(allNodes, nodeRepository().resourcesCalculator()); @@ -165,11 +165,11 @@ public class SpareCapacityMaintainer extends NodeRepositoryMaintainer { try (MaintenanceDeployment deployment = new MaintenanceDeployment(application, deployer, metric, nodeRepository())) { if ( ! deployment.isValid()) return; // this will be done at another config server - Optional<Node> nodeWithWantToRetire = nodeRepository().getNode(nodeToRetire.get().hostname()) + Optional<Node> nodeWithWantToRetire = nodeRepository().nodes().getNode(nodeToRetire.get().hostname()) .map(node -> node.withWantToRetire(true, Agent.SpareCapacityMaintainer, nodeRepository().clock().instant())); if (nodeWithWantToRetire.isEmpty()) return; - nodeRepository().write(nodeWithWantToRetire.get(), deployment.applicationLock().get()); + nodeRepository().nodes().write(nodeWithWantToRetire.get(), deployment.applicationLock().get()); log.log(Level.INFO, String.format("Redeploying %s to relocate %s from overcommited host", application, nodeToRetire.get().hostname())); deployment.activate(); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SwitchRebalancer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SwitchRebalancer.java index e545b3d97ee..50e0116d98d 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SwitchRebalancer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SwitchRebalancer.java @@ -34,9 +34,9 @@ public class SwitchRebalancer extends NodeMover<Move> { @Override protected boolean maintain() { - if (!nodeRepository().isWorking()) return false; + if (!nodeRepository().nodes().isWorking()) return false; if (!nodeRepository().zone().environment().isProduction()) return true; - NodeList allNodes = nodeRepository().list(); // Lockless as strong consistency is not needed + NodeList allNodes = nodeRepository().nodes().list(); // Lockless as strong consistency is not needed if (!zoneIsStable(allNodes)) return true; findBestMove(allNodes).execute(false, Agent.SwitchRebalancer, deployer, metric, nodeRepository()); 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 new file mode 100644 index 00000000000..d61c6f38306 --- /dev/null +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java @@ -0,0 +1,739 @@ +// Copyright Verizon Media. 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.yahoo.collections.ListMap; +import com.yahoo.component.Version; +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.ApplicationTransaction; +import com.yahoo.config.provision.Flavor; +import com.yahoo.config.provision.NodeType; +import com.yahoo.config.provision.Zone; +import com.yahoo.transaction.Mutex; +import com.yahoo.transaction.NestedTransaction; +import com.yahoo.vespa.hosted.provision.LockedNodeList; +import com.yahoo.vespa.hosted.provision.NoSuchNodeException; +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.maintenance.NodeFailer; +import com.yahoo.vespa.hosted.provision.node.filter.NodeFilter; +import com.yahoo.vespa.hosted.provision.node.filter.NodeListFilter; +import com.yahoo.vespa.hosted.provision.node.filter.StateFilter; +import com.yahoo.vespa.hosted.provision.persistence.CuratorDatabaseClient; +import com.yahoo.vespa.hosted.provision.restapi.NotFoundException; + +import java.time.Clock; +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.BiFunction; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * The nodes in the node repo and their state transitions + * + * @author bratseth + */ +// Node state transitions: +// 1) (new) | deprovisioned - > provisioned -> (dirty ->) ready -> reserved -> active -> inactive -> dirty -> ready +// 2) inactive -> reserved | parked +// 3) reserved -> dirty +// 4) * -> failed | parked -> (breakfixed) -> dirty | active | deprovisioned +// 5) deprovisioned -> (forgotten) +// Nodes have an application assigned when in states reserved, active and inactive. +// Nodes might have an application assigned in dirty. +public class Nodes { + + private final Zone zone; + private final Clock clock; + private final CuratorDatabaseClient db; + + public Nodes(CuratorDatabaseClient db, Zone zone, Clock clock) { + this.zone = zone; + this.clock = clock; + this.db = db; + } + + // ---------------- Query API ---------------------------------------------------------------- + + /** + * Finds and returns the node with the hostname in any of the given states, or empty if not found + * + * @param hostname the full host name of the node + * @param inState the states the node may be in. If no states are given, it will be returned from any state + * @return the node, or empty if it was not found in any of the given states + */ + public Optional<Node> getNode(String hostname, Node.State... inState) { + return db.readNode(hostname, inState); + } + + /** + * Returns all nodes in any of the given states. + * + * @param inState the states to return nodes from. If no states are given, all nodes of the given type are returned + * @return the node, or empty if it was not found in any of the given states + */ + public List<Node> getNodes(Node.State... inState) { + return new ArrayList<>(db.readNodes(inState)); + } + /** + * Finds and returns the nodes of the given type in any of the given states. + * + * @param type the node type to return + * @param inState the states to return nodes from. If no states are given, all nodes of the given type are returned + * @return the node, or empty if it was not found in any of the given states + */ + public List<Node> getNodes(NodeType type, Node.State... inState) { + return db.readNodes(inState).stream().filter(node -> node.type().equals(type)).collect(Collectors.toList()); + } + + /** Returns a filterable list of nodes in this repository in any of the given states */ + public NodeList list(Node.State... inState) { + return NodeList.copyOf(getNodes(inState)); + } + + public NodeList list(ApplicationId application, Node.State... inState) { + return NodeList.copyOf(getNodes(application, inState)); + } + + /** Returns a filterable list of all nodes of an application */ + public NodeList list(ApplicationId application) { + return NodeList.copyOf(getNodes(application)); + } + + /** Returns a locked list of all nodes in this repository */ + public LockedNodeList list(Mutex lock) { + return new LockedNodeList(getNodes(), lock); + } + + public List<Node> getNodes(ApplicationId id, Node.State... inState) { return db.readNodes(id, inState); } + public List<Node> getInactive() { return db.readNodes(Node.State.inactive); } + public List<Node> getFailed() { return db.readNodes(Node.State.failed); } + + /** + * Returns whether the zone managed by this node repository seems to be working. + * If too many nodes are not responding, there is probably some zone-wide issue + * and we should probably refrain from making changes to it. + */ + public boolean isWorking() { + NodeList activeNodes = list(Node.State.active); + if (activeNodes.size() <= 5) return true; // Not enough data to decide + NodeList downNodes = activeNodes.down(); + return ! ( (double)downNodes.size() / (double)activeNodes.size() > 0.2 ); + } + + // ----------------- Node lifecycle ----------------------------------------------------------- + + /** Adds a list of newly created docker container nodes to the node repository as <i>reserved</i> nodes */ + public List<Node> addDockerNodes(LockedNodeList nodes) { + for (Node node : nodes) { + if ( ! node.flavor().getType().equals(Flavor.Type.DOCKER_CONTAINER)) + illegal("Cannot add " + node + ": This is not a docker node"); + if (node.allocation().isEmpty()) + illegal("Cannot add " + node + ": Docker containers needs to be allocated"); + Optional<Node> existing = getNode(node.hostname()); + if (existing.isPresent()) + illegal("Cannot add " + node + ": A node with this name already exists (" + + existing.get() + ", " + existing.get().history() + "). Node to be added: " + + node + ", " + node.history()); + } + return db.addNodesInState(nodes.asList(), Node.State.reserved, Agent.system); + } + + /** + * Adds a list of (newly created) nodes to the node repository as <i>provisioned</i> nodes. + * If any of the nodes already exists in the deprovisioned state, the new node will be merged + * with the history of that node. + */ + public List<Node> addNodes(List<Node> nodes, Agent agent) { + try (Mutex lock = lockUnallocated()) { + List<Node> nodesToAdd = new ArrayList<>(); + List<Node> nodesToRemove = new ArrayList<>(); + for (int i = 0; i < nodes.size(); i++) { + var node = nodes.get(i); + + // Check for duplicates + for (int j = 0; j < i; j++) { + if (node.equals(nodes.get(j))) + illegal("Cannot add nodes: " + node + " is duplicated in the argument list"); + } + + Optional<Node> existing = getNode(node.hostname()); + if (existing.isPresent()) { + if (existing.get().state() != Node.State.deprovisioned) + illegal("Cannot add " + node + ": A node with this name already exists"); + node = node.with(existing.get().history()); + node = node.with(existing.get().reports()); + node = node.with(node.status().withFailCount(existing.get().status().failCount())); + if (existing.get().status().firmwareVerifiedAt().isPresent()) + node = node.with(node.status().withFirmwareVerifiedAt(existing.get().status().firmwareVerifiedAt().get())); + nodesToRemove.add(existing.get()); + } + + nodesToAdd.add(node); + } + List<Node> resultingNodes = db.addNodesInState(IP.Config.verify(nodesToAdd, list(lock)), Node.State.provisioned, agent); + db.removeNodes(nodesToRemove); + return resultingNodes; + } + } + + /** Sets a list of nodes ready and returns the nodes in the ready state */ + public List<Node> setReady(List<Node> nodes, Agent agent, String reason) { + try (Mutex lock = lockUnallocated()) { + List<Node> nodesWithResetFields = nodes.stream() + .map(node -> { + if (node.state() != Node.State.provisioned && node.state() != Node.State.dirty) + illegal("Can not set " + node + " ready. It is not provisioned or dirty."); + if (node.type() == NodeType.host && node.ipConfig().pool().getIpSet().isEmpty()) + illegal("Can not set host " + node + " ready. Its IP address pool is empty."); + return node.withWantToRetire(false, false, Agent.system, clock.instant()); + }) + .collect(Collectors.toList()); + + return db.writeTo(Node.State.ready, nodesWithResetFields, agent, Optional.of(reason)); + } + } + + public Node setReady(String hostname, Agent agent, String reason) { + Node nodeToReady = getNode(hostname).orElseThrow(() -> + new NoSuchNodeException("Could not move " + hostname + " to ready: Node not found")); + + if (nodeToReady.state() == Node.State.ready) return nodeToReady; + return setReady(List.of(nodeToReady), agent, reason).get(0); + } + + /** Reserve nodes. This method does <b>not</b> lock the node repository */ + public List<Node> reserve(List<Node> nodes) { + return db.writeTo(Node.State.reserved, nodes, Agent.application, Optional.empty()); + } + + /** Activate nodes. This method does <b>not</b> lock the node repository */ + public List<Node> activate(List<Node> nodes, NestedTransaction transaction) { + return db.writeTo(Node.State.active, nodes, Agent.application, Optional.empty(), transaction); + } + + /** + * Sets a list of nodes to have their allocation removable (active to inactive) in the node repository. + * + * @param application the application the nodes belong to + * @param nodes the nodes to make removable. These nodes MUST be in the active state. + */ + public void setRemovable(ApplicationId application, List<Node> nodes) { + try (Mutex lock = lock(application)) { + List<Node> removableNodes = + nodes.stream().map(node -> node.with(node.allocation().get().removable(true))) + .collect(Collectors.toList()); + write(removableNodes, lock); + } + } + + /** + * Deactivates these nodes in a transaction and returns the nodes in the new state which will hold if the + * transaction commits. + */ + public List<Node> deactivate(List<Node> nodes, ApplicationTransaction transaction) { + var stateless = NodeList.copyOf(nodes).stateless(); + var stateful = NodeList.copyOf(nodes).stateful(); + List<Node> written = new ArrayList<>(); + written.addAll(deallocate(stateless.asList(), Agent.application, "Deactivated by application", transaction.nested())); + written.addAll(db.writeTo(Node.State.inactive, stateful.asList(), Agent.application, Optional.empty(), transaction.nested())); + return written; + + } + + /** Move nodes to the dirty state */ + public List<Node> deallocate(List<Node> nodes, Agent agent, String reason) { + return performOn(NodeListFilter.from(nodes), (node, lock) -> deallocate(node, agent, reason)); + } + + public List<Node> deallocateRecursively(String hostname, Agent agent, String reason) { + Node nodeToDirty = getNode(hostname).orElseThrow(() -> + new IllegalArgumentException("Could not deallocate " + hostname + ": Node not found")); + + List<Node> nodesToDirty = + (nodeToDirty.type().isHost() ? + Stream.concat(list().childrenOf(hostname).asList().stream(), Stream.of(nodeToDirty)) : + Stream.of(nodeToDirty)) + .filter(node -> node.state() != Node.State.dirty) + .collect(Collectors.toList()); + + List<String> hostnamesNotAllowedToDirty = nodesToDirty.stream() + .filter(node -> node.state() != Node.State.provisioned) + .filter(node -> node.state() != Node.State.failed) + .filter(node -> node.state() != Node.State.parked) + .filter(node -> node.state() != Node.State.breakfixed) + .map(Node::hostname) + .collect(Collectors.toList()); + if ( ! hostnamesNotAllowedToDirty.isEmpty()) + illegal("Could not deallocate " + nodeToDirty + ": " + + hostnamesNotAllowedToDirty + " are not in states [provisioned, failed, parked, breakfixed]"); + + return nodesToDirty.stream().map(node -> deallocate(node, agent, reason)).collect(Collectors.toList()); + } + + /** + * Set a node dirty or parked, allowed if it is in the provisioned, inactive, failed or parked state. + * Use this to clean newly provisioned nodes or to recycle failed nodes which have been repaired or put on hold. + */ + public Node deallocate(Node node, Agent agent, String reason) { + NestedTransaction transaction = new NestedTransaction(); + Node deallocated = deallocate(node, agent, reason, transaction); + transaction.commit(); + return deallocated; + } + + public List<Node> deallocate(List<Node> nodes, Agent agent, String reason, NestedTransaction transaction) { + return nodes.stream().map(node -> deallocate(node, agent, reason, transaction)).collect(Collectors.toList()); + } + + public Node deallocate(Node node, Agent agent, String reason, NestedTransaction transaction) { + if (node.state() != Node.State.parked && agent != Agent.operator + && (node.status().wantToDeprovision() || retiredByOperator(node))) + return park(node.hostname(), false, agent, reason, transaction); + else + return db.writeTo(Node.State.dirty, List.of(node), agent, Optional.of(reason), transaction).get(0); + } + + private static boolean retiredByOperator(Node node) { + return node.status().wantToRetire() && node.history().event(History.Event.Type.wantToRetire) + .map(History.Event::agent) + .map(agent -> agent == Agent.operator) + .orElse(false); + } + + /** + * Fails this node and returns it in its new state. + * + * @return the node in its new state + * @throws NoSuchNodeException if the node is not found + */ + public Node fail(String hostname, Agent agent, String reason) { + return move(hostname, true, Node.State.failed, agent, Optional.of(reason)); + } + + /** + * Fails all the nodes that are children of hostname before finally failing the hostname itself. + * + * @return List of all the failed nodes in their new state + */ + public List<Node> failRecursively(String hostname, Agent agent, String reason) { + return moveRecursively(hostname, Node.State.failed, agent, Optional.of(reason)); + } + + /** + * Parks this node and returns it in its new state. + * + * @return the node in its new state + * @throws NoSuchNodeException if the node is not found + */ + public Node park(String hostname, boolean keepAllocation, Agent agent, String reason) { + NestedTransaction transaction = new NestedTransaction(); + Node parked = park(hostname, keepAllocation, agent, reason, transaction); + transaction.commit(); + return parked; + } + + public Node park(String hostname, boolean keepAllocation, Agent agent, String reason, NestedTransaction transaction) { + return move(hostname, keepAllocation, Node.State.parked, agent, Optional.of(reason), transaction); + } + + /** + * Parks all the nodes that are children of hostname before finally parking the hostname itself. + * + * @return List of all the parked nodes in their new state + */ + public List<Node> parkRecursively(String hostname, Agent agent, String reason) { + return moveRecursively(hostname, Node.State.parked, agent, Optional.of(reason)); + } + + /** + * Moves a previously failed or parked node back to the active state. + * + * @return the node in its new state + * @throws NoSuchNodeException if the node is not found + */ + public Node reactivate(String hostname, Agent agent, String reason) { + return move(hostname, true, Node.State.active, agent, Optional.of(reason)); + } + + /** + * Moves a host to breakfixed state, removing any children. + */ + public List<Node> breakfixRecursively(String hostname, Agent agent, String reason) { + Node node = getNode(hostname).orElseThrow(() -> + new NoSuchNodeException("Could not breakfix " + hostname + ": Node not found")); + + try (Mutex lock = lockUnallocated()) { + requireBreakfixable(node); + List<Node> removed = removeChildren(node, false); + removed.add(move(node, Node.State.breakfixed, agent, Optional.of(reason))); + return removed; + } + } + + private List<Node> moveRecursively(String hostname, Node.State toState, Agent agent, Optional<String> reason) { + List<Node> moved = list().childrenOf(hostname).asList().stream() + .map(child -> move(child, toState, agent, reason)) + .collect(Collectors.toList()); + + moved.add(move(hostname, true, toState, agent, reason)); + return moved; + } + + private Node move(String hostname, boolean keepAllocation, Node.State toState, Agent agent, Optional<String> reason) { + NestedTransaction transaction = new NestedTransaction(); + Node moved = move(hostname, keepAllocation, toState, agent, reason, transaction); + transaction.commit(); + return moved; + } + + private Node move(String hostname, boolean keepAllocation, Node.State toState, Agent agent, Optional<String> reason, + NestedTransaction transaction) { + Node node = getNode(hostname).orElseThrow(() -> + new NoSuchNodeException("Could not move " + hostname + " to " + toState + ": Node not found")); + + if (!keepAllocation && node.allocation().isPresent()) { + node = node.withoutAllocation(); + } + + return move(node, toState, agent, reason, transaction); + } + + private Node move(Node node, Node.State toState, Agent agent, Optional<String> reason) { + NestedTransaction transaction = new NestedTransaction(); + Node moved = move(node, toState, agent, reason, transaction); + transaction.commit(); + return moved; + } + + private Node move(Node node, Node.State toState, Agent agent, Optional<String> reason, NestedTransaction transaction) { + if (toState == Node.State.active && node.allocation().isEmpty()) + illegal("Could not set " + node + " active. It has no allocation."); + + // TODO: Work out a safe lock acquisition strategy for moves, e.g. migrate to lockNode. + try (Mutex lock = lock(node)) { + if (toState == Node.State.active) { + for (Node currentActive : getNodes(node.allocation().get().owner(), Node.State.active)) { + if (node.allocation().get().membership().cluster().equals(currentActive.allocation().get().membership().cluster()) + && node.allocation().get().membership().index() == currentActive.allocation().get().membership().index()) + illegal("Could not set " + node + " active: Same cluster and index as " + currentActive); + } + } + return db.writeTo(toState, List.of(node), agent, reason, transaction).get(0); + } + } + + /* + * This method is used by the REST API to handle readying nodes for new allocations. For tenant docker + * containers this will remove the node from node repository, otherwise the node will be moved to state ready. + */ + public Node markNodeAvailableForNewAllocation(String hostname, Agent agent, String reason) { + Node node = getNode(hostname).orElseThrow(() -> new NotFoundException("No node with hostname '" + hostname + "'")); + if (node.flavor().getType() == Flavor.Type.DOCKER_CONTAINER && node.type() == NodeType.tenant) { + if (node.state() != Node.State.dirty) + illegal("Cannot make " + node + " available for new allocation as it is not in state [dirty]"); + return removeRecursively(node, true).get(0); + } + + if (node.state() == Node.State.ready) return node; + + Node parentHost = node.parentHostname().flatMap(this::getNode).orElse(node); + List<String> failureReasons = NodeFailer.reasonsToFailParentHost(parentHost); + if ( ! failureReasons.isEmpty()) + illegal(node + " cannot be readied because it has hard failures: " + failureReasons); + + return setReady(List.of(node), agent, reason).get(0); + } + + /** + * Removes all the nodes that are children of hostname before finally removing the hostname itself. + * + * @return a List of all the nodes that have been removed or (for hosts) deprovisioned + */ + public List<Node> removeRecursively(String hostname) { + Node node = getNode(hostname).orElseThrow(() -> new NotFoundException("No node with hostname '" + hostname + "'")); + return removeRecursively(node, false); + } + + public List<Node> removeRecursively(Node node, boolean force) { + try (Mutex lock = lockUnallocated()) { + requireRemovable(node, false, force); + + if (node.type().isHost()) { + List<Node> removed = removeChildren(node, force); + if (zone.getCloud().dynamicProvisioning() || node.type() != NodeType.host) + db.removeNodes(List.of(node)); + else { + node = node.with(IP.Config.EMPTY); + move(node, Node.State.deprovisioned, Agent.system, Optional.empty()); + } + removed.add(node); + return removed; + } + else { + List<Node> removed = List.of(node); + db.removeNodes(removed); + return removed; + } + } + } + + /** Forgets a deprovisioned node. This removes all traces of the node in the node repository. */ + public void forget(Node node) { + if (node.state() != Node.State.deprovisioned) + throw new IllegalArgumentException(node + " must be deprovisioned before it can be forgotten"); + db.removeNodes(List.of(node)); + } + + private List<Node> removeChildren(Node node, boolean force) { + List<Node> children = list().childrenOf(node).asList(); + children.forEach(child -> requireRemovable(child, true, force)); + db.removeNodes(children); + return new ArrayList<>(children); + } + + /** + * Throws if the given node cannot be removed. Removal is allowed if: + * - Tenant node: node is unallocated + * - Host node: iff in state provisioned|failed|parked + * - Child node: + * If only removing the container node: node in state ready + * If also removing the parent node: child is in state provisioned|failed|parked|dirty|ready + */ + private void requireRemovable(Node node, boolean removingAsChild, boolean force) { + if (force) return; + + if (node.type() == NodeType.tenant && node.allocation().isPresent()) + illegal(node + " is currently allocated and cannot be removed"); + + if (!node.type().isHost() && !removingAsChild) { + if (node.state() != Node.State.ready) + illegal(node + " can not be removed as it is not in the state " + Node.State.ready); + } + else if (!node.type().isHost()) { // removing a child node + Set<Node.State> legalStates = EnumSet.of(Node.State.provisioned, Node.State.failed, Node.State.parked, Node.State.dirty, Node.State.ready); + if ( ! legalStates.contains(node.state())) + illegal(node + " can not be removed as it is not in the states " + legalStates); + } + else { // a host + Set<Node.State> legalStates = EnumSet.of(Node.State.provisioned, Node.State.failed, Node.State.parked); + if (! legalStates.contains(node.state())) + illegal(node + " can not be removed as it is not in the states " + legalStates); + } + } + + /** + * Throws if given node cannot be breakfixed. + * Breakfix is allowed if the following is true: + * - Node is tenant host + * - Node is in zone without dynamic provisioning + * - Node is in parked or failed state + */ + private void requireBreakfixable(Node node) { + if (zone.getCloud().dynamicProvisioning()) { + illegal("Can not breakfix in zone: " + zone); + } + + if (node.type() != NodeType.host) { + illegal(node + " can not be breakfixed as it is not a tenant host"); + } + + Set<Node.State> legalStates = EnumSet.of(Node.State.failed, Node.State.parked); + if (! legalStates.contains(node.state())) { + illegal(node + " can not be removed as it is not in the states " + legalStates); + } + } + + /** + * Increases the restart generation of the active nodes matching the filter. + * + * @return the nodes in their new state + */ + public List<Node> restart(NodeFilter filter) { + return performOn(StateFilter.from(Node.State.active, filter), + (node, lock) -> write(node.withRestart(node.allocation().get().restartGeneration().withIncreasedWanted()), + lock)); + } + + /** + * Increases the reboot generation of the nodes matching the filter. + * + * @return the nodes in their new state + */ + public List<Node> reboot(NodeFilter filter) { + return performOn(filter, (node, lock) -> write(node.withReboot(node.status().reboot().withIncreasedWanted()), lock)); + } + + /** + * Set target OS version of all nodes matching given filter. + * + * @return the nodes in their new state + */ + public List<Node> upgradeOs(NodeFilter filter, Optional<Version> version) { + return performOn(filter, (node, lock) -> { + var newStatus = node.status().withOsVersion(node.status().osVersion().withWanted(version)); + return write(node.with(newStatus), lock); + }); + } + + /** Retire nodes matching given filter */ + public List<Node> retire(NodeFilter filter, Agent agent, Instant instant) { + return performOn(filter, (node, lock) -> write(node.withWantToRetire(true, agent, instant), lock)); + } + + /** + * Writes this node after it has changed some internal state but NOT changed its state field. + * This does NOT lock the node repository implicitly, but callers are expected to already hold the lock. + * + * @param lock already acquired lock + * @return the written node for convenience + */ + public Node write(Node node, Mutex lock) { return write(List.of(node), lock).get(0); } + + /** + * Writes these nodes after they have changed some internal state but NOT changed their state field. + * This does NOT lock the node repository implicitly, but callers are expected to already hold the lock. + * + * @param lock already acquired lock + * @return the written nodes for convenience + */ + public List<Node> write(List<Node> nodes, @SuppressWarnings("unused") Mutex lock) { + return db.writeTo(nodes, Agent.system, Optional.empty()); + } + + /** + * Performs an operation requiring locking on all nodes matching some filter. + * + * @param filter the filter determining the set of nodes where the operation will be performed + * @param action the action to perform + * @return the set of nodes on which the action was performed, as they became as a result of the operation + */ + private List<Node> performOn(NodeFilter filter, BiFunction<Node, Mutex, Node> action) { + List<Node> unallocatedNodes = new ArrayList<>(); + ListMap<ApplicationId, Node> allocatedNodes = new ListMap<>(); + + // Group matching nodes by the lock needed + for (Node node : db.readNodes()) { + if ( ! filter.matches(node)) continue; + if (node.allocation().isPresent()) + allocatedNodes.put(node.allocation().get().owner(), node); + else + unallocatedNodes.add(node); + } + + // perform operation while holding locks + List<Node> resultingNodes = new ArrayList<>(); + try (Mutex lock = lockUnallocated()) { + for (Node node : unallocatedNodes) { + Optional<Node> currentNode = db.readNode(node.hostname()); // Re-read while holding lock + if (currentNode.isEmpty()) continue; + resultingNodes.add(action.apply(currentNode.get(), lock)); + } + } + for (Map.Entry<ApplicationId, List<Node>> applicationNodes : allocatedNodes.entrySet()) { + try (Mutex lock = lock(applicationNodes.getKey())) { + for (Node node : applicationNodes.getValue()) { + Optional<Node> currentNode = db.readNode(node.hostname()); // Re-read while holding lock + if (currentNode.isEmpty()) continue; + resultingNodes.add(action.apply(currentNode.get(), lock)); + } + } + } + return resultingNodes; + } + + public boolean canAllocateTenantNodeTo(Node host) { + return canAllocateTenantNodeTo(host, zone.getCloud().dynamicProvisioning()); + } + + public static boolean canAllocateTenantNodeTo(Node host, boolean dynamicProvisioning) { + if ( ! host.type().canRun(NodeType.tenant)) return false; + if (host.status().wantToRetire()) return false; + if (host.allocation().map(alloc -> alloc.membership().retired()).orElse(false)) return false; + + if (dynamicProvisioning) + return EnumSet.of(Node.State.active, Node.State.ready, Node.State.provisioned).contains(host.state()); + else + return host.state() == Node.State.active; + } + + /** Create a lock which provides exclusive rights to making changes to the given application */ + public Mutex lock(ApplicationId application) { + return db.lock(application); + } + + /** Create a lock with a timeout which provides exclusive rights to making changes to the given application */ + public Mutex lock(ApplicationId application, Duration timeout) { + return db.lock(application, timeout); + } + + /** Create a lock which provides exclusive rights to modifying unallocated nodes */ + public Mutex lockUnallocated() { return db.lockInactive(); } + + /** Returns the unallocated/application lock, and the node acquired under that lock. */ + public Optional<NodeMutex> lockAndGet(Node node) { + Node staleNode = node; + + final int maxRetries = 4; + for (int i = 0; i < maxRetries; ++i) { + Mutex lockToClose = lock(staleNode); + try { + // As an optimization we first try finding the node in the same state + Optional<Node> freshNode = getNode(staleNode.hostname(), staleNode.state()); + if (freshNode.isEmpty()) { + freshNode = getNode(staleNode.hostname()); + if (freshNode.isEmpty()) { + return Optional.empty(); + } + } + + if (Objects.equals(freshNode.get().allocation().map(Allocation::owner), + staleNode.allocation().map(Allocation::owner))) { + NodeMutex nodeMutex = new NodeMutex(freshNode.get(), lockToClose); + lockToClose = null; + return Optional.of(nodeMutex); + } + + // The wrong lock was held when the fresh node was fetched, so try again + staleNode = freshNode.get(); + } finally { + if (lockToClose != null) lockToClose.close(); + } + } + + throw new IllegalStateException("Giving up (after " + maxRetries + " attempts) " + + "fetching an up to date node under lock: " + node.hostname()); + } + + /** Returns the unallocated/application lock, and the node acquired under that lock. */ + public Optional<NodeMutex> lockAndGet(String hostname) { + return getNode(hostname).flatMap(this::lockAndGet); + } + + /** Returns the unallocated/application lock, and the node acquired under that lock. */ + public NodeMutex lockAndGetRequired(Node node) { + return lockAndGet(node).orElseThrow(() -> new IllegalArgumentException("No such node: " + node.hostname())); + } + + /** Returns the unallocated/application lock, and the node acquired under that lock. */ + public NodeMutex lockAndGetRequired(String hostname) { + return lockAndGet(hostname).orElseThrow(() -> new IllegalArgumentException("No such node: " + hostname)); + } + + private Mutex lock(Node node) { + return node.allocation().isPresent() ? lock(node.allocation().get().owner()) : lockUnallocated(); + } + + private void illegal(String message) { + throw new IllegalArgumentException(message); + } + +} diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/DelegatingUpgrader.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/DelegatingUpgrader.java index 74b288d77c5..5410cb06269 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/DelegatingUpgrader.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/DelegatingUpgrader.java @@ -35,7 +35,7 @@ public class DelegatingUpgrader implements Upgrader { @Override public void upgradeTo(OsVersionTarget target) { - NodeList activeNodes = nodeRepository.list().nodeType(target.nodeType()).state(Node.State.active); + NodeList activeNodes = nodeRepository.nodes().list().nodeType(target.nodeType()).state(Node.State.active); int numberToUpgrade = Math.max(0, maxActiveUpgrades - activeNodes.changingOsVersionTo(target.version()).size()); NodeList nodesToUpgrade = activeNodes.not().changingOsVersionTo(target.version()) .osVersionIsBefore(target.version()) @@ -44,17 +44,17 @@ public class DelegatingUpgrader implements Upgrader { if (nodesToUpgrade.size() == 0) return; LOG.info("Upgrading " + nodesToUpgrade.size() + " nodes of type " + target.nodeType() + " to OS version " + target.version().toFullString()); - nodeRepository.upgradeOs(NodeListFilter.from(nodesToUpgrade.asList()), Optional.of(target.version())); + nodeRepository.nodes().upgradeOs(NodeListFilter.from(nodesToUpgrade.asList()), Optional.of(target.version())); } @Override public void disableUpgrade(NodeType type) { - NodeList nodesUpgrading = nodeRepository.list() + NodeList nodesUpgrading = nodeRepository.nodes().list() .nodeType(type) .changingOsVersion(); if (nodesUpgrading.size() == 0) return; LOG.info("Disabling OS upgrade of all " + type + " nodes"); - nodeRepository.upgradeOs(NodeListFilter.from(nodesUpgrading.asList()), Optional.empty()); + nodeRepository.nodes().upgradeOs(NodeListFilter.from(nodesUpgrading.asList()), Optional.empty()); } } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/RetiringUpgrader.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/RetiringUpgrader.java index 68ac96fdf1d..8615488b92f 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/RetiringUpgrader.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/RetiringUpgrader.java @@ -35,7 +35,7 @@ public class RetiringUpgrader implements Upgrader { @Override public void upgradeTo(OsVersionTarget target) { - NodeList allNodes = nodeRepository.list(); + NodeList allNodes = nodeRepository.nodes().list(); NodeList activeNodes = allNodes.state(Node.State.active).nodeType(target.nodeType()); if (activeNodes.size() == 0) return; // No nodes eligible for upgrade @@ -62,7 +62,7 @@ public class RetiringUpgrader implements Upgrader { /** Retire and deprovision given host and its children */ private void retire(Node host, Version target, Instant now, NodeList allNodes) { if (!host.type().isHost()) throw new IllegalArgumentException("Cannot retire non-host " + host); - Optional<NodeMutex> nodeMutex = nodeRepository.lockAndGet(host); + Optional<NodeMutex> nodeMutex = nodeRepository.nodes().lockAndGet(host); if (nodeMutex.isEmpty()) return; try (var lock = nodeMutex.get()) { host = lock.node(); @@ -72,10 +72,10 @@ public class RetiringUpgrader implements Upgrader { host.status().osVersion().current().map(Version::toFullString).orElse("<unset>") + ", want " + target); NodeList children = allNodes.childrenOf(host); - nodeRepository.retire(NodeListFilter.from(children.asList()), Agent.RetiringUpgrader, now); + nodeRepository.nodes().retire(NodeListFilter.from(children.asList()), Agent.RetiringUpgrader, now); host = host.withWantToRetire(true, true, Agent.RetiringUpgrader, now); host = host.with(host.status().withOsVersion(host.status().osVersion().withWanted(Optional.of(target)))); - nodeRepository.write(host, lock); + nodeRepository.nodes().write(host, lock); nodeRepository.osVersions().writeChange((change) -> change.withRetirementAt(now, nodeType)); } } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Activator.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Activator.java index 2ec3912181b..cad9faacf20 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Activator.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Activator.java @@ -64,7 +64,7 @@ class Activator { Instant activationTime = nodeRepository.clock().instant(); // Use one timestamp for all activation changes ApplicationId application = transaction.application(); Set<String> hostnames = hosts.stream().map(HostSpec::hostname).collect(Collectors.toSet()); - NodeList allNodes = nodeRepository.list(); + NodeList allNodes = nodeRepository.nodes().list(); NodeList applicationNodes = allNodes.owner(application); List<Node> reserved = applicationNodes.state(Node.State.reserved).asList(); @@ -86,8 +86,8 @@ class Activator { List<Node> activeToRemove = removeHostsFromList(hostnames, oldActive); activeToRemove = activeToRemove.stream().map(Node::unretire).collect(Collectors.toList()); // only active nodes can be retired. TODO: Move this line to deactivate - nodeRepository.deactivate(activeToRemove, transaction); // TODO: Pass activation time in this call and next line - nodeRepository.activate(newActive, transaction.nested()); // activate also continued active to update node state + nodeRepository.nodes().deactivate(activeToRemove, transaction); // TODO: Pass activation time in this call and next line + nodeRepository.nodes().activate(newActive, transaction.nested()); // activate also continued active to update node state rememberResourceChange(transaction, generation, activationTime, NodeList.copyOf(oldActive).not().retired(), @@ -126,16 +126,16 @@ class Activator { private void unreserveParentsOf(List<Node> nodes) { for (Node node : nodes) { if ( node.parentHostname().isEmpty()) continue; - Optional<Node> parentNode = nodeRepository.getNode(node.parentHostname().get()); + Optional<Node> parentNode = nodeRepository.nodes().getNode(node.parentHostname().get()); if (parentNode.isEmpty()) continue; if (parentNode.get().reservedTo().isEmpty()) continue; // Above is an optimization to avoid unnecessary locking - now repeat all conditions under lock - Optional<NodeMutex> parent = nodeRepository.lockAndGet(node.parentHostname().get()); + Optional<NodeMutex> parent = nodeRepository.nodes().lockAndGet(node.parentHostname().get()); if (parent.isEmpty()) continue; try (var lock = parent.get()) { if (lock.node().reservedTo().isEmpty()) continue; - nodeRepository.write(lock.node().withoutReservedTo(), lock); + nodeRepository.nodes().write(lock.node().withoutReservedTo(), lock); } } } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java index d9ca0100402..cd381b467d4 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java @@ -81,8 +81,8 @@ public class GroupPreparer { } // There were some changes, so re-do the allocation with locks - try (Mutex lock = nodeRepository.lock(application); - Mutex allocationLock = nodeRepository.lockUnallocated()) { + try (Mutex lock = nodeRepository.nodes().lock(application); + Mutex allocationLock = nodeRepository.nodes().lockUnallocated()) { NodeAllocation allocation = prepareAllocation(application, cluster, requestedNodes, surplusActiveNodes, highestIndex, wantedGroups, allocationLock, @@ -109,7 +109,7 @@ public class GroupPreparer { List<Node> hosts = provisionedHosts.stream() .map(ProvisionedHost::generateHost) .collect(Collectors.toList()); - nodeRepository.addNodes(hosts, Agent.application); + nodeRepository.nodes().addNodes(hosts, Agent.application); // Offer the nodes on the newly provisioned hosts, this should be enough to cover the deficit List<NodeCandidate> candidates = provisionedHosts.stream() @@ -124,8 +124,8 @@ public class GroupPreparer { allocation.outOfCapacityDetails()); // Carry out and return allocation - nodeRepository.reserve(allocation.reservableNodes()); - nodeRepository.addDockerNodes(new LockedNodeList(allocation.newNodes(), allocationLock)); + nodeRepository.nodes().reserve(allocation.reservableNodes()); + nodeRepository.nodes().addDockerNodes(new LockedNodeList(allocation.newNodes(), allocationLock)); List<Node> acceptedNodes = allocation.finalNodes(); surplusActiveNodes.removeAll(acceptedNodes); return acceptedNodes; @@ -135,7 +135,7 @@ public class GroupPreparer { private NodeAllocation prepareAllocation(ApplicationId application, ClusterSpec cluster, NodeSpec requestedNodes, List<Node> surplusActiveNodes, MutableInteger highestIndex, int wantedGroups, Mutex allocationLock, String allocateOsRequirement) { - LockedNodeList allNodes = nodeRepository.list(allocationLock); + LockedNodeList allNodes = nodeRepository.nodes().list(allocationLock); NodeAllocation allocation = new NodeAllocation(allNodes, application, cluster, requestedNodes, highestIndex, nodeRepository); NodePrioritizer prioritizer = new NodePrioritizer( diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/InfraDeployerImpl.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/InfraDeployerImpl.java index d81d16fe62e..1b98514e3a8 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/InfraDeployerImpl.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/InfraDeployerImpl.java @@ -89,7 +89,7 @@ public class InfraDeployerImpl implements InfraDeployer { public void prepare() { if (prepared) return; - try (Mutex lock = nodeRepository.lock(application.getApplicationId())) { + try (Mutex lock = nodeRepository.nodes().lock(application.getApplicationId())) { NodeType nodeType = application.getCapacity().type(); Version targetVersion = infrastructureVersions.getTargetVersionFor(nodeType); hostSpecs = provisioner.prepare(application.getApplicationId(), diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisioner.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisioner.java index 356b27dfe2c..156d1023bbc 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisioner.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisioner.java @@ -210,7 +210,7 @@ public class LoadBalancerProvisioner { /** Returns the load balanced clusters of given application and their nodes */ private Map<ClusterSpec.Id, List<Node>> loadBalancedClustersOf(ApplicationId application) { - NodeList nodes = NodeList.copyOf(nodeRepository.getNodes(Node.State.reserved, Node.State.active)) + NodeList nodes = NodeList.copyOf(nodeRepository.nodes().getNodes(Node.State.reserved, Node.State.active)) .owner(application); if (nodes.stream().anyMatch(node -> node.type() == NodeType.config)) { nodes = nodes.nodeType(NodeType.config).type(ClusterSpec.Type.admin); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java index a8db081dbfd..9578e43609b 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java @@ -9,6 +9,7 @@ import com.yahoo.vespa.hosted.provision.LockedNodeList; 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.Nodes; import com.yahoo.vespa.hosted.provision.persistence.NameResolver; import java.util.ArrayList; @@ -136,7 +137,7 @@ public class NodePrioritizer { if ( !canAllocateNew) return; for (Node host : allNodes) { - if ( ! NodeRepository.canAllocateTenantNodeTo(host, dynamicProvisioning)) continue; + if ( ! Nodes.canAllocateTenantNodeTo(host, dynamicProvisioning)) continue; if (host.reservedTo().isPresent() && !host.reservedTo().get().equals(application.tenant())) continue; if (host.reservedTo().isPresent() && application.instance().isTester()) continue; if (host.exclusiveTo().isPresent()) continue; // Never allocate new nodes to exclusive hosts @@ -221,7 +222,7 @@ public class NodePrioritizer { if (node.type() != NodeType.tenant || node.parentHostname().isEmpty()) return true; Optional<Node> parent = allNodes.parentOf(node); if (parent.isEmpty()) return false; - return NodeRepository.canAllocateTenantNodeTo(parent.get(), dynamicProvisioning); + return Nodes.canAllocateTenantNodeTo(parent.get(), dynamicProvisioning); } } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java index 05c20ee69f1..825ea82e95c 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java @@ -118,7 +118,7 @@ public class NodeRepositoryProvisioner implements Provisioner { @Override public void restart(ApplicationId application, HostFilter filter) { - nodeRepository.restart(ApplicationFilter.from(application, NodeHostFilter.from(filter))); + nodeRepository.nodes().restart(ApplicationFilter.from(application, NodeHostFilter.from(filter))); } @Override @@ -129,7 +129,7 @@ public class NodeRepositoryProvisioner implements Provisioner { @Override public ProvisionLock lock(ApplicationId application) { - return new ProvisionLock(application, nodeRepository.lock(application)); + return new ProvisionLock(application, nodeRepository.nodes().lock(application)); } /** @@ -137,7 +137,7 @@ public class NodeRepositoryProvisioner implements Provisioner { * and updates the application store with the received min and max. */ private ClusterResources decideTargetResources(ApplicationId applicationId, ClusterSpec clusterSpec, Capacity requested) { - try (Mutex lock = nodeRepository.lock(applicationId)) { + try (Mutex lock = nodeRepository.nodes().lock(applicationId)) { Application application = nodeRepository.applications().get(applicationId).orElse(new Application(applicationId)); application = application.withCluster(clusterSpec.id(), clusterSpec.isExclusive(), requested.minResources(), requested.maxResources()); nodeRepository.applications().put(application, lock); @@ -150,7 +150,7 @@ public class NodeRepositoryProvisioner implements Provisioner { private ClusterResources currentResources(ApplicationId applicationId, ClusterSpec clusterSpec, Capacity requested) { - List<Node> nodes = NodeList.copyOf(nodeRepository.getNodes(applicationId, Node.State.active)) + List<Node> nodes = NodeList.copyOf(nodeRepository.nodes().getNodes(applicationId, Node.State.active)) .cluster(clusterSpec.id()) .not().retired() .not().removable() diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Preparer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Preparer.java index 6597c64a399..18ab9b70491 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Preparer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Preparer.java @@ -85,7 +85,7 @@ class Preparer { */ private List<Node> findNodesInRemovableGroups(ApplicationId application, ClusterSpec requestedCluster, int wantedGroups) { List<Node> surplusNodes = new ArrayList<>(0); - for (Node node : nodeRepository.getNodes(application, Node.State.active)) { + for (Node node : nodeRepository.nodes().getNodes(application, Node.State.active)) { ClusterSpec nodeCluster = node.allocation().get().membership().cluster(); if ( ! nodeCluster.id().equals(requestedCluster.id())) continue; if ( ! nodeCluster.type().equals(requestedCluster.type())) continue; @@ -127,7 +127,7 @@ class Preparer { */ private int findHighestIndex(ApplicationId application, ClusterSpec cluster) { int highestIndex = -1; - for (Node node : nodeRepository.getNodes(application, Node.State.allocatedStates().toArray(new Node.State[0]))) { + for (Node node : nodeRepository.nodes().getNodes(application, Node.State.allocatedStates().toArray(new Node.State[0]))) { ClusterSpec nodeCluster = node.allocation().get().membership().cluster(); if ( ! nodeCluster.id().equals(cluster.id())) continue; if ( ! nodeCluster.type().equals(cluster.type())) continue; diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/HostCapacityResponse.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/HostCapacityResponse.java index 219fdaf9663..3c06533b8f5 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/HostCapacityResponse.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/HostCapacityResponse.java @@ -28,7 +28,7 @@ public class HostCapacityResponse extends HttpResponse { public HostCapacityResponse(NodeRepository nodeRepository, HttpRequest request) { super(200); - capacityChecker = new CapacityChecker(nodeRepository.list()); + capacityChecker = new CapacityChecker(nodeRepository.nodes().list()); json = request.getBooleanProperty("json"); String hostsJson = request.getProperty("hosts"); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodeAclResponse.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodeAclResponse.java index 2d2feccc114..708a2f73ee6 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodeAclResponse.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodeAclResponse.java @@ -39,11 +39,11 @@ public class NodeAclResponse extends HttpResponse { } private void toSlime(String hostname, Cursor object) { - Node node = nodeRepository.getNode(hostname) + Node node = nodeRepository.nodes().getNode(hostname) .orElseThrow(() -> new NotFoundException("No node with hostname '" + hostname + "'")); List<NodeAcl> acls = aclsForChildren ? nodeRepository.getChildAcls(node) : - List.of(node.acl(nodeRepository.list(), nodeRepository.loadBalancers())); + List.of(node.acl(nodeRepository.nodes().list(), nodeRepository.loadBalancers())); Cursor trustedNodesArray = object.setArray("trustedNodes"); acls.forEach(nodeAcl -> toSlime(nodeAcl, trustedNodesArray)); 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 47b0021874d..ea951798da0 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 @@ -73,9 +73,9 @@ public class NodePatcher implements AutoCloseable { throw new UncheckedIOException("Error reading request body", e); } - this.patchedNodes = new PatchedNodes(nodeRepository.lockAndGetRequired(node)); + this.patchedNodes = new PatchedNodes(nodeRepository.nodes().lockAndGetRequired(node)); try { - this.memoizedNodes = Suppliers.memoize(() -> nodeRepository.list(patchedNodes.nodeMutex())); + this.memoizedNodes = Suppliers.memoize(() -> nodeRepository.nodes().list(patchedNodes.nodeMutex())); } catch (RuntimeException e) { patchedNodes.close(); throw e; @@ -312,7 +312,7 @@ public class NodePatcher implements AutoCloseable { if (!fetchedChildren) { memoizedNodes.get() .childrenOf(hostname) - .forEach(node -> nodeRepository.lockAndGet(node) + .forEach(node -> nodeRepository.nodes().lockAndGet(node) .ifPresent(nodeMutex -> nodes.put(nodeMutex.node().hostname(), nodeMutex))); fetchedChildren = true; } 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 e12952062b8..e71902f908b 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 @@ -110,13 +110,13 @@ class NodesResponse extends HttpResponse { private void nodesToSlime(Node.State state, Cursor parentObject) { Cursor nodeArray = parentObject.setArray("nodes"); for (NodeType type : NodeType.values()) - toSlime(nodeRepository.getNodes(type, state), nodeArray); + toSlime(nodeRepository.nodes().getNodes(type, state), nodeArray); } /** Outputs all the nodes to a node array */ private void nodesToSlime(Cursor parentObject) { Cursor nodeArray = parentObject.setArray("nodes"); - toSlime(nodeRepository.getNodes(), nodeArray); + toSlime(nodeRepository.nodes().getNodes(), nodeArray); } private void toSlime(List<Node> nodes, Cursor array) { @@ -127,7 +127,7 @@ class NodesResponse extends HttpResponse { } private void nodeToSlime(String hostname, Cursor object) { - Node node = nodeRepository.getNode(hostname).orElseThrow(() -> + Node node = nodeRepository.nodes().getNode(hostname).orElseThrow(() -> new NotFoundException("No node with hostname '" + hostname + "'")); toSlime(node, true, 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 08bfd104863..a6a58b6a9dd 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 @@ -130,27 +130,27 @@ public class NodesV2ApiHandler extends LoggingRequestHandler { // Check paths to disallow illegal state changes if (path.startsWith("/nodes/v2/state/ready/") || path.startsWith("/nodes/v2/state/availablefornewallocations/")) { - nodeRepository.markNodeAvailableForNewAllocation(lastElement(path), Agent.operator, "Readied through the nodes/v2 API"); + nodeRepository.nodes().markNodeAvailableForNewAllocation(lastElement(path), Agent.operator, "Readied through the nodes/v2 API"); return new MessageResponse("Moved " + lastElement(path) + " to ready"); } else if (path.startsWith("/nodes/v2/state/failed/")) { - List<Node> failedNodes = nodeRepository.failRecursively(lastElement(path), Agent.operator, "Failed through the nodes/v2 API"); + List<Node> failedNodes = nodeRepository.nodes().failRecursively(lastElement(path), Agent.operator, "Failed through the nodes/v2 API"); return new MessageResponse("Moved " + hostnamesAsString(failedNodes) + " to failed"); } else if (path.startsWith("/nodes/v2/state/parked/")) { - List<Node> parkedNodes = nodeRepository.parkRecursively(lastElement(path), Agent.operator, "Parked through the nodes/v2 API"); + List<Node> parkedNodes = nodeRepository.nodes().parkRecursively(lastElement(path), Agent.operator, "Parked through the nodes/v2 API"); return new MessageResponse("Moved " + hostnamesAsString(parkedNodes) + " to parked"); } else if (path.startsWith("/nodes/v2/state/dirty/")) { - List<Node> dirtiedNodes = nodeRepository.deallocateRecursively(lastElement(path), Agent.operator, "Dirtied through the nodes/v2 API"); + List<Node> dirtiedNodes = nodeRepository.nodes().deallocateRecursively(lastElement(path), Agent.operator, "Dirtied through the nodes/v2 API"); return new MessageResponse("Moved " + hostnamesAsString(dirtiedNodes) + " to dirty"); } else if (path.startsWith("/nodes/v2/state/active/")) { - nodeRepository.reactivate(lastElement(path), Agent.operator, "Reactivated through nodes/v2 API"); + nodeRepository.nodes().reactivate(lastElement(path), Agent.operator, "Reactivated through nodes/v2 API"); return new MessageResponse("Moved " + lastElement(path) + " to active"); } else if (path.startsWith("/nodes/v2/state/breakfixed/")) { - List<Node> breakfixedNodes = nodeRepository.breakfixRecursively(lastElement(path), Agent.operator, "Breakfixed through the nodes/v2 API"); + List<Node> breakfixedNodes = nodeRepository.nodes().breakfixRecursively(lastElement(path), Agent.operator, "Breakfixed through the nodes/v2 API"); return new MessageResponse("Breakfixed " + hostnamesAsString(breakfixedNodes)); } @@ -162,7 +162,7 @@ public class NodesV2ApiHandler extends LoggingRequestHandler { if (path.startsWith("/nodes/v2/node/")) { try (NodePatcher patcher = new NodePatcher(nodeFlavors, request.getData(), nodeFromRequest(request), nodeRepository)) { var patchedNodes = patcher.apply(); - nodeRepository.write(patchedNodes, patcher.nodeMutexOfHost()); + nodeRepository.nodes().write(patchedNodes, patcher.nodeMutexOfHost()); return new MessageResponse("Updated " + patcher.nodeMutexOfHost().node().hostname()); } @@ -177,11 +177,11 @@ public class NodesV2ApiHandler extends LoggingRequestHandler { private HttpResponse handlePOST(HttpRequest request) { Path path = new Path(request.getUri()); if (path.matches("/nodes/v2/command/restart")) { - int restartCount = nodeRepository.restart(toNodeFilter(request)).size(); + int restartCount = nodeRepository.nodes().restart(toNodeFilter(request)).size(); return new MessageResponse("Scheduled restart of " + restartCount + " matching nodes"); } if (path.matches("/nodes/v2/command/reboot")) { - int rebootCount = nodeRepository.reboot(toNodeFilter(request)).size(); + int rebootCount = nodeRepository.nodes().reboot(toNodeFilter(request)).size(); return new MessageResponse("Scheduled reboot of " + rebootCount + " matching nodes"); } if (path.matches("/nodes/v2/node")) { @@ -208,14 +208,14 @@ public class NodesV2ApiHandler extends LoggingRequestHandler { } private HttpResponse deleteNode(String hostname) { - Optional<NodeMutex> nodeMutex = nodeRepository.lockAndGet(hostname); + Optional<NodeMutex> nodeMutex = nodeRepository.nodes().lockAndGet(hostname); if (nodeMutex.isEmpty()) throw new NotFoundException("No node with hostname '" + hostname + "'"); try (var lock = nodeMutex.get()) { if (lock.node().state() == Node.State.deprovisioned) { - nodeRepository.forget(lock.node()); + nodeRepository.nodes().forget(lock.node()); return new MessageResponse("Permanently removed " + hostname); } else { - List<Node> removedNodes = nodeRepository.removeRecursively(hostname); + List<Node> removedNodes = nodeRepository.nodes().removeRecursively(hostname); return new MessageResponse("Removed " + removedNodes.stream().map(Node::hostname).collect(Collectors.joining(", "))); } } @@ -223,13 +223,13 @@ public class NodesV2ApiHandler extends LoggingRequestHandler { private Node nodeFromRequest(HttpRequest request) { String hostname = lastElement(request.getUri().getPath()); - return nodeRepository.getNode(hostname).orElseThrow(() -> + return nodeRepository.nodes().getNode(hostname).orElseThrow(() -> new NotFoundException("No node found with hostname " + hostname)); } public int addNodes(InputStream jsonStream) { List<Node> nodes = createNodesFromSlime(toSlime(jsonStream).get()); - return nodeRepository.addNodes(nodes, Agent.operator).size(); + return nodeRepository.nodes().addNodes(nodes, Agent.operator).size(); } private Slime toSlime(InputStream jsonStream) { @@ -435,7 +435,7 @@ public class NodesV2ApiHandler extends LoggingRequestHandler { if (application.isEmpty()) return ErrorResponse.notFoundError("No application '" + id + "'"); Slime slime = ApplicationSerializer.toSlime(application.get(), - nodeRepository.getNodes(id, Node.State.active), + nodeRepository.nodes().getNodes(id, Node.State.active), withPath("/nodes/v2/applications/" + id, uri)); return new SlimeJsonResponse(slime); } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockDeployer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockDeployer.java index 9461cb00c5f..c31ebbb2c11 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockDeployer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockDeployer.java @@ -195,9 +195,9 @@ public class MockDeployer implements Deployer { public long activate() { lastDeployTimes.put(applicationId, clock.instant()); - for (Node node : nodeRepository.list().owner(applicationId).state(Node.State.active).wantToRetire().asList()) { - try (NodeMutex lock = nodeRepository.lockAndGetRequired(node)) { - nodeRepository.write(lock.node().retire(nodeRepository.clock().instant()), lock); + for (Node node : nodeRepository.nodes().list().owner(applicationId).state(Node.State.active).wantToRetire().asList()) { + try (NodeMutex lock = nodeRepository.nodes().lockAndGetRequired(node)) { + nodeRepository.nodes().write(lock.node().retire(nodeRepository.clock().instant()), lock); } } return redeployments++; diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java index cf1ccf9a052..f6649b44c0b 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java @@ -139,17 +139,17 @@ public class MockNodeRepository extends NodeRepository { nodes.add(Node.create("cfg2", ipConfig(202), "cfg2.yahoo.com", flavors.getFlavorOrThrow("default"), NodeType.config).build()); // Ready all nodes, except 7 and 55 - nodes = addNodes(nodes, Agent.system); + nodes = nodes().addNodes(nodes, Agent.system); nodes.remove(node7); nodes.remove(node55); - nodes = deallocate(nodes, Agent.system, getClass().getSimpleName()); - setReady(nodes, Agent.system, getClass().getSimpleName()); + nodes = nodes().deallocate(nodes, Agent.system, getClass().getSimpleName()); + nodes().setReady(nodes, Agent.system, getClass().getSimpleName()); - fail(node5.hostname(), Agent.system, getClass().getSimpleName()); - deallocateRecursively(node55.hostname(), Agent.system, getClass().getSimpleName()); + nodes().fail(node5.hostname(), Agent.system, getClass().getSimpleName()); + nodes().deallocateRecursively(node55.hostname(), Agent.system, getClass().getSimpleName()); - fail("dockerhost6.yahoo.com", Agent.operator, getClass().getSimpleName()); - removeRecursively("dockerhost6.yahoo.com"); + nodes().fail("dockerhost6.yahoo.com", Agent.operator, getClass().getSimpleName()); + nodes().removeRecursively("dockerhost6.yahoo.com"); ApplicationId zoneApp = ApplicationId.from(TenantName.from("zoneapp"), ApplicationName.from("zoneapp"), InstanceName.from("zoneapp")); ClusterSpec zoneCluster = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("node-admin")).vespaVersion("6.42").build(); @@ -169,7 +169,7 @@ public class MockNodeRepository extends NodeRepository { clock().instant()))); cluster1 = cluster1.withTarget(Optional.of(new ClusterResources(4, 1, new NodeResources(3, 16, 100, 1)))); - try (Mutex lock = lock(app1Id)) { + try (Mutex lock = nodes().lock(app1Id)) { applications().put(app1.with(cluster1), lock); } @@ -184,8 +184,8 @@ public class MockNodeRepository extends NodeRepository { List<Node> largeNodes = new ArrayList<>(); largeNodes.add(Node.create("node13", ipConfig(13), "host13.yahoo.com", resources(10, 48, 500, 1, fast, local), NodeType.tenant).build()); largeNodes.add(Node.create("node14", ipConfig(14), "host14.yahoo.com", resources(10, 48, 500, 1, fast, local), NodeType.tenant).build()); - addNodes(largeNodes, Agent.system); - setReady(largeNodes, Agent.system, getClass().getSimpleName()); + nodes().addNodes(largeNodes, Agent.system); + nodes().setReady(largeNodes, Agent.system, getClass().getSimpleName()); ApplicationId app4 = ApplicationId.from(TenantName.from("tenant4"), ApplicationName.from("application4"), InstanceName.from("instance4")); ClusterSpec cluster4 = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("id4")).vespaVersion("6.42").build(); activate(provisioner.prepare(app4, cluster4, Capacity.from(new ClusterResources(2, 1, new NodeResources(10, 48, 500, 1)), false, true), null), app4, provisioner); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/ServiceMonitorStub.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/ServiceMonitorStub.java index e18f5adb257..ce30baa3862 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/ServiceMonitorStub.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/ServiceMonitorStub.java @@ -70,7 +70,7 @@ public class ServiceMonitorStub implements ServiceMonitor { Map<ApplicationInstanceReference, ApplicationInstance> status = new HashMap<>(); for (Map.Entry<ApplicationId, MockDeployer.ApplicationContext> app : apps.entrySet()) { Set<ServiceInstance> serviceInstances = new HashSet<>(); - for (Node node : nodeRepository.getNodes(app.getValue().id(), Node.State.active)) { + for (Node node : nodeRepository.nodes().getNodes(app.getValue().id(), Node.State.active)) { serviceInstances.add(new ServiceInstance(new ConfigId("configid"), new HostName(node.hostname()), getHostStatus(node.hostname()))); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTest.java index 5f357b9e4b0..0617884d227 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTest.java @@ -32,19 +32,19 @@ public class NodeRepositoryTest { @Test public void add_and_remove() { NodeRepositoryTester tester = new NodeRepositoryTester(); - assertEquals(0, tester.nodeRepository().getNodes().size()); + assertEquals(0, tester.nodeRepository().nodes().getNodes().size()); tester.addHost("id1", "host1", "default", NodeType.host); tester.addHost("id2", "host2", "default", NodeType.host); tester.addHost("id3", "host3", "default", NodeType.host); - assertEquals(3, tester.nodeRepository().getNodes().size()); + assertEquals(3, tester.nodeRepository().nodes().getNodes().size()); - tester.nodeRepository().park("host2", true, Agent.system, "Parking to unit test"); - tester.nodeRepository().removeRecursively("host2"); + tester.nodeRepository().nodes().park("host2", true, Agent.system, "Parking to unit test"); + tester.nodeRepository().nodes().removeRecursively("host2"); - assertEquals(3, tester.nodeRepository().getNodes().size()); - assertEquals(1, tester.nodeRepository().getNodes(Node.State.deprovisioned).size()); + assertEquals(3, tester.nodeRepository().nodes().getNodes().size()); + assertEquals(1, tester.nodeRepository().nodes().getNodes(Node.State.deprovisioned).size()); } @Test @@ -53,14 +53,14 @@ public class NodeRepositoryTest { tester.addHost("id1", "host1", "docker", NodeType.tenant); try { - tester.nodeRepository().removeRecursively("host1"); // host1 is in state provisioned + tester.nodeRepository().nodes().removeRecursively("host1"); // host1 is in state provisioned fail("Should not be able to delete docker container node by itself in state provisioned"); } catch (IllegalArgumentException ignored) { // Expected } - tester.nodeRepository().setReady("host1", Agent.system, getClass().getSimpleName()); - tester.nodeRepository().removeRecursively("host1"); + tester.nodeRepository().nodes().setReady("host1", Agent.system, getClass().getSimpleName()); + tester.nodeRepository().nodes().removeRecursively("host1"); } @Test @@ -74,14 +74,14 @@ public class NodeRepositoryTest { tester.setNodeState("host2", Node.State.dirty); tester.setNodeState("cfg1", Node.State.dirty); - tester.nodeRepository().markNodeAvailableForNewAllocation("host1", Agent.system, getClass().getSimpleName()); - assertEquals(Node.State.ready, tester.nodeRepository().getNode("host1").get().state()); + tester.nodeRepository().nodes().markNodeAvailableForNewAllocation("host1", Agent.system, getClass().getSimpleName()); + assertEquals(Node.State.ready, tester.nodeRepository().nodes().getNode("host1").get().state()); - tester.nodeRepository().markNodeAvailableForNewAllocation("host2", Agent.system, getClass().getSimpleName()); - assertFalse(tester.nodeRepository().getNode("host2").isPresent()); + tester.nodeRepository().nodes().markNodeAvailableForNewAllocation("host2", Agent.system, getClass().getSimpleName()); + assertFalse(tester.nodeRepository().nodes().getNode("host2").isPresent()); - tester.nodeRepository().markNodeAvailableForNewAllocation("cfg1", Agent.system, getClass().getSimpleName()); - assertEquals(Node.State.ready, tester.nodeRepository().getNode("cfg1").get().state()); + tester.nodeRepository().nodes().markNodeAvailableForNewAllocation("cfg1", Agent.system, getClass().getSimpleName()); + assertEquals(Node.State.ready, tester.nodeRepository().nodes().getNode("cfg1").get().state()); } @Test @@ -92,17 +92,17 @@ public class NodeRepositoryTest { tester.setNodeState("host1", Node.State.dirty); tester.setNodeState("host2", Node.State.dirty); - Node node2 = tester.nodeRepository().getNode("host2").orElseThrow(); + Node node2 = tester.nodeRepository().nodes().getNode("host2").orElseThrow(); var reportsBuilder = new Reports.Builder(node2.reports()); reportsBuilder.setReport(Report.basicReport("reportId", Report.Type.HARD_FAIL, Instant.EPOCH, "hardware failure")); node2 = node2.with(reportsBuilder.build()); - tester.nodeRepository().write(node2, () -> {}); + tester.nodeRepository().nodes().write(node2, () -> {}); - tester.nodeRepository().markNodeAvailableForNewAllocation("host1", Agent.system, getClass().getSimpleName()); - assertEquals(Node.State.ready, tester.nodeRepository().getNode("host1").get().state()); + tester.nodeRepository().nodes().markNodeAvailableForNewAllocation("host1", Agent.system, getClass().getSimpleName()); + assertEquals(Node.State.ready, tester.nodeRepository().nodes().getNode("host1").get().state()); try { - tester.nodeRepository().markNodeAvailableForNewAllocation("host2", Agent.system, getClass().getSimpleName()); + tester.nodeRepository().nodes().markNodeAvailableForNewAllocation("host2", Agent.system, getClass().getSimpleName()); fail(); } catch (IllegalArgumentException e) { assertTrue(e.getMessage().contains("hardware failure")); @@ -120,29 +120,29 @@ public class NodeRepositoryTest { tester.addNode("node12", "node12", "host1", "docker", NodeType.tenant); tester.addNode("node20", "node20", "host2", "docker", NodeType.tenant); tester.setNodeState("node11", Node.State.active); - assertEquals(6, tester.nodeRepository().getNodes().size()); + assertEquals(6, tester.nodeRepository().nodes().getNodes().size()); try { - tester.nodeRepository().removeRecursively("host1"); + tester.nodeRepository().nodes().removeRecursively("host1"); fail("Should not be able to delete host node, one of the children is in state active"); } catch (IllegalArgumentException ignored) { // Expected } - assertEquals(6, tester.nodeRepository().getNodes().size()); + assertEquals(6, tester.nodeRepository().nodes().getNodes().size()); // Should be OK to delete host2 as both host2 and its only child, node20, are in state provisioned - tester.nodeRepository().removeRecursively("host2"); - assertEquals(5, tester.nodeRepository().getNodes().size()); - assertEquals(Node.State.deprovisioned, tester.nodeRepository().getNode("host2").get().state()); + tester.nodeRepository().nodes().removeRecursively("host2"); + assertEquals(5, tester.nodeRepository().nodes().getNodes().size()); + assertEquals(Node.State.deprovisioned, tester.nodeRepository().nodes().getNode("host2").get().state()); // Now node10 is in provisioned, set node11 to failed and node12 to ready, and it should be OK to delete host1 - tester.nodeRepository().fail("node11", Agent.system, getClass().getSimpleName()); - tester.nodeRepository().setReady("node12", Agent.system, getClass().getSimpleName()); - tester.nodeRepository().removeRecursively("node12"); // Remove one of the children first instead - assertEquals(4, tester.nodeRepository().getNodes().size()); - tester.nodeRepository().removeRecursively("host1"); - assertEquals(Node.State.deprovisioned, tester.nodeRepository().getNode("host1").get().state()); - assertEquals(IP.Config.EMPTY.primary(), tester.nodeRepository().getNode("host1").get().ipConfig().primary()); + tester.nodeRepository().nodes().fail("node11", Agent.system, getClass().getSimpleName()); + tester.nodeRepository().nodes().setReady("node12", Agent.system, getClass().getSimpleName()); + tester.nodeRepository().nodes().removeRecursively("node12"); // Remove one of the children first instead + assertEquals(4, tester.nodeRepository().nodes().getNodes().size()); + tester.nodeRepository().nodes().removeRecursively("host1"); + assertEquals(Node.State.deprovisioned, tester.nodeRepository().nodes().getNode("host1").get().state()); + assertEquals(IP.Config.EMPTY.primary(), tester.nodeRepository().nodes().getNode("host1").get().ipConfig().primary()); } @Test @@ -155,20 +155,20 @@ public class NodeRepositoryTest { tester.addNode("id2", cfg1, cfghost1, "docker", NodeType.config); tester.setNodeState(cfghost1, Node.State.active); tester.setNodeState(cfg1, Node.State.active); - assertEquals(2, tester.nodeRepository().getNodes().size()); + assertEquals(2, tester.nodeRepository().nodes().getNodes().size()); try { - tester.nodeRepository().removeRecursively(cfghost1); + tester.nodeRepository().nodes().removeRecursively(cfghost1); fail("Should not be able to delete host node, one of the children is in state active"); } catch (IllegalArgumentException ignored) { } - assertEquals(2, tester.nodeRepository().getNodes().size()); + assertEquals(2, tester.nodeRepository().nodes().getNodes().size()); // Fail host and container - tester.nodeRepository().failRecursively(cfghost1, Agent.system, getClass().getSimpleName()); + tester.nodeRepository().nodes().failRecursively(cfghost1, Agent.system, getClass().getSimpleName()); // Remove recursively - tester.nodeRepository().removeRecursively(cfghost1); - assertEquals(0, tester.nodeRepository().list().not().state(Node.State.deprovisioned).size()); + tester.nodeRepository().nodes().removeRecursively(cfghost1); + assertEquals(0, tester.nodeRepository().nodes().list().not().state(Node.State.deprovisioned).size()); } @Test @@ -179,29 +179,29 @@ public class NodeRepositoryTest { tester.clock().advance(Duration.ofSeconds(1)); tester.addHost("id1", "host1", "default", NodeType.host); tester.addHost("id2", "host2", "default", NodeType.host); - assertFalse(tester.nodeRepository().getNode("host1").get().history().hasEventAfter(History.Event.Type.deprovisioned, testStart)); + assertFalse(tester.nodeRepository().nodes().getNode("host1").get().history().hasEventAfter(History.Event.Type.deprovisioned, testStart)); // Set host 1 properties and deprovision it - try (var lock = tester.nodeRepository().lockAndGetRequired("host1")) { + try (var lock = tester.nodeRepository().nodes().lockAndGetRequired("host1")) { Node host1 = lock.node().withWantToRetire(true, true, Agent.system, tester.nodeRepository().clock().instant()); host1 = host1.withFirmwareVerifiedAt(tester.clock().instant()); host1 = host1.with(host1.status().withIncreasedFailCount()); host1 = host1.with(host1.reports().withReport(Report.basicReport("id", Report.Type.HARD_FAIL, tester.clock().instant(), "Test report"))); - tester.nodeRepository().write(host1, lock); + tester.nodeRepository().nodes().write(host1, lock); } - tester.nodeRepository().removeRecursively("host1"); + tester.nodeRepository().nodes().removeRecursively("host1"); // Host 1 is deprovisioned and unwanted properties are cleared - Node host1 = tester.nodeRepository().getNode("host1").get(); + Node host1 = tester.nodeRepository().nodes().getNode("host1").get(); assertEquals(Node.State.deprovisioned, host1.state()); assertTrue(host1.history().hasEventAfter(History.Event.Type.deprovisioned, testStart)); // Adding it again preserves some information from the deprovisioned host and removes it tester.addHost("id2", "host1", "default", NodeType.host); - host1 = tester.nodeRepository().getNode("host1").get(); + host1 = tester.nodeRepository().nodes().getNode("host1").get(); assertEquals("This is the newly added node", "id2", host1.id()); assertFalse("The old 'host1' is removed", - tester.nodeRepository().getNode("host1", Node.State.deprovisioned).isPresent()); + tester.nodeRepository().nodes().getNode("host1", Node.State.deprovisioned).isPresent()); assertFalse("Not transferred from deprovisioned host", host1.status().wantToRetire()); assertFalse("Not transferred from deprovisioned host", host1.status().wantToDeprovision()); assertTrue("Transferred from deprovisioned host", host1.history().hasEventAfter(History.Event.Type.deprovisioned, testStart)); @@ -225,15 +225,15 @@ public class NodeRepositoryTest { tester.setNodeState("node12", Node.State.active); tester.setNodeState("node20", Node.State.failed); - assertEquals(6, tester.nodeRepository().getNodes().size()); + assertEquals(6, tester.nodeRepository().nodes().getNodes().size()); // Should be OK to dirty host2 as it is in provisioned and its only child is in failed - tester.nodeRepository().deallocateRecursively("host2", Agent.system, NodeRepositoryTest.class.getSimpleName()); + tester.nodeRepository().nodes().deallocateRecursively("host2", Agent.system, NodeRepositoryTest.class.getSimpleName()); assertEquals(asSet("host2", "node20"), filterNodes(tester, node -> node.state() == Node.State.dirty)); // Cant dirty host1, node11 is ready and node12 is active try { - tester.nodeRepository().deallocateRecursively("host1", Agent.system, NodeRepositoryTest.class.getSimpleName()); + tester.nodeRepository().nodes().deallocateRecursively("host1", Agent.system, NodeRepositoryTest.class.getSimpleName()); fail("Should not be able to dirty host1"); } catch (IllegalArgumentException ignored) { } // Expected; @@ -248,27 +248,27 @@ public class NodeRepositoryTest { String reason = NodeRepositoryTest.class.getSimpleName(); try { - tester.nodeRepository().breakfixRecursively("node1", Agent.system, reason); + tester.nodeRepository().nodes().breakfixRecursively("node1", Agent.system, reason); fail("Should not be able to breakfix tenant node"); } catch (IllegalArgumentException ignored) {} try { - tester.nodeRepository().breakfixRecursively("host1", Agent.system, reason); + tester.nodeRepository().nodes().breakfixRecursively("host1", Agent.system, reason); fail("Should not be able to breakfix host in state not in [parked, failed]"); } catch (IllegalArgumentException ignored) {} tester.setNodeState("host1", Node.State.failed); tester.setNodeState("node1", Node.State.active); try { - tester.nodeRepository().breakfixRecursively("host1", Agent.system, reason); + tester.nodeRepository().nodes().breakfixRecursively("host1", Agent.system, reason); fail("Should not be able to breakfix host with active tenant node"); } catch (IllegalArgumentException ignored) {} tester.setNodeState("node1", Node.State.failed); - tester.nodeRepository().breakfixRecursively("host1", Agent.system, reason); + tester.nodeRepository().nodes().breakfixRecursively("host1", Agent.system, reason); - assertEquals(1, tester.nodeRepository().getNodes().size()); - Node node = tester.nodeRepository().getNodes().get(0); + assertEquals(1, tester.nodeRepository().nodes().getNodes().size()); + Node node = tester.nodeRepository().nodes().getNodes().get(0); assertEquals("host1", node.hostname()); assertEquals(Node.State.breakfixed, node.state()); } @@ -278,7 +278,7 @@ public class NodeRepositoryTest { } private static Set<String> filterNodes(NodeRepositoryTester tester, Predicate<Node> filter) { - return tester.nodeRepository() + return tester.nodeRepository().nodes() .getNodes().stream() .filter(filter) .map(Node::hostname) 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 f6ad119b80b..5e3b474e48b 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 @@ -52,7 +52,7 @@ public class NodeRepositoryTester { public MockCurator curator() { return curator; } public List<Node> getNodes(NodeType type, Node.State ... inState) { - return nodeRepository.getNodes(type, inState); + return nodeRepository.nodes().getNodes(type, inState); } public Node addHost(String id, String hostname, String flavor, NodeType type) { @@ -70,7 +70,7 @@ public class NodeRepositoryTester { private Node addNode(String id, String hostname, String parentHostname, Flavor flavor, NodeType type) { IP.Config ipConfig = new IP.Config(nodeRepository.nameResolver().resolveAll(hostname), Set.of()); Node node = Node.create(id, ipConfig, hostname, flavor, type).parentHostname(parentHostname).build(); - return nodeRepository.addNodes(List.of(node), Agent.system).get(0); + return nodeRepository.nodes().addNodes(List.of(node), Agent.system).get(0); } /** @@ -79,7 +79,7 @@ public class NodeRepositoryTester { * of valid state transitions */ public void setNodeState(String hostname, Node.State state) { - Node node = nodeRepository.getNode(hostname).orElseThrow(RuntimeException::new); + Node node = nodeRepository.nodes().getNode(hostname).orElseThrow(RuntimeException::new); nodeRepository.database().writeTo(state, node, Agent.system, Optional.empty()); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/RealDataScenarioTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/RealDataScenarioTest.java index af14876c20c..b17c8fc35b6 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/RealDataScenarioTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/RealDataScenarioTest.java @@ -80,7 +80,7 @@ public class RealDataScenarioTest { }; deploy(tester, app, specs, capacities); - tester.nodeRepository().list(app).cluster(specs[1].id()).forEach(System.out::println); + tester.nodeRepository().nodes().list(app).cluster(specs[1].id()).forEach(System.out::println); } private void deploy(ProvisioningTester tester, ApplicationId app, ClusterSpec[] specs, Capacity[] capacities) { diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingIntegrationTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingIntegrationTest.java index 8ef2fd72d08..5f7b4bc865c 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingIntegrationTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingIntegrationTest.java @@ -56,11 +56,11 @@ public class AutoscalingIntegrationTest { Application application = tester.nodeRepository().applications().get(application1).orElse(new Application(application1)) .withCluster(cluster1.id(), false, min, max); - try (Mutex lock = tester.nodeRepository().lock(application1)) { + try (Mutex lock = tester.nodeRepository().nodes().lock(application1)) { tester.nodeRepository().applications().put(application, lock); } var scaledResources = autoscaler.suggest(application.clusters().get(cluster1.id()), - tester.nodeRepository().list(application1)); + tester.nodeRepository().nodes().list(application1)); assertTrue(scaledResources.isPresent()); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java index a217d97ac27..a5f3d5f2828 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java @@ -116,7 +116,7 @@ public class AutoscalingTest { // deploy with slow tester.deploy(application1, cluster1, 5, 1, hostResources); - tester.nodeRepository().getNodes(application1).stream() + tester.nodeRepository().nodes().getNodes(application1).stream() .allMatch(n -> n.allocation().get().requestedResources().diskSpeed() == NodeResources.DiskSpeed.slow); tester.clock().advance(Duration.ofDays(2)); @@ -132,7 +132,7 @@ public class AutoscalingTest { assertEquals("Disk speed from min/max is used", NodeResources.DiskSpeed.any, scaledResources.nodeResources().diskSpeed()); tester.deploy(application1, cluster1, scaledResources); - tester.nodeRepository().getNodes(application1).stream() + tester.nodeRepository().nodes().getNodes(application1).stream() .allMatch(n -> n.allocation().get().requestedResources().diskSpeed() == NodeResources.DiskSpeed.any); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java index 43302c4fe23..e3148ad5de0 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java @@ -95,19 +95,19 @@ class AutoscalingTester { } public void makeReady(String hostname) { - Node node = nodeRepository().getNode(hostname).get(); + Node node = nodeRepository().nodes().getNode(hostname).get(); provisioningTester.patchNode(node, (n) -> n.with(new IP.Config(Set.of("::" + 0 + ":0"), Set.of()))); - Node host = nodeRepository().getNode(node.parentHostname().get()).get(); + Node host = nodeRepository().nodes().getNode(node.parentHostname().get()).get(); host = host.with(new IP.Config(Set.of("::" + 0 + ":0"), Set.of("::" + 0 + ":2"))); if (host.state() == Node.State.provisioned) - nodeRepository().setReady(List.of(host), Agent.system, getClass().getSimpleName()); + nodeRepository().nodes().setReady(List.of(host), Agent.system, getClass().getSimpleName()); } public void deactivateRetired(ApplicationId application, ClusterSpec cluster, ClusterResources resources) { - try (Mutex lock = nodeRepository().lock(application)){ - for (Node node : nodeRepository().getNodes(application, Node.State.active)) { + try (Mutex lock = nodeRepository().nodes().lock(application)){ + for (Node node : nodeRepository().nodes().getNodes(application, Node.State.active)) { if (node.allocation().get().membership().retired()) - nodeRepository().write(node.with(node.allocation().get().removable(true)), lock); + nodeRepository().nodes().write(node.with(node.allocation().get().removable(true)), lock); } } deploy(application, cluster, resources); @@ -125,7 +125,7 @@ class AutoscalingTester { */ public void addCpuMeasurements(float value, float otherResourcesLoad, int count, ApplicationId applicationId) { - List<Node> nodes = nodeRepository().getNodes(applicationId, Node.State.active); + List<Node> nodes = nodeRepository().nodes().getNodes(applicationId, Node.State.active); float oneExtraNodeFactor = (float)(nodes.size() - 1.0) / (nodes.size()); for (int i = 0; i < count; i++) { clock().advance(Duration.ofMinutes(1)); @@ -156,7 +156,7 @@ class AutoscalingTester { */ public void addMemMeasurements(float value, float otherResourcesLoad, int count, ApplicationId applicationId) { - List<Node> nodes = nodeRepository().getNodes(applicationId, Node.State.active); + List<Node> nodes = nodeRepository().nodes().getNodes(applicationId, Node.State.active); float oneExtraNodeFactor = (float)(nodes.size() - 1.0) / (nodes.size()); for (int i = 0; i < count; i++) { clock().advance(Duration.ofMinutes(1)); @@ -181,7 +181,7 @@ class AutoscalingTester { public void addMeasurements(float cpu, float memory, float disk, int generation, boolean inService, boolean stable, int count, ApplicationId applicationId) { - List<Node> nodes = nodeRepository().getNodes(applicationId, Node.State.active); + List<Node> nodes = nodeRepository().nodes().getNodes(applicationId, Node.State.active); for (int i = 0; i < count; i++) { clock().advance(Duration.ofMinutes(1)); for (Node node : nodes) { @@ -200,22 +200,22 @@ class AutoscalingTester { ClusterResources min, ClusterResources max) { Application application = nodeRepository().applications().get(applicationId).orElse(new Application(applicationId)) .withCluster(clusterId, false, min, max); - try (Mutex lock = nodeRepository().lock(applicationId)) { + try (Mutex lock = nodeRepository().nodes().lock(applicationId)) { nodeRepository().applications().put(application, lock); } return autoscaler.autoscale(application.clusters().get(clusterId), - nodeRepository().list(applicationId, Node.State.active)); + nodeRepository().nodes().list(applicationId, Node.State.active)); } public Autoscaler.Advice suggest(ApplicationId applicationId, ClusterSpec.Id clusterId, ClusterResources min, ClusterResources max) { Application application = nodeRepository().applications().get(applicationId).orElse(new Application(applicationId)) .withCluster(clusterId, false, min, max); - try (Mutex lock = nodeRepository().lock(applicationId)) { + try (Mutex lock = nodeRepository().nodes().lock(applicationId)) { nodeRepository().applications().put(application, lock); } return autoscaler.suggest(application.clusters().get(clusterId), - nodeRepository().list(applicationId, Node.State.active)); + nodeRepository().nodes().list(applicationId, Node.State.active)); } public ClusterResources assertResources(String message, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java index 14626a40070..1ea4abab17b 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java @@ -77,8 +77,8 @@ public class MetricsV2MetricsFetcherTest { { httpClient.cannedResponse = cannedResponseForApplication2; - try (Mutex lock = tester.nodeRepository().lock(application1)) { - tester.nodeRepository().write(tester.nodeRepository().getNodes(application2, Node.State.active) + try (Mutex lock = tester.nodeRepository().nodes().lock(application1)) { + tester.nodeRepository().nodes().write(tester.nodeRepository().nodes().getNodes(application2, Node.State.active) .get(0).retire(tester.clock().instant()), lock); } List<Pair<String, MetricSnapshot>> values = new ArrayList<>(fetcher.fetchMetrics(application2).get().metrics()); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java index f53ae1baad2..d6e6a7548c2 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java @@ -71,7 +71,7 @@ public class AutoscalingMaintainerTester { } public void addMeasurements(float cpu, float mem, float disk, long generation, int count, ApplicationId applicationId) { - List<Node> nodes = nodeRepository().getNodes(applicationId, Node.State.active); + List<Node> nodes = nodeRepository().nodes().getNodes(applicationId, Node.State.active); for (int i = 0; i < count; i++) { for (Node node : nodes) metricsDb.add(List.of(new Pair<>(node.hostname(), new MetricSnapshot(clock().instant(), diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/CapacityCheckerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/CapacityCheckerTest.java index 5e72cfc53ac..038d5729f0e 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/CapacityCheckerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/CapacityCheckerTest.java @@ -28,7 +28,7 @@ public class CapacityCheckerTest { tester.populateNodeRepositoryFromJsonFile(Paths.get(path)); var failurePath = tester.capacityChecker.worstCaseHostLossLeadingToFailure(); assertTrue(failurePath.isPresent()); - assertTrue(tester.nodeRepository.getNodes(NodeType.host).containsAll(failurePath.get().hostsCausingFailure)); + assertTrue(tester.nodeRepository.nodes().getNodes(NodeType.host).containsAll(failurePath.get().hostsCausingFailure)); assertEquals(5, failurePath.get().hostsCausingFailure.size()); } @@ -39,7 +39,7 @@ public class CapacityCheckerTest { 10, new NodeResources(-1, 10, 100, 1), 10, 0, new NodeResources(1, 10, 100, 1), 10); int overcommittedHosts = tester.capacityChecker.findOvercommittedHosts().size(); - assertEquals(tester.nodeRepository.getNodes(NodeType.host).size(), overcommittedHosts); + assertEquals(tester.nodeRepository.nodes().getNodes(NodeType.host).size(), overcommittedHosts); } @Test @@ -63,7 +63,7 @@ public class CapacityCheckerTest { assertTrue(failurePath.isPresent()); assertTrue("Computing worst case host loss if all hosts have to be removed should result in an non-empty failureReason with empty nodes.", failurePath.get().failureReason.tenant.isEmpty() && failurePath.get().failureReason.host.isEmpty()); - assertEquals(tester.nodeRepository.getNodes(NodeType.host).size(), failurePath.get().hostsCausingFailure.size()); + assertEquals(tester.nodeRepository.nodes().getNodes(NodeType.host).size(), failurePath.get().hostsCausingFailure.size()); } { 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 5dfd1193581..a94d91374fc 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 @@ -75,7 +75,7 @@ public class CapacityCheckerTester { } private void updateCapacityChecker() { - this.capacityChecker = new CapacityChecker(nodeRepository.list()); + this.capacityChecker = new CapacityChecker(nodeRepository.nodes().list()); } List<NodeModel> createDistinctChildren(int amount, List<NodeResources> childResources) { @@ -191,12 +191,12 @@ public class CapacityCheckerTester { int numEmptyHosts, NodeResources emptyHostExcessCapacity, int emptyHostExcessIps) { List<NodeModel> possibleChildren = createDistinctChildren(numDistinctChildren, childResources); Map<ApplicationId, List<Node>> hostsWithChildren = createHostsWithChildren(childrenPerHost, possibleChildren, numHosts, hostExcessCapacity, hostExcessIps); - nodeRepository.addNodes(hostsWithChildren.getOrDefault(tenantHostApp, List.of()), Agent.system); + nodeRepository.nodes().addNodes(hostsWithChildren.getOrDefault(tenantHostApp, List.of()), Agent.system); hostsWithChildren.forEach((applicationId, nodes) -> { if (applicationId.equals(tenantHostApp)) return; - nodeRepository.addNodes(nodes, Agent.system); + nodeRepository.nodes().addNodes(nodes, Agent.system); }); - nodeRepository.addNodes(createEmptyHosts(numHosts, numEmptyHosts, emptyHostExcessCapacity, emptyHostExcessIps), Agent.system); + nodeRepository.nodes().addNodes(createEmptyHosts(numHosts, numEmptyHosts, emptyHostExcessCapacity, emptyHostExcessIps), Agent.system); updateCapacityChecker(); } @@ -314,9 +314,9 @@ public class CapacityCheckerTester { } } - nodeRepository.addNodes(hosts, Agent.system); + nodeRepository.nodes().addNodes(hosts, Agent.system); nodes.forEach((application, applicationNodes) -> { - nodeRepository.addNodes(applicationNodes, Agent.system); + nodeRepository.nodes().addNodes(applicationNodes, Agent.system); }); updateCapacityChecker(); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainerTest.java index c67f6657c7f..2f735742ed5 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainerTest.java @@ -62,9 +62,9 @@ public class DynamicProvisioningMaintainerTest { var tester = new DynamicProvisioningTester().addInitialNodes(); tester.hostProvisioner.with(Behaviour.failDeprovisioning); // To avoid deleting excess nodes - Node host3 = tester.nodeRepository.getNode("host3").orElseThrow(); - Node host4 = tester.nodeRepository.getNode("host4").orElseThrow(); - Node host41 = tester.nodeRepository.getNode("host4-1").orElseThrow(); + Node host3 = tester.nodeRepository.nodes().getNode("host3").orElseThrow(); + Node host4 = tester.nodeRepository.nodes().getNode("host4").orElseThrow(); + Node host41 = tester.nodeRepository.nodes().getNode("host4-1").orElseThrow(); assertTrue("No IP addresses assigned", Stream.of(host3, host4, host41).map(node -> node.ipConfig().primary()).allMatch(Set::isEmpty)); @@ -73,9 +73,9 @@ public class DynamicProvisioningMaintainerTest { Node host41new = host41.with(host41.ipConfig().withPrimary(Set.of("::4:1", "::4:2"))); tester.maintainer.maintain(); - assertEquals(host3new, tester.nodeRepository.getNode("host3").get()); - assertEquals(host4new, tester.nodeRepository.getNode("host4").get()); - assertEquals(host41new, tester.nodeRepository.getNode("host4-1").get()); + assertEquals(host3new, tester.nodeRepository.nodes().getNode("host3").get()); + assertEquals(host4new, tester.nodeRepository.nodes().getNode("host4").get()); + assertEquals(host41new, tester.nodeRepository.nodes().getNode("host4-1").get()); } @Test @@ -88,29 +88,29 @@ public class DynamicProvisioningMaintainerTest { tester.maintainer.maintain(); assertEquals(Set.of("host4", "host4-1"), - tester.nodeRepository.getNodes(Node.State.failed).stream().map(Node::hostname).collect(Collectors.toSet())); + tester.nodeRepository.nodes().getNodes(Node.State.failed).stream().map(Node::hostname).collect(Collectors.toSet())); } @Test public void finds_nodes_that_need_deprovisioning_without_pre_provisioning() { var tester = new DynamicProvisioningTester().addInitialNodes(); - assertTrue(tester.nodeRepository.getNode("host2").isPresent()); - assertTrue(tester.nodeRepository.getNode("host3").isPresent()); + assertTrue(tester.nodeRepository.nodes().getNode("host2").isPresent()); + assertTrue(tester.nodeRepository.nodes().getNode("host3").isPresent()); tester.maintainer.maintain(); - assertTrue(tester.nodeRepository.getNode("host2").isEmpty()); - assertTrue(tester.nodeRepository.getNode("host3").isEmpty()); + assertTrue(tester.nodeRepository.nodes().getNode("host2").isEmpty()); + assertTrue(tester.nodeRepository.nodes().getNode("host3").isEmpty()); } @Test public void does_not_deprovision_when_preprovisioning_enabled() { var tester = new DynamicProvisioningTester().addInitialNodes(); tester.flagSource.withListFlag(PermanentFlags.PREPROVISION_CAPACITY.id(), List.of(new ClusterCapacity(1, 1, 3, 2, 1.0)), ClusterCapacity.class); - Optional<Node> failedHost = tester.nodeRepository.getNode("host2"); + Optional<Node> failedHost = tester.nodeRepository.nodes().getNode("host2"); assertTrue(failedHost.isPresent()); tester.maintainer.maintain(); - assertTrue("Failed host is deprovisioned", tester.nodeRepository.getNode(failedHost.get().hostname()).isEmpty()); + assertTrue("Failed host is deprovisioned", tester.nodeRepository.nodes().getNode(failedHost.get().hostname()).isEmpty()); assertEquals(1, tester.hostProvisioner.deprovisionedHosts); } @@ -123,24 +123,24 @@ public class DynamicProvisioningMaintainerTest { ClusterCapacity.class); assertEquals(0, tester.hostProvisioner.provisionedHosts.size()); - assertEquals(11, tester.nodeRepository.getNodes().size()); - assertTrue(tester.nodeRepository.getNode("host2").isPresent()); - assertTrue(tester.nodeRepository.getNode("host2-1").isPresent()); - assertTrue(tester.nodeRepository.getNode("host3").isPresent()); - assertTrue(tester.nodeRepository.getNode("hostname100").isEmpty()); - assertTrue(tester.nodeRepository.getNode("hostname101").isEmpty()); + assertEquals(11, tester.nodeRepository.nodes().getNodes().size()); + assertTrue(tester.nodeRepository.nodes().getNode("host2").isPresent()); + assertTrue(tester.nodeRepository.nodes().getNode("host2-1").isPresent()); + assertTrue(tester.nodeRepository.nodes().getNode("host3").isPresent()); + assertTrue(tester.nodeRepository.nodes().getNode("hostname100").isEmpty()); + assertTrue(tester.nodeRepository.nodes().getNode("hostname101").isEmpty()); tester.maintainer.maintain(); assertEquals(2, tester.hostProvisioner.provisionedHosts.size()); assertEquals(2, tester.provisionedHostsMatching(new NodeResources(48, 128, 1000, 10))); - List<Node> nodesAfter = tester.nodeRepository.getNodes(); + List<Node> nodesAfter = tester.nodeRepository.nodes().getNodes(); assertEquals(11, nodesAfter.size()); // 2 removed, 2 added - assertTrue("Failed host 'host2' is deprovisioned", tester.nodeRepository.getNode("host2").isEmpty()); - assertTrue("Node on deprovisioned host removed", tester.nodeRepository.getNode("host2-1").isEmpty()); - assertTrue("Host satisfying 16-24-100-1 is kept", tester.nodeRepository.getNode("host3").isPresent()); - assertTrue("New 48-128-1000-10 host added", tester.nodeRepository.getNode("hostname100").isPresent()); - assertTrue("New 48-128-1000-10 host added", tester.nodeRepository.getNode("hostname101").isPresent()); + assertTrue("Failed host 'host2' is deprovisioned", tester.nodeRepository.nodes().getNode("host2").isEmpty()); + assertTrue("Node on deprovisioned host removed", tester.nodeRepository.nodes().getNode("host2-1").isEmpty()); + assertTrue("Host satisfying 16-24-100-1 is kept", tester.nodeRepository.nodes().getNode("host3").isPresent()); + assertTrue("New 48-128-1000-10 host added", tester.nodeRepository.nodes().getNode("hostname100").isPresent()); + assertTrue("New 48-128-1000-10 host added", tester.nodeRepository.nodes().getNode("hostname101").isPresent()); } @Test @@ -154,11 +154,11 @@ public class DynamicProvisioningMaintainerTest { ClusterCapacity.class); assertEquals(0, tester.hostProvisioner.provisionedHosts.size()); - assertEquals(11, tester.nodeRepository.getNodes().size()); - assertTrue(tester.nodeRepository.getNode("host2").isPresent()); - assertTrue(tester.nodeRepository.getNode("host2-1").isPresent()); - assertTrue(tester.nodeRepository.getNode("host3").isPresent()); - assertTrue(tester.nodeRepository.getNode("hostname100").isEmpty()); + assertEquals(11, tester.nodeRepository.nodes().getNodes().size()); + assertTrue(tester.nodeRepository.nodes().getNode("host2").isPresent()); + assertTrue(tester.nodeRepository.nodes().getNode("host2-1").isPresent()); + assertTrue(tester.nodeRepository.nodes().getNode("host3").isPresent()); + assertTrue(tester.nodeRepository.nodes().getNode("hostname100").isEmpty()); // The first cluster will be allocated to host3 and a new host hostname100. // hostname100 will be a large shared host specified above. @@ -194,10 +194,10 @@ public class DynamicProvisioningMaintainerTest { assertEquals(2, tester.hostProvisioner.provisionedHosts.size()); assertEquals(2, tester.provisionedHostsMatching(new NodeResources(48, 128, 1000, 10))); - assertEquals(10, tester.nodeRepository.getNodes().size()); // 3 removed, 2 added - assertTrue("preprovision capacity is prefered on shared hosts", tester.nodeRepository.getNode("host3").isEmpty()); - assertTrue(tester.nodeRepository.getNode("hostname100").isPresent()); - assertTrue(tester.nodeRepository.getNode("hostname101").isPresent()); + assertEquals(10, tester.nodeRepository.nodes().getNodes().size()); // 3 removed, 2 added + assertTrue("preprovision capacity is prefered on shared hosts", tester.nodeRepository.nodes().getNode("host3").isEmpty()); + assertTrue(tester.nodeRepository.nodes().getNode("hostname100").isPresent()); + assertTrue(tester.nodeRepository.nodes().getNode("hostname101").isPresent()); // If the preprovision capacity is reduced, we should see shared hosts deprovisioned. @@ -210,13 +210,13 @@ public class DynamicProvisioningMaintainerTest { assertEquals("one provisioned host has been deprovisioned, so there are 2 -> 1 provisioned hosts", 1, tester.hostProvisioner.provisionedHosts.size()); assertEquals(1, tester.provisionedHostsMatching(new NodeResources(48, 128, 1000, 10))); - assertEquals(9, tester.nodeRepository.getNodes().size()); // 4 removed, 2 added - if (tester.nodeRepository.getNode("hostname100").isPresent()) { + assertEquals(9, tester.nodeRepository.nodes().getNodes().size()); // 4 removed, 2 added + if (tester.nodeRepository.nodes().getNode("hostname100").isPresent()) { assertTrue("hostname101 is superfluous and should have been deprovisioned", - tester.nodeRepository.getNode("hostname101").isEmpty()); + tester.nodeRepository.nodes().getNode("hostname101").isEmpty()); } else { assertTrue("hostname101 is required for preprovision capacity", - tester.nodeRepository.getNode("hostname101").isPresent()); + tester.nodeRepository.nodes().getNode("hostname101").isPresent()); } } @@ -224,11 +224,11 @@ public class DynamicProvisioningMaintainerTest { private void verifyFirstMaintain(DynamicProvisioningTester tester) { assertEquals(1, tester.hostProvisioner.provisionedHosts.size()); assertEquals(1, tester.provisionedHostsMatching(new NodeResources(48, 128, 1000, 10))); - assertEquals(10, tester.nodeRepository.getNodes().size()); // 2 removed, 1 added - assertTrue("Failed host 'host2' is deprovisioned", tester.nodeRepository.getNode("host2").isEmpty()); - assertTrue("Node on deprovisioned host removed", tester.nodeRepository.getNode("host2-1").isEmpty()); - assertTrue("One 1-30-20-3 node fits on host3", tester.nodeRepository.getNode("host3").isPresent()); - assertTrue("New 48-128-1000-10 host added", tester.nodeRepository.getNode("hostname100").isPresent()); + assertEquals(10, tester.nodeRepository.nodes().getNodes().size()); // 2 removed, 1 added + assertTrue("Failed host 'host2' is deprovisioned", tester.nodeRepository.nodes().getNode("host2").isEmpty()); + assertTrue("Node on deprovisioned host removed", tester.nodeRepository.nodes().getNode("host2-1").isEmpty()); + assertTrue("One 1-30-20-3 node fits on host3", tester.nodeRepository.nodes().getNode("host3").isPresent()); + assertTrue("New 48-128-1000-10 host added", tester.nodeRepository.nodes().getNode("hostname100").isPresent()); } @Test @@ -282,7 +282,7 @@ public class DynamicProvisioningMaintainerTest { tester.hostProvisioner.with(Behaviour.failDeprovisioning); tester.maintainer.maintain(); - assertTrue(tester.nodeRepository.getNode(host2.hostname()).isPresent()); + assertTrue(tester.nodeRepository.nodes().getNode(host2.hostname()).isPresent()); } @Test @@ -317,8 +317,8 @@ public class DynamicProvisioningMaintainerTest { tester.assertNodesUnchanged(); // Activate hosts - List<Node> provisioned = tester.nodeRepository.list().state(Node.State.provisioned).asList(); - tester.nodeRepository.setReady(provisioned, Agent.system, this.getClass().getSimpleName()); + List<Node> provisioned = tester.nodeRepository.nodes().list().state(Node.State.provisioned).asList(); + tester.nodeRepository.nodes().setReady(provisioned, Agent.system, this.getClass().getSimpleName()); tester.provisioningTester.activateTenantHosts(); // Allocating nodes to a host does not result in provisioning of additional capacity @@ -326,7 +326,7 @@ public class DynamicProvisioningMaintainerTest { NodeResources applicationNodeResources = new NodeResources(4, 8, 50, 0.1); tester.provisioningTester.deploy(application, Capacity.from(new ClusterResources(2, 1, applicationNodeResources))); - assertEquals(2, tester.nodeRepository.list().owner(application).size()); + assertEquals(2, tester.nodeRepository.nodes().list().owner(application).size()); tester.assertNodesUnchanged(); // Clearing flag does nothing @@ -338,10 +338,10 @@ public class DynamicProvisioningMaintainerTest { List.of(new ClusterCapacity(3, 0, 0, 0, 0.0)), ClusterCapacity.class); assertEquals(0, tester.provisionedHostsMatching(sharedHostNodeResources)); - assertTrue(tester.nodeRepository.getNode("hostname102").isEmpty()); + assertTrue(tester.nodeRepository.nodes().getNode("hostname102").isEmpty()); tester.maintainer.maintain(); assertEquals(1, tester.provisionedHostsMatching(sharedHostNodeResources)); - assertTrue(tester.nodeRepository.getNode("hostname102").isPresent()); + assertTrue(tester.nodeRepository.nodes().getNode("hostname102").isPresent()); // Next maintenance run does nothing tester.assertNodesUnchanged(); @@ -366,14 +366,14 @@ public class DynamicProvisioningMaintainerTest { ClusterCapacity.class); assertEquals(1, tester.provisionedHostsMatching(sharedHostNodeResources)); - assertTrue(tester.nodeRepository.getNode("hostname102").isPresent()); - assertTrue(tester.nodeRepository.getNode("hostname103").isEmpty()); - assertTrue(tester.nodeRepository.getNode("hostname104").isEmpty()); + assertTrue(tester.nodeRepository.nodes().getNode("hostname102").isPresent()); + assertTrue(tester.nodeRepository.nodes().getNode("hostname103").isEmpty()); + assertTrue(tester.nodeRepository.nodes().getNode("hostname104").isEmpty()); tester.maintainer.maintain(); assertEquals(3, tester.provisionedHostsMatching(sharedHostNodeResources)); - assertTrue(tester.nodeRepository.getNode("hostname102").isPresent()); - assertTrue(tester.nodeRepository.getNode("hostname103").isPresent()); - assertTrue(tester.nodeRepository.getNode("hostname104").isPresent()); + assertTrue(tester.nodeRepository.nodes().getNode("hostname102").isPresent()); + assertTrue(tester.nodeRepository.nodes().getNode("hostname103").isPresent()); + assertTrue(tester.nodeRepository.nodes().getNode("hostname104").isPresent()); } @Test @@ -381,7 +381,7 @@ public class DynamicProvisioningMaintainerTest { var tester = new DynamicProvisioningTester().addInitialNodes(); tester.hostProvisioner.with(Behaviour.failDnsUpdate); - Supplier<List<Node>> provisioning = () -> tester.nodeRepository.getNodes(NodeType.host, Node.State.provisioned); + Supplier<List<Node>> provisioning = () -> tester.nodeRepository.nodes().getNodes(NodeType.host, Node.State.provisioned); assertEquals(2, provisioning.get().size()); tester.maintainer.maintain(); @@ -482,9 +482,9 @@ public class DynamicProvisioningMaintainerTest { } private void assertNodesUnchanged() { - List<Node> nodes = nodeRepository.getNodes(); + List<Node> nodes = nodeRepository.nodes().getNodes(); maintainer.maintain(); - assertEquals("Nodes are unchanged after maintenance run", nodes, nodeRepository.getNodes()); + assertEquals("Nodes are unchanged after maintenance run", nodes, nodeRepository.nodes().getNodes()); } } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java index 9f2f7541c91..d02d08f7736 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java @@ -268,7 +268,7 @@ public class FailedExpirerTest { } public Node get(String hostname) { - return nodeRepository.getNode(hostname) + return nodeRepository.nodes().getNode(hostname) .orElseThrow(() -> new IllegalArgumentException("No such node: " + hostname)); } @@ -292,8 +292,8 @@ public class FailedExpirerTest { public FailureScenario failNode(int times, String... hostname) { Stream.of(hostname).forEach(h -> { Node node = get(h); - nodeRepository.write(node.with(node.status().withFailCount(times)), () -> {}); - nodeRepository.fail(h, Agent.system, "Failed by unit test"); + nodeRepository.nodes().write(node.with(node.status().withFailCount(times)), () -> {}); + nodeRepository.nodes().fail(h, Agent.system, "Failed by unit test"); }); return this; } @@ -302,8 +302,8 @@ public class FailedExpirerTest { Stream.of(hostname).forEach(h -> { Node node = get(h); Report report = Report.basicReport("reportId", Report.Type.HARD_FAIL, Instant.EPOCH, "hardware failure"); - nodeRepository.write(node.with(new Reports().withReport(report)), () -> {}); - nodeRepository.fail(h, Agent.system, "Failed by unit test"); + nodeRepository.nodes().write(node.with(new Reports().withReport(report)), () -> {}); + nodeRepository.nodes().fail(h, Agent.system, "Failed by unit test"); }); return this; } @@ -312,8 +312,8 @@ public class FailedExpirerTest { List<Node> nodes = Stream.of(hostname) .map(this::get) .collect(Collectors.toList()); - nodes = nodeRepository.deallocate(nodes, Agent.system, getClass().getSimpleName()); - nodeRepository.setReady(nodes, Agent.system, getClass().getSimpleName()); + nodes = nodeRepository.nodes().deallocate(nodes, Agent.system, getClass().getSimpleName()); + nodeRepository.nodes().setReady(nodes, Agent.system, getClass().getSimpleName()); return this; } @@ -340,7 +340,8 @@ public class FailedExpirerTest { public void assertNodesIn(Node.State state, String... hostnames) { assertEquals(Stream.of(hostnames).collect(Collectors.toSet()), - nodeRepository.getNodes(state).stream() + nodeRepository.nodes() + .getNodes(state).stream() .map(Node::hostname) .collect(Collectors.toSet())); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveAndFailedExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveAndFailedExpirerTest.java index 20c1bd78a52..4bee276af6d 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveAndFailedExpirerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveAndFailedExpirerTest.java @@ -65,14 +65,14 @@ public class InactiveAndFailedExpirerTest { // Inactive times out tester.advanceTime(Duration.ofMinutes(14)); new InactiveExpirer(tester.nodeRepository(), Duration.ofMinutes(10), new TestMetric()).run(); - assertEquals(0, tester.nodeRepository().getNodes(Node.State.inactive).size()); - List<Node> dirty = tester.nodeRepository().getNodes(Node.State.dirty); + assertEquals(0, tester.nodeRepository().nodes().getNodes(Node.State.inactive).size()); + List<Node> dirty = tester.nodeRepository().nodes().getNodes(Node.State.dirty); assertEquals(2, dirty.size()); assertFalse(dirty.get(0).allocation().isPresent()); assertFalse(dirty.get(1).allocation().isPresent()); // One node is set back to ready - Node ready = tester.nodeRepository().setReady(Collections.singletonList(dirty.get(0)), Agent.system, getClass().getSimpleName()).get(0); + Node ready = tester.nodeRepository().nodes().setReady(Collections.singletonList(dirty.get(0)), Agent.system, getClass().getSimpleName()).get(0); assertEquals("Allocated history is removed on readying", Arrays.asList(History.Event.Type.provisioned, History.Event.Type.readied), ready.history().events().stream().map(History.Event::type).collect(Collectors.toList())); @@ -80,8 +80,8 @@ public class InactiveAndFailedExpirerTest { // Dirty times out for the other one tester.advanceTime(Duration.ofMinutes(14)); new DirtyExpirer(tester.nodeRepository(), Duration.ofMinutes(10), new TestMetric()).run(); - assertEquals(0, tester.nodeRepository().getNodes(NodeType.tenant, Node.State.dirty).size()); - List<Node> failed = tester.nodeRepository().getNodes(NodeType.tenant, Node.State.failed); + assertEquals(0, tester.nodeRepository().nodes().getNodes(NodeType.tenant, Node.State.dirty).size()); + List<Node> failed = tester.nodeRepository().nodes().getNodes(NodeType.tenant, Node.State.failed); assertEquals(1, failed.size()); assertEquals(1, failed.get(0).status().failCount()); } @@ -108,7 +108,7 @@ public class InactiveAndFailedExpirerTest { // Inactive times out and node is moved to dirty tester.advanceTime(Duration.ofMinutes(14)); new InactiveExpirer(tester.nodeRepository(), Duration.ofMinutes(10), new TestMetric()).run(); - List<Node> dirty = tester.nodeRepository().getNodes(Node.State.dirty); + List<Node> dirty = tester.nodeRepository().nodes().getNodes(Node.State.dirty); assertEquals(2, dirty.size()); // Reboot generation is increased @@ -154,12 +154,12 @@ public class InactiveAndFailedExpirerTest { doThrow(new RuntimeException()).when(orchestrator).acquirePermissionToRemove(any()); new RetiredExpirer(tester.nodeRepository(), tester.orchestrator(), deployer, new TestMetric(), Duration.ofDays(30), Duration.ofMinutes(10)).run(); - assertEquals(1, tester.nodeRepository().getNodes(Node.State.inactive).size()); + assertEquals(1, tester.nodeRepository().nodes().getNodes(Node.State.inactive).size()); // Inactive times out and one node is moved to parked tester.advanceTime(Duration.ofMinutes(11)); // Trigger InactiveExpirer new InactiveExpirer(tester.nodeRepository(), Duration.ofMinutes(10), new TestMetric()).run(); - assertEquals(1, tester.nodeRepository().getNodes(Node.State.parked).size()); + assertEquals(1, tester.nodeRepository().nodes().getNodes(Node.State.parked).size()); } @Test @@ -181,8 +181,8 @@ public class InactiveAndFailedExpirerTest { // See that nodes are moved to dirty immediately. new InactiveExpirer(tester.nodeRepository(), Duration.ofMinutes(10), new TestMetric()).run(); - assertEquals(0, tester.nodeRepository().getNodes(Node.State.inactive).size()); - List<Node> dirty = tester.nodeRepository().getNodes(Node.State.dirty); + assertEquals(0, tester.nodeRepository().nodes().getNodes(Node.State.inactive).size()); + List<Node> dirty = tester.nodeRepository().nodes().getNodes(Node.State.dirty); assertEquals(1, dirty.size()); assertFalse(dirty.get(0).allocation().isPresent()); @@ -206,7 +206,7 @@ public class InactiveAndFailedExpirerTest { tester.patchNodes(inactiveNodes, (node) -> node.withWantToRetire(true, true, Agent.system, tester.clock().instant())); tester.advanceTime(Duration.ofMinutes(11)); new InactiveExpirer(tester.nodeRepository(), Duration.ofMinutes(10), new TestMetric()).run(); - assertEquals(2, tester.nodeRepository().getNodes(Node.State.parked).size()); + assertEquals(2, tester.nodeRepository().nodes().getNodes(Node.State.parked).size()); } } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirerTest.java index 60ca625d07e..832f8c0c318 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirerTest.java @@ -132,10 +132,10 @@ public class LoadBalancerExpirerTest { } private void dirtyNodesOf(ApplicationId application, ClusterSpec.Id cluster) { - tester.nodeRepository().deallocate(tester.nodeRepository().getNodes(application).stream() - .filter(node -> node.allocation().isPresent()) - .filter(node -> node.allocation().get().membership().cluster().id().equals(cluster)) - .collect(Collectors.toList()), + tester.nodeRepository().nodes().deallocate(tester.nodeRepository().nodes().getNodes(application).stream() + .filter(node -> node.allocation().isPresent()) + .filter(node -> node.allocation().get().membership().cluster().id().equals(cluster)) + .collect(Collectors.toList()), Agent.system, this.getClass().getSimpleName()); } 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 9adba744101..6cfd95e828a 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 @@ -121,7 +121,7 @@ public class MetricsReporterTest { expectedMetrics.put("cache.nodeObject.evictionCount", 0L); expectedMetrics.put("cache.nodeObject.size", 2L); - nodeRepository.list(); + nodeRepository.nodes().list(); expectedMetrics.put("cache.curator.hitRate", 0.52D); expectedMetrics.put("cache.curator.evictionCount", 0L); expectedMetrics.put("cache.curator.size", 12L); @@ -162,26 +162,26 @@ public class MetricsReporterTest { Node dockerHost = Node.create("openStackId1", new IP.Config(Set.of("::1"), ipAddressPool), "dockerHost", nodeFlavors.getFlavorOrThrow("host"), NodeType.host).build(); - nodeRepository.addNodes(List.of(dockerHost), Agent.system); - nodeRepository.deallocateRecursively("dockerHost", Agent.system, getClass().getSimpleName()); - nodeRepository.setReady("dockerHost", Agent.system, getClass().getSimpleName()); + nodeRepository.nodes().addNodes(List.of(dockerHost), Agent.system); + nodeRepository.nodes().deallocateRecursively("dockerHost", Agent.system, getClass().getSimpleName()); + nodeRepository.nodes().setReady("dockerHost", Agent.system, getClass().getSimpleName()); Node container1 = Node.createDockerNode(Set.of("::2"), "container1", "dockerHost", new NodeResources(1, 3, 2, 1), NodeType.tenant).build(); container1 = container1.with(allocation(Optional.of("app1"), container1).get()); - try (Mutex lock = nodeRepository.lockUnallocated()) { - nodeRepository.addDockerNodes(new LockedNodeList(List.of(container1), lock)); + try (Mutex lock = nodeRepository.nodes().lockUnallocated()) { + nodeRepository.nodes().addDockerNodes(new LockedNodeList(List.of(container1), lock)); } Node container2 = Node.createDockerNode(Set.of("::3"), "container2", "dockerHost", new NodeResources(2, 4, 4, 1), NodeType.tenant).build(); container2 = container2.with(allocation(Optional.of("app2"), container2).get()); - try (Mutex lock = nodeRepository.lockUnallocated()) { - nodeRepository.addDockerNodes(new LockedNodeList(List.of(container2), lock)); + try (Mutex lock = nodeRepository.nodes().lockUnallocated()) { + nodeRepository.nodes().addDockerNodes(new LockedNodeList(List.of(container2), lock)); } NestedTransaction transaction = new NestedTransaction(); - nodeRepository.activate(nodeRepository.getNodes(NodeType.host), transaction); + nodeRepository.nodes().activate(nodeRepository.nodes().getNodes(NodeType.host), transaction); transaction.commit(); Orchestrator orchestrator = mock(Orchestrator.class); 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 d0473d08ea2..dba3ca6a92e 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 @@ -102,8 +102,8 @@ public class NodeFailTester { tester.activate(app1, clusterApp1, capacity1); tester.activate(app2, clusterApp2, capacity2); - assertEquals(capacity1.minResources().nodes(), tester.nodeRepository.getNodes(app1, Node.State.active).size()); - assertEquals(capacity2.minResources().nodes(), tester.nodeRepository.getNodes(app2, Node.State.active).size()); + assertEquals(capacity1.minResources().nodes(), tester.nodeRepository.nodes().getNodes(app1, Node.State.active).size()); + assertEquals(capacity2.minResources().nodes(), tester.nodeRepository.nodes().getNodes(app2, Node.State.active).size()); Map<ApplicationId, MockDeployer.ApplicationContext> apps = Map.of( app1, new MockDeployer.ApplicationContext(app1, clusterApp1, capacity1), @@ -132,10 +132,10 @@ public class NodeFailTester { tester.activate(tenantHostApp, clusterNodeAdminApp, allHosts); tester.activate(app1, clusterApp1, capacity1); tester.activate(app2, clusterApp2, capacity2); - assertEquals(Set.of(tester.nodeRepository.getNodes(NodeType.host)), - Set.of(tester.nodeRepository.getNodes(tenantHostApp, Node.State.active))); - assertEquals(capacity1.minResources().nodes(), tester.nodeRepository.getNodes(app1, Node.State.active).size()); - assertEquals(capacity2.minResources().nodes(), tester.nodeRepository.getNodes(app2, Node.State.active).size()); + assertEquals(Set.of(tester.nodeRepository.nodes().getNodes(NodeType.host)), + Set.of(tester.nodeRepository.nodes().getNodes(tenantHostApp, Node.State.active))); + assertEquals(capacity1.minResources().nodes(), tester.nodeRepository.nodes().getNodes(app1, Node.State.active).size()); + assertEquals(capacity2.minResources().nodes(), tester.nodeRepository.nodes().getNodes(app2, Node.State.active).size()); Map<ApplicationId, MockDeployer.ApplicationContext> apps = Map.of( tenantHostApp, new MockDeployer.ApplicationContext(tenantHostApp, clusterNodeAdminApp, allHosts), @@ -163,7 +163,7 @@ public class NodeFailTester { Capacity allNodes = Capacity.fromRequiredNodeType(nodeType); ClusterSpec clusterApp1 = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("test")).vespaVersion("6.42").build(); tester.activate(app1, clusterApp1, allNodes); - assertEquals(count, tester.nodeRepository.getNodes(nodeType, Node.State.active).size()); + assertEquals(count, tester.nodeRepository.nodes().getNodes(nodeType, Node.State.active).size()); Map<ApplicationId, MockDeployer.ApplicationContext> apps = Map.of( app1, new MockDeployer.ApplicationContext(app1, clusterApp1, allNodes)); @@ -212,7 +212,7 @@ public class NodeFailTester { } public void allNodesMakeAConfigRequestExcept(List<Node> deadNodes) { - for (Node node : nodeRepository.getNodes()) { + for (Node node : nodeRepository.nodes().getNodes()) { if ( ! deadNodes.contains(node)) hostLivenessTracker.receivedRequestFrom(node.hostname()); } @@ -258,18 +258,18 @@ public class NodeFailTester { nodes.add(builder.build()); } - nodes = nodeRepository.addNodes(nodes, Agent.system); - nodes = nodeRepository.deallocate(nodes, Agent.system, getClass().getSimpleName()); - return nodeRepository.setReady(nodes, Agent.system, getClass().getSimpleName()); + nodes = nodeRepository.nodes().addNodes(nodes, Agent.system); + nodes = nodeRepository.nodes().deallocate(nodes, Agent.system, getClass().getSimpleName()); + return nodeRepository.nodes().setReady(nodes, Agent.system, getClass().getSimpleName()); } private List<Node> createHostNodes(int count) { List<Node> nodes = tester.makeProvisionedNodes(count, (index) -> "parent" + index, hostFlavors.getFlavorOrThrow("default"), Optional.empty(), NodeType.host, 10, false); - nodes = nodeRepository.deallocate(nodes, Agent.system, getClass().getSimpleName()); + nodes = nodeRepository.nodes().deallocate(nodes, Agent.system, getClass().getSimpleName()); tester.activateTenantHosts(); - return nodeRepository.setReady(nodes, Agent.system, getClass().getSimpleName()); + return nodeRepository.nodes().setReady(nodes, Agent.system, getClass().getSimpleName()); } // Prefer using this instead of the above diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailerTest.java index d4dbc6f55a5..50b99afbca5 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailerTest.java @@ -51,11 +51,11 @@ public class NodeFailerTest { String hostWithFailureReports = selectFirstParentHostWithNActiveNodesExcept(tester.nodeRepository, 2); // Set failure report to the parent and all its children. - tester.nodeRepository.getNodes().stream() + tester.nodeRepository.nodes().getNodes().stream() .filter(node -> node.hostname().equals(hostWithFailureReports)) .forEach(node -> { Node updatedNode = node.with(node.reports().withReport(badTotalMemorySizeReport)); - tester.nodeRepository.write(updatedNode, () -> {}); + tester.nodeRepository.nodes().write(updatedNode, () -> {}); }); testNodeFailingWith(tester, hostWithFailureReports); @@ -63,7 +63,7 @@ public class NodeFailerTest { private void testNodeFailingWith(NodeFailTester tester, String hostWithHwFailure) { // The host should have 2 nodes in active and 1 ready - Map<Node.State, List<String>> hostnamesByState = tester.nodeRepository.list().childrenOf(hostWithHwFailure).asList().stream() + Map<Node.State, List<String>> hostnamesByState = tester.nodeRepository.nodes().list().childrenOf(hostWithHwFailure).asList().stream() .collect(Collectors.groupingBy(Node::state, Collectors.mapping(Node::hostname, Collectors.toList()))); assertEquals(2, hostnamesByState.get(Node.State.active).size()); assertEquals(1, hostnamesByState.get(Node.State.ready).size()); @@ -80,7 +80,7 @@ public class NodeFailerTest { Map<Node.State, List<String>> expectedHostnamesByState1Iter = Map.of( Node.State.failed, List.of(hostnamesByState.get(Node.State.ready).get(0), hostnamesByState.get(Node.State.active).get(0)), Node.State.active, hostnamesByState.get(Node.State.active).subList(1, 2)); - Map<Node.State, List<String>> hostnamesByState1Iter = tester.nodeRepository.list().childrenOf(hostWithHwFailure).asList().stream() + Map<Node.State, List<String>> hostnamesByState1Iter = tester.nodeRepository.nodes().list().childrenOf(hostWithHwFailure).asList().stream() .collect(Collectors.groupingBy(Node::state, Collectors.mapping(Node::hostname, Collectors.toList()))); assertEquals(expectedHostnamesByState1Iter, hostnamesByState1Iter); @@ -92,26 +92,26 @@ public class NodeFailerTest { tester.runMaintainers(); // All of the children should be failed now - Set<Node.State> childStates2Iter = tester.nodeRepository.list().childrenOf(hostWithHwFailure).asList().stream() + Set<Node.State> childStates2Iter = tester.nodeRepository.nodes().list().childrenOf(hostWithHwFailure).asList().stream() .map(Node::state).collect(Collectors.toSet()); assertEquals(Set.of(Node.State.failed), childStates2Iter); // The host itself is still active as it too must be allowed to suspend - assertEquals(Node.State.active, tester.nodeRepository.getNode(hostWithHwFailure).get().state()); + assertEquals(Node.State.active, tester.nodeRepository.nodes().getNode(hostWithHwFailure).get().state()); tester.suspend(hostWithHwFailure); tester.runMaintainers(); - assertEquals(Node.State.failed, tester.nodeRepository.getNode(hostWithHwFailure).get().state()); - assertEquals(4, tester.nodeRepository.getNodes(Node.State.failed).size()); + assertEquals(Node.State.failed, tester.nodeRepository.nodes().getNode(hostWithHwFailure).get().state()); + assertEquals(4, tester.nodeRepository.nodes().getNodes(Node.State.failed).size()); } @Test public void hw_fail_only_if_whole_host_is_suspended() { NodeFailTester tester = NodeFailTester.withTwoApplicationsOnDocker(6); String hostWithFailureReports = selectFirstParentHostWithNActiveNodesExcept(tester.nodeRepository, 2); - assertEquals(Node.State.active, tester.nodeRepository.getNode(hostWithFailureReports).get().state()); + assertEquals(Node.State.active, tester.nodeRepository.nodes().getNode(hostWithFailureReports).get().state()); // The host has 2 nodes in active and 1 ready - Map<Node.State, List<String>> hostnamesByState = tester.nodeRepository.list().childrenOf(hostWithFailureReports).asList().stream() + Map<Node.State, List<String>> hostnamesByState = tester.nodeRepository.nodes().list().childrenOf(hostWithFailureReports).asList().stream() .collect(Collectors.groupingBy(Node::state, Collectors.mapping(Node::hostname, Collectors.toList()))); assertEquals(2, hostnamesByState.get(Node.State.active).size()); String activeChild1 = hostnamesByState.get(Node.State.active).get(0); @@ -121,50 +121,50 @@ public class NodeFailerTest { // Set failure report to the parent and all its children. Report badTotalMemorySizeReport = Report.basicReport("badTotalMemorySize", HARD_FAIL, Instant.now(), "too low"); - tester.nodeRepository.getNodes().stream() + tester.nodeRepository.nodes().getNodes().stream() .filter(node -> node.hostname().equals(hostWithFailureReports)) .forEach(node -> { Node updatedNode = node.with(node.reports().withReport(badTotalMemorySizeReport)); - tester.nodeRepository.write(updatedNode, () -> {}); + tester.nodeRepository.nodes().write(updatedNode, () -> {}); }); // The ready node will be failed, but neither the host nor the 2 active nodes since they have not been suspended tester.allNodesMakeAConfigRequestExcept(); tester.runMaintainers(); - assertEquals(Node.State.failed, tester.nodeRepository.getNode(readyChild).get().state()); - assertEquals(Node.State.active, tester.nodeRepository.getNode(hostWithFailureReports).get().state()); - assertEquals(Node.State.active, tester.nodeRepository.getNode(activeChild1).get().state()); - assertEquals(Node.State.active, tester.nodeRepository.getNode(activeChild2).get().state()); + assertEquals(Node.State.failed, tester.nodeRepository.nodes().getNode(readyChild).get().state()); + assertEquals(Node.State.active, tester.nodeRepository.nodes().getNode(hostWithFailureReports).get().state()); + assertEquals(Node.State.active, tester.nodeRepository.nodes().getNode(activeChild1).get().state()); + assertEquals(Node.State.active, tester.nodeRepository.nodes().getNode(activeChild2).get().state()); // Suspending the host will not fail any more since none of the children are suspened tester.suspend(hostWithFailureReports); tester.clock.advance(Duration.ofHours(25)); tester.allNodesMakeAConfigRequestExcept(); tester.runMaintainers(); - assertEquals(Node.State.failed, tester.nodeRepository.getNode(readyChild).get().state()); - assertEquals(Node.State.active, tester.nodeRepository.getNode(hostWithFailureReports).get().state()); - assertEquals(Node.State.active, tester.nodeRepository.getNode(activeChild1).get().state()); - assertEquals(Node.State.active, tester.nodeRepository.getNode(activeChild2).get().state()); + assertEquals(Node.State.failed, tester.nodeRepository.nodes().getNode(readyChild).get().state()); + assertEquals(Node.State.active, tester.nodeRepository.nodes().getNode(hostWithFailureReports).get().state()); + assertEquals(Node.State.active, tester.nodeRepository.nodes().getNode(activeChild1).get().state()); + assertEquals(Node.State.active, tester.nodeRepository.nodes().getNode(activeChild2).get().state()); // Suspending one child node will fail that out. tester.suspend(activeChild1); tester.clock.advance(Duration.ofHours(25)); tester.allNodesMakeAConfigRequestExcept(); tester.runMaintainers(); - assertEquals(Node.State.failed, tester.nodeRepository.getNode(readyChild).get().state()); - assertEquals(Node.State.active, tester.nodeRepository.getNode(hostWithFailureReports).get().state()); - assertEquals(Node.State.failed, tester.nodeRepository.getNode(activeChild1).get().state()); - assertEquals(Node.State.active, tester.nodeRepository.getNode(activeChild2).get().state()); + assertEquals(Node.State.failed, tester.nodeRepository.nodes().getNode(readyChild).get().state()); + assertEquals(Node.State.active, tester.nodeRepository.nodes().getNode(hostWithFailureReports).get().state()); + assertEquals(Node.State.failed, tester.nodeRepository.nodes().getNode(activeChild1).get().state()); + assertEquals(Node.State.active, tester.nodeRepository.nodes().getNode(activeChild2).get().state()); // Suspending the second child node will fail that out and the host. tester.suspend(activeChild2); tester.clock.advance(Duration.ofHours(25)); tester.allNodesMakeAConfigRequestExcept(); tester.runMaintainers(); - assertEquals(Node.State.failed, tester.nodeRepository.getNode(readyChild).get().state()); - assertEquals(Node.State.failed, tester.nodeRepository.getNode(hostWithFailureReports).get().state()); - assertEquals(Node.State.failed, tester.nodeRepository.getNode(activeChild1).get().state()); - assertEquals(Node.State.failed, tester.nodeRepository.getNode(activeChild2).get().state()); + assertEquals(Node.State.failed, tester.nodeRepository.nodes().getNode(readyChild).get().state()); + assertEquals(Node.State.failed, tester.nodeRepository.nodes().getNode(hostWithFailureReports).get().state()); + assertEquals(Node.State.failed, tester.nodeRepository.nodes().getNode(activeChild1).get().state()); + assertEquals(Node.State.failed, tester.nodeRepository.nodes().getNode(activeChild2).get().state()); } @Test @@ -173,39 +173,39 @@ public class NodeFailerTest { tester.suspend(NodeFailTester.app1); // Set two nodes down (one for each application) and wait 65 minutes - String host_from_suspended_app = tester.nodeRepository.getNodes(NodeFailTester.app1, Node.State.active).get(1).hostname(); - String host_from_normal_app = tester.nodeRepository.getNodes(NodeFailTester.app2, Node.State.active).get(3).hostname(); + String host_from_suspended_app = tester.nodeRepository.nodes().getNodes(NodeFailTester.app1, Node.State.active).get(1).hostname(); + String host_from_normal_app = tester.nodeRepository.nodes().getNodes(NodeFailTester.app2, Node.State.active).get(3).hostname(); tester.serviceMonitor.setHostDown(host_from_suspended_app); tester.serviceMonitor.setHostDown(host_from_normal_app); tester.runMaintainers(); tester.clock.advance(Duration.ofMinutes(65)); tester.runMaintainers(); - assertTrue(tester.nodeRepository.getNode(host_from_normal_app).get().isDown()); - assertTrue(tester.nodeRepository.getNode(host_from_suspended_app).get().isDown()); - assertEquals(Node.State.failed, tester.nodeRepository.getNode(host_from_normal_app).get().state()); - assertEquals(Node.State.active, tester.nodeRepository.getNode(host_from_suspended_app).get().state()); + assertTrue(tester.nodeRepository.nodes().getNode(host_from_normal_app).get().isDown()); + assertTrue(tester.nodeRepository.nodes().getNode(host_from_suspended_app).get().isDown()); + assertEquals(Node.State.failed, tester.nodeRepository.nodes().getNode(host_from_normal_app).get().state()); + assertEquals(Node.State.active, tester.nodeRepository.nodes().getNode(host_from_suspended_app).get().state()); } @Test public void zone_is_not_working_if_too_many_nodes_down() { NodeFailTester tester = NodeFailTester.withTwoApplications(); - tester.serviceMonitor.setHostDown(tester.nodeRepository.getNodes(NodeFailTester.app1, Node.State.active).get(0).hostname()); + tester.serviceMonitor.setHostDown(tester.nodeRepository.nodes().getNodes(NodeFailTester.app1, Node.State.active).get(0).hostname()); tester.runMaintainers(); - assertTrue(tester.nodeRepository.isWorking()); + assertTrue(tester.nodeRepository.nodes().isWorking()); - tester.serviceMonitor.setHostDown(tester.nodeRepository.getNodes(NodeFailTester.app1, Node.State.active).get(1).hostname()); + tester.serviceMonitor.setHostDown(tester.nodeRepository.nodes().getNodes(NodeFailTester.app1, Node.State.active).get(1).hostname()); tester.runMaintainers(); - assertTrue(tester.nodeRepository.isWorking()); + assertTrue(tester.nodeRepository.nodes().isWorking()); - tester.serviceMonitor.setHostDown(tester.nodeRepository.getNodes(NodeFailTester.app1, Node.State.active).get(2).hostname()); + tester.serviceMonitor.setHostDown(tester.nodeRepository.nodes().getNodes(NodeFailTester.app1, Node.State.active).get(2).hostname()); tester.runMaintainers(); - assertFalse(tester.nodeRepository.isWorking()); + assertFalse(tester.nodeRepository.nodes().isWorking()); tester.clock.advance(Duration.ofMinutes(65)); tester.runMaintainers(); - assertTrue("Node failing is deactivated", tester.nodeRepository.list(Node.State.failed).isEmpty()); + assertTrue("Node failing is deactivated", tester.nodeRepository.nodes().list(Node.State.failed).isEmpty()); } @Test @@ -219,24 +219,24 @@ public class NodeFailerTest { tester.allNodesMakeAConfigRequestExcept(); assertEquals( 0, tester.deployer.redeployments); - assertEquals(12, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.active).size()); - assertEquals( 0, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.failed).size()); - assertEquals( 4, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.ready).size()); + assertEquals(12, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.active).size()); + assertEquals( 0, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed).size()); + assertEquals( 4, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.ready).size()); } // Hardware failures are detected on two ready nodes, which are then failed - Node readyFail1 = tester.nodeRepository.getNodes(NodeType.tenant, Node.State.ready).get(2); - Node readyFail2 = tester.nodeRepository.getNodes(NodeType.tenant, Node.State.ready).get(3); - tester.nodeRepository.write(readyFail1.with(new Reports().withReport(badTotalMemorySizeReport)), () -> {}); - tester.nodeRepository.write(readyFail2.with(new Reports().withReport(badTotalMemorySizeReport)), () -> {}); - assertEquals(4, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.ready).size()); - tester.runMaintainers(); - assertEquals(2, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.ready).size()); - assertEquals(Node.State.failed, tester.nodeRepository.getNode(readyFail1.hostname()).get().state()); - assertEquals(Node.State.failed, tester.nodeRepository.getNode(readyFail2.hostname()).get().state()); - - String downHost1 = tester.nodeRepository.getNodes(NodeFailTester.app1, Node.State.active).get(1).hostname(); - String downHost2 = tester.nodeRepository.getNodes(NodeFailTester.app2, Node.State.active).get(3).hostname(); + Node readyFail1 = tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.ready).get(2); + Node readyFail2 = tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.ready).get(3); + tester.nodeRepository.nodes().write(readyFail1.with(new Reports().withReport(badTotalMemorySizeReport)), () -> {}); + tester.nodeRepository.nodes().write(readyFail2.with(new Reports().withReport(badTotalMemorySizeReport)), () -> {}); + assertEquals(4, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.ready).size()); + tester.runMaintainers(); + assertEquals(2, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.ready).size()); + assertEquals(Node.State.failed, tester.nodeRepository.nodes().getNode(readyFail1.hostname()).get().state()); + assertEquals(Node.State.failed, tester.nodeRepository.nodes().getNode(readyFail2.hostname()).get().state()); + + String downHost1 = tester.nodeRepository.nodes().getNodes(NodeFailTester.app1, Node.State.active).get(1).hostname(); + String downHost2 = tester.nodeRepository.nodes().getNodes(NodeFailTester.app2, Node.State.active).get(3).hostname(); tester.serviceMonitor.setHostDown(downHost1); tester.serviceMonitor.setHostDown(downHost2); // nothing happens the first 45 minutes @@ -245,9 +245,9 @@ public class NodeFailerTest { tester.clock.advance(Duration.ofMinutes(5)); tester.allNodesMakeAConfigRequestExcept(); assertEquals( 0, tester.deployer.redeployments); - assertEquals(12, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.active).size()); - assertEquals( 2, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.failed).size()); - assertEquals( 2, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.ready).size()); + assertEquals(12, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.active).size()); + assertEquals( 2, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed).size()); + assertEquals( 2, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.ready).size()); } tester.serviceMonitor.setHostUp(downHost1); @@ -256,10 +256,10 @@ public class NodeFailerTest { tester.allNodesMakeAConfigRequestExcept(); tester.runMaintainers(); assertEquals( 1, tester.deployer.redeployments); - assertEquals(12, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.active).size()); - assertEquals( 3, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.failed).size()); - assertEquals( 1, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.ready).size()); - assertEquals(downHost2, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.failed).get(0).hostname()); + assertEquals(12, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.active).size()); + assertEquals( 3, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed).size()); + assertEquals( 1, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.ready).size()); + assertEquals(downHost2, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed).get(0).hostname()); // downHost1 fails again tester.serviceMonitor.setHostDown(downHost1); @@ -275,12 +275,12 @@ public class NodeFailerTest { tester.allNodesMakeAConfigRequestExcept(); tester.runMaintainers(); assertEquals( 2, tester.deployer.redeployments); - assertEquals(12, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.active).size()); - assertEquals( 4, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.failed).size()); - assertEquals( 0, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.ready).size()); + assertEquals(12, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.active).size()); + assertEquals( 4, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed).size()); + assertEquals( 0, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.ready).size()); // the last host goes down - Node lastNode = tester.highestIndex(tester.nodeRepository.getNodes(NodeFailTester.app1, Node.State.active)); + Node lastNode = tester.highestIndex(tester.nodeRepository.nodes().getNodes(NodeFailTester.app1, Node.State.active)); tester.serviceMonitor.setHostDown(lastNode.hostname()); // it is not failed because there are no ready nodes to replace it for (int minutes = 0; minutes < 75; minutes +=5 ) { @@ -288,9 +288,9 @@ public class NodeFailerTest { tester.clock.advance(Duration.ofMinutes(5)); tester.allNodesMakeAConfigRequestExcept(); assertEquals( 2, tester.deployer.redeployments); - assertEquals(12, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.active).size()); - assertEquals( 4, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.failed).size()); - assertEquals( 0, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.ready).size()); + assertEquals(12, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.active).size()); + assertEquals( 4, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed).size()); + assertEquals( 0, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.ready).size()); } // A new node is available @@ -300,11 +300,11 @@ public class NodeFailerTest { tester.runMaintainers(); // The node is now failed assertEquals( 3, tester.deployer.redeployments); - assertEquals(12, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.active).size()); - assertEquals( 5, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.failed).size()); - assertEquals( 0, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.ready).size()); + assertEquals(12, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.active).size()); + assertEquals( 5, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed).size()); + assertEquals( 0, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.ready).size()); assertTrue("The index of the last failed node is not reused", - tester.highestIndex(tester.nodeRepository.getNodes(NodeFailTester.app1, Node.State.active)).allocation().get().membership().index() + tester.highestIndex(tester.nodeRepository.nodes().getNodes(NodeFailTester.app1, Node.State.active)).allocation().get().membership().index() > lastNode.allocation().get().membership().index()); } @@ -312,31 +312,31 @@ public class NodeFailerTest { @Test public void re_activate_grace_period_test() { NodeFailTester tester = NodeFailTester.withTwoApplications(); - String downNode = tester.nodeRepository.getNodes(NodeFailTester.app1, Node.State.active).get(1).hostname(); + String downNode = tester.nodeRepository.nodes().getNodes(NodeFailTester.app1, Node.State.active).get(1).hostname(); tester.serviceMonitor.setHostDown(downNode); tester.allNodesMakeAConfigRequestExcept(); tester.runMaintainers(); - assertEquals(0, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.failed).size()); + assertEquals(0, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed).size()); tester.clock.advance(Duration.ofMinutes(75)); tester.allNodesMakeAConfigRequestExcept(); tester.runMaintainers(); - assertEquals(1, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.failed).size()); - assertEquals(Node.State.failed, tester.nodeRepository.getNode(downNode).get().state()); + assertEquals(1, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed).size()); + assertEquals(Node.State.failed, tester.nodeRepository.nodes().getNode(downNode).get().state()); // Re-activate the node. It is still down, but should not be failed out until the grace period has passed again - tester.nodeRepository.reactivate(downNode, Agent.system, getClass().getSimpleName()); + tester.nodeRepository.nodes().reactivate(downNode, Agent.system, getClass().getSimpleName()); tester.clock.advance(Duration.ofMinutes(30)); tester.allNodesMakeAConfigRequestExcept(); tester.runMaintainers(); - assertEquals(0, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.failed).size()); + assertEquals(0, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed).size()); tester.clock.advance(Duration.ofMinutes(45)); tester.allNodesMakeAConfigRequestExcept(); tester.runMaintainers(); - assertEquals(1, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.failed).size()); - assertEquals(Node.State.failed, tester.nodeRepository.getNode(downNode).get().state()); + assertEquals(1, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed).size()); + assertEquals(Node.State.failed, tester.nodeRepository.nodes().getNode(downNode).get().state()); } @Test @@ -349,7 +349,7 @@ public class NodeFailerTest { ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("test")).vespaVersion("6.42").build(); tester.activate(NodeFailTester.app1, cluster, capacity); - String downHost = tester.nodeRepository.getNodes(NodeFailTester.app1, Node.State.active).get(0).hostname(); + String downHost = tester.nodeRepository.nodes().getNodes(NodeFailTester.app1, Node.State.active).get(0).hostname(); tester.serviceMonitor.setHostDown(downHost); // nothing happens the first 45 minutes @@ -358,8 +358,8 @@ public class NodeFailerTest { tester.clock.advance(Duration.ofMinutes(5)); tester.allNodesMakeAConfigRequestExcept(); assertEquals(0, tester.deployer.redeployments); - assertEquals(3, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.active).size()); - assertEquals(0, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.failed).size()); + assertEquals(3, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.active).size()); + assertEquals(0, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed).size()); } // downHost should now be failed and replaced @@ -367,9 +367,9 @@ public class NodeFailerTest { tester.allNodesMakeAConfigRequestExcept(); tester.runMaintainers(); assertEquals(1, tester.deployer.redeployments); - assertEquals(1, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.failed).size()); - assertEquals(3, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.active).size()); - assertEquals(downHost, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.failed).get(0).hostname()); + assertEquals(1, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed).size()); + assertEquals(3, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.active).size()); + assertEquals(downHost, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed).get(0).hostname()); } @Test @@ -385,10 +385,10 @@ public class NodeFailerTest { tester.clock.advance(Duration.ofMinutes(interval)); tester.allNodesMakeAConfigRequestExcept(); tester.runMaintainers(); - assertEquals( 5, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.ready).size()); + assertEquals( 5, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.ready).size()); } - List<Node> ready = tester.nodeRepository.getNodes(NodeType.tenant, Node.State.ready); + List<Node> ready = tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.ready); // Two ready nodes and a ready docker node die, but only 2 of those are failed out tester.clock.advance(Duration.ofMinutes(180)); @@ -398,16 +398,16 @@ public class NodeFailerTest { .collect(Collectors.toList()); tester.allNodesMakeAConfigRequestExcept(otherNodes.get(0), otherNodes.get(2), dockerNode); tester.runMaintainers(); - assertEquals( 3, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.ready).size()); - assertEquals( 2, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.failed).size()); + assertEquals( 3, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.ready).size()); + assertEquals( 2, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed).size()); // Another ready node dies and the node that died earlier, are allowed to fail tester.clock.advance(Duration.ofDays(1)); tester.allNodesMakeAConfigRequestExcept(otherNodes.get(0), otherNodes.get(2), dockerNode, otherNodes.get(3)); tester.runMaintainers(); - assertEquals( 1, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.ready).size()); - assertEquals(otherNodes.get(1), tester.nodeRepository.getNodes(NodeType.tenant, Node.State.ready).get(0)); - assertEquals( 4, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.failed).size()); + assertEquals( 1, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.ready).size()); + assertEquals(otherNodes.get(1), tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.ready).get(0)); + assertEquals( 4, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed).size()); } @Test @@ -419,17 +419,17 @@ public class NodeFailerTest { tester.clock.advance(Duration.ofMinutes(interval)); tester.allNodesMakeAConfigRequestExcept(); tester.runMaintainers(); - assertEquals( 3, tester.nodeRepository.getNodes(NodeType.host, Node.State.ready).size()); - assertEquals( 0, tester.nodeRepository.getNodes(NodeType.host, Node.State.failed).size()); + assertEquals( 3, tester.nodeRepository.nodes().getNodes(NodeType.host, Node.State.ready).size()); + assertEquals( 0, tester.nodeRepository.nodes().getNodes(NodeType.host, Node.State.failed).size()); } // Two ready nodes and a ready docker node die, but only 2 of those are failed out tester.clock.advance(Duration.ofMinutes(180)); - Node dockerHost = tester.nodeRepository.getNodes(NodeType.host, Node.State.ready).iterator().next(); + Node dockerHost = tester.nodeRepository.nodes().getNodes(NodeType.host, Node.State.ready).iterator().next(); tester.allNodesMakeAConfigRequestExcept(dockerHost); tester.runMaintainers(); - assertEquals( 3, tester.nodeRepository.getNodes(NodeType.host, Node.State.ready).size()); - assertEquals( 0, tester.nodeRepository.getNodes(NodeType.host, Node.State.failed).size()); + assertEquals( 3, tester.nodeRepository.nodes().getNodes(NodeType.host, Node.State.ready).size()); + assertEquals( 0, tester.nodeRepository.nodes().getNodes(NodeType.host, Node.State.failed).size()); } @Test @@ -441,9 +441,9 @@ public class NodeFailerTest { tester.clock.advance(Duration.ofMinutes(interval)); tester.allNodesMakeAConfigRequestExcept(); tester.runMaintainers(); - assertEquals(8, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.active).size()); - assertEquals(13, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.ready).size()); - assertEquals(7, tester.nodeRepository.getNodes(NodeType.host, Node.State.active).size()); + assertEquals(8, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.active).size()); + assertEquals(13, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.ready).size()); + assertEquals(7, tester.nodeRepository.nodes().getNodes(NodeType.host, Node.State.active).size()); } @@ -457,9 +457,9 @@ public class NodeFailerTest { tester.clock.advance(Duration.ofMinutes(5)); tester.allNodesMakeAConfigRequestExcept(); assertEquals(0, tester.deployer.redeployments); - assertEquals(8, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.active).size()); - assertEquals(13, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.ready).size()); - assertEquals(7, tester.nodeRepository.getNodes(NodeType.host, Node.State.active).size()); + assertEquals(8, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.active).size()); + assertEquals(13, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.ready).size()); + assertEquals(7, tester.nodeRepository.nodes().getNodes(NodeType.host, Node.State.active).size()); } tester.clock.advance(Duration.ofMinutes(30)); @@ -467,14 +467,14 @@ public class NodeFailerTest { tester.runMaintainers(); assertEquals(2 + 1, tester.deployer.redeployments); - assertEquals(3, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.failed).size()); - assertEquals(8, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.active).size()); - assertEquals(10, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.ready).size()); - assertEquals(6, tester.nodeRepository.getNodes(NodeType.host, Node.State.active).size()); + assertEquals(3, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed).size()); + assertEquals(8, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.active).size()); + assertEquals(10, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.ready).size()); + assertEquals(6, tester.nodeRepository.nodes().getNodes(NodeType.host, Node.State.active).size()); // Now lets fail an active tenant node - Node downTenant1 = tester.nodeRepository.getNodes(NodeType.tenant, Node.State.active).get(0); + Node downTenant1 = tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.active).get(0); tester.serviceMonitor.setHostDown(downTenant1.hostname()); // nothing happens during the entire day because of the failure throttling @@ -482,7 +482,7 @@ public class NodeFailerTest { tester.runMaintainers(); tester.clock.advance(Duration.ofMinutes(interval)); tester.allNodesMakeAConfigRequestExcept(); - assertEquals(3 + 1, tester.nodeRepository.getNodes(Node.State.failed).size()); + assertEquals(3 + 1, tester.nodeRepository.nodes().getNodes(Node.State.failed).size()); } tester.clock.advance(Duration.ofMinutes(30)); @@ -490,10 +490,10 @@ public class NodeFailerTest { tester.runMaintainers(); assertEquals(3 + 1, tester.deployer.redeployments); - assertEquals(4, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.failed).size()); - assertEquals(8, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.active).size()); - assertEquals(9, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.ready).size()); - assertEquals(6, tester.nodeRepository.getNodes(NodeType.host, Node.State.active).size()); + assertEquals(4, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed).size()); + assertEquals(8, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.active).size()); + assertEquals(9, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.ready).size()); + assertEquals(6, tester.nodeRepository.nodes().getNodes(NodeType.host, Node.State.active).size()); // Lets fail another host, make sure it is not the same where downTenant1 is a child @@ -505,10 +505,10 @@ public class NodeFailerTest { tester.runMaintainers(); assertEquals(5 + 2, tester.deployer.redeployments); - assertEquals(7, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.failed).size()); - assertEquals(8, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.active).size()); - assertEquals(6, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.ready).size()); - assertEquals(5, tester.nodeRepository.getNodes(NodeType.host, Node.State.active).size()); + assertEquals(7, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed).size()); + assertEquals(8, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.active).size()); + assertEquals(6, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.ready).size()); + assertEquals(5, tester.nodeRepository.nodes().getNodes(NodeType.host, Node.State.active).size()); // We have only 5 hosts remaining, so if we fail another host, we should only be able to redeploy app1's // node, while app2's should remain @@ -520,10 +520,10 @@ public class NodeFailerTest { tester.runMaintainers(); assertEquals(6 + 2, tester.deployer.redeployments); - assertEquals(9, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.failed).size()); - assertEquals(8, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.active).size()); - assertEquals(4, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.ready).size()); - assertEquals(5, tester.nodeRepository.getNodes(NodeType.host, Node.State.active).size()); + assertEquals(9, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed).size()); + assertEquals(8, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.active).size()); + assertEquals(4, tester.nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.ready).size()); + assertEquals(5, tester.nodeRepository.nodes().getNodes(NodeType.host, Node.State.active).size()); } @Test @@ -545,7 +545,7 @@ public class NodeFailerTest { tester.clock.advance(Duration.ofMinutes(5)); tester.allNodesMakeAConfigRequestExcept(); - assertEquals(count, tester.nodeRepository.getNodes(nodeType, Node.State.active).size()); + assertEquals(count, tester.nodeRepository.nodes().getNodes(nodeType, Node.State.active).size()); } Set<String> downHosts = Set.of("host2", "host3"); @@ -558,7 +558,7 @@ public class NodeFailerTest { tester.clock.advance(Duration.ofMinutes(5)); tester.allNodesMakeAConfigRequestExcept(); assertEquals( 0, tester.deployer.redeployments); - assertEquals(count, tester.nodeRepository.getNodes(nodeType, Node.State.active).size()); + assertEquals(count, tester.nodeRepository.nodes().getNodes(nodeType, Node.State.active).size()); } tester.clock.advance(Duration.ofMinutes(60)); @@ -566,15 +566,15 @@ public class NodeFailerTest { // one down host should now be failed, but not two as we are only allowed to fail one proxy assertEquals(expectedFailCount, tester.deployer.redeployments); - assertEquals(count - expectedFailCount, tester.nodeRepository.getNodes(nodeType, Node.State.active).size()); - assertEquals(expectedFailCount, tester.nodeRepository.getNodes(nodeType, Node.State.failed).size()); - tester.nodeRepository.getNodes(nodeType, Node.State.failed) + assertEquals(count - expectedFailCount, tester.nodeRepository.nodes().getNodes(nodeType, Node.State.active).size()); + assertEquals(expectedFailCount, tester.nodeRepository.nodes().getNodes(nodeType, Node.State.failed).size()); + tester.nodeRepository.nodes().getNodes(nodeType, Node.State.failed) .forEach(node -> assertTrue(downHosts.contains(node.hostname()))); // trying to fail again will still not fail the other down host tester.clock.advance(Duration.ofMinutes(60)); tester.runMaintainers(); - assertEquals(count - expectedFailCount, tester.nodeRepository.getNodes(nodeType, Node.State.active).size()); + assertEquals(count - expectedFailCount, tester.nodeRepository.nodes().getNodes(nodeType, Node.State.active).size()); } @Test @@ -586,10 +586,10 @@ public class NodeFailerTest { tester.runMaintainers(); assertEquals(Node.State.ready, readyNode.state()); - tester.nodeRepository.write(readyNode.with(new Reports().withReport(badTotalMemorySizeReport)), () -> {}); + tester.nodeRepository.nodes().write(readyNode.with(new Reports().withReport(badTotalMemorySizeReport)), () -> {}); tester.runMaintainers(); - assertEquals(1, tester.nodeRepository.getNodes(Node.State.failed).size()); + assertEquals(1, tester.nodeRepository.nodes().getNodes(Node.State.failed).size()); } @Test @@ -599,7 +599,7 @@ public class NodeFailerTest { // 50 regular tenant nodes, 10 hosts with each 3 tenant nodes, total 90 nodes NodeFailTester tester = NodeFailTester.withTwoApplicationsOnDocker(10); List<Node> readyNodes = tester.createReadyNodes(50, 30); - List<Node> hosts = tester.nodeRepository.getNodes(NodeType.host); + List<Node> hosts = tester.nodeRepository.nodes().getNodes(NodeType.host); List<Node> deadNodes = readyNodes.subList(0, 4); // 2 hours pass, 4 physical nodes die @@ -610,7 +610,7 @@ public class NodeFailerTest { // 2 nodes are failed (the minimum amount that are always allowed to fail) tester.runMaintainers(); - assertEquals(2, tester.nodeRepository.getNodes(Node.State.failed).size()); + assertEquals(2, tester.nodeRepository.nodes().getNodes(Node.State.failed).size()); assertEquals("Throttling is indicated by the metric", 1, tester.metric.values.get(NodeFailer.throttlingActiveMetric)); assertEquals("Throttled node failures", 2, tester.metric.values.get(NodeFailer.throttledNodeFailuresMetric)); @@ -620,7 +620,7 @@ public class NodeFailerTest { tester.allNodesMakeAConfigRequestExcept(deadNodes); } tester.runMaintainers(); - assertEquals(2, tester.nodeRepository.getNodes(Node.State.failed).size()); + assertEquals(2, tester.nodeRepository.nodes().getNodes(Node.State.failed).size()); assertEquals("Throttling is indicated by the metric", 1, tester.metric.values.get(NodeFailer.throttlingActiveMetric)); assertEquals("Throttled node failures", 2, tester.metric.values.get(NodeFailer.throttledNodeFailuresMetric)); @@ -630,7 +630,7 @@ public class NodeFailerTest { tester.allNodesMakeAConfigRequestExcept(deadNodes); } tester.runMaintainers(); - assertEquals(4, tester.nodeRepository.getNodes(Node.State.failed).size()); + assertEquals(4, tester.nodeRepository.nodes().getNodes(Node.State.failed).size()); // 24 more hours pass, nothing happens for (int minutes = 0, interval = 30; minutes < 24 * 60; minutes += interval) { @@ -652,7 +652,7 @@ public class NodeFailerTest { assertEquals(4 + /* already failed */ 2 + /* hosts */ (2 * 3) /* containers per host */, - tester.nodeRepository.getNodes(Node.State.failed).size()); + tester.nodeRepository.nodes().getNodes(Node.State.failed).size()); assertEquals("Throttling is indicated by the metric", 1, tester.metric.values.get(NodeFailer.throttlingActiveMetric)); assertEquals("Throttled host failures", 1, tester.metric.values.get(NodeFailer.throttledHostFailuresMetric)); @@ -662,14 +662,14 @@ public class NodeFailerTest { tester.allNodesMakeAConfigRequestExcept(deadNodes); } tester.runMaintainers(); - assertEquals(12, tester.nodeRepository.getNodes(Node.State.failed).size()); + assertEquals(12, tester.nodeRepository.nodes().getNodes(Node.State.failed).size()); assertEquals("Throttling is indicated by the metric", 1, tester.metric.values.get(NodeFailer.throttlingActiveMetric)); assertEquals("Throttled host failures", 1, tester.metric.values.get(NodeFailer.throttledHostFailuresMetric)); // The final host and its containers are failed out tester.clock.advance(Duration.ofMinutes(30)); tester.runMaintainers(); - assertEquals(16, tester.nodeRepository.getNodes(Node.State.failed).size()); + assertEquals(16, tester.nodeRepository.nodes().getNodes(Node.State.failed).size()); assertEquals("Throttling is not indicated by the metric, as no throttled attempt is made", 0, tester.metric.values.get(NodeFailer.throttlingActiveMetric)); assertEquals("No throttled node failures", 0, tester.metric.values.get(NodeFailer.throttledNodeFailuresMetric)); @@ -677,7 +677,7 @@ public class NodeFailerTest { tester.clock.advance(Duration.ofHours(25)); tester.allNodesMakeAConfigRequestExcept(deadNodes); tester.runMaintainers(); - assertEquals(16, tester.nodeRepository.getNodes(Node.State.failed).size()); + assertEquals(16, tester.nodeRepository.nodes().getNodes(Node.State.failed).size()); assertEquals("Throttling is not indicated by the metric", 0, tester.metric.values.get(NodeFailer.throttlingActiveMetric)); assertEquals("No throttled node failures", 0, tester.metric.values.get(NodeFailer.throttledNodeFailuresMetric)); } @@ -695,7 +695,7 @@ public class NodeFailerTest { } tester.runMaintainers(); // 2% are allowed to fail - assertEquals(10, tester.nodeRepository.getNodes(Node.State.failed).size()); + assertEquals(10, tester.nodeRepository.nodes().getNodes(Node.State.failed).size()); assertEquals("Throttling is indicated by the metric.", 1, tester.metric.values.get(NodeFailer.throttlingActiveMetric)); assertEquals("Throttled node failures", 5, tester.metric.values.get(NodeFailer.throttledNodeFailuresMetric)); @@ -705,7 +705,7 @@ public class NodeFailerTest { tester.allNodesMakeAConfigRequestExcept(deadNodes); } tester.runMaintainers(); - assertEquals(10, tester.nodeRepository.getNodes(Node.State.failed).size()); + assertEquals(10, tester.nodeRepository.nodes().getNodes(Node.State.failed).size()); assertEquals("Throttling is indicated by the metric.", 1, tester.metric.values.get(NodeFailer.throttlingActiveMetric)); assertEquals("Throttled node failures", 5, tester.metric.values.get(NodeFailer.throttledNodeFailuresMetric)); @@ -715,7 +715,7 @@ public class NodeFailerTest { tester.allNodesMakeAConfigRequestExcept(deadNodes); } tester.runMaintainers(); - assertEquals(15, tester.nodeRepository.getNodes(Node.State.failed).size()); + assertEquals(15, tester.nodeRepository.nodes().getNodes(Node.State.failed).size()); assertEquals("Throttling is not indicated by the metric, as no throttled attempt is made.", 0, tester.metric.values.get(NodeFailer.throttlingActiveMetric)); assertEquals("No throttled node failures", 0, tester.metric.values.get(NodeFailer.throttledNodeFailuresMetric)); } @@ -758,7 +758,7 @@ public class NodeFailerTest { */ private static String selectFirstParentHostWithNActiveNodesExcept(NodeRepository nodeRepository, int n, String... except) { Set<String> exceptSet = Arrays.stream(except).collect(Collectors.toSet()); - return nodeRepository.getNodes(NodeType.tenant, Node.State.active).stream() + return nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.active).stream() .collect(Collectors.groupingBy(Node::parentHostname)) .entrySet().stream() .filter(entry -> entry.getValue().size() == n) diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooterTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooterTest.java index 2abe5ed7ebf..b9f3985172b 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooterTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooterTest.java @@ -94,7 +94,7 @@ public class NodeRebooterTest { while (true) { rebooter.maintain(); simulateReboot(nodeRepository); - List<Node> nodes = nodeRepository.getNodes(NodeType.host, Node.State.ready); + List<Node> nodes = nodeRepository.nodes().getNodes(NodeType.host, Node.State.ready); int count = withCurrentRebootGeneration(1L, nodes).size(); if (count == 2) { break; @@ -103,7 +103,7 @@ public class NodeRebooterTest { } private void assertReadyHosts(int expectedCount, NodeRepository nodeRepository, long generation) { - List<Node> nodes = nodeRepository.getNodes(NodeType.host, Node.State.ready); + List<Node> nodes = nodeRepository.nodes().getNodes(NodeType.host, Node.State.ready); assertEquals(expectedCount, withCurrentRebootGeneration(generation, nodes).size()); } @@ -113,10 +113,10 @@ public class NodeRebooterTest { /** Set current reboot generation to the wanted reboot generation whenever it is larger (i.e record a reboot) */ private void simulateReboot(NodeRepository nodeRepository) { - for (Node node : nodeRepository.getNodes(Node.State.ready, Node.State.active)) { + for (Node node : nodeRepository.nodes().getNodes(Node.State.ready, Node.State.active)) { if (node.status().reboot().wanted() > node.status().reboot().current()) - nodeRepository.write(node.withCurrentRebootGeneration(node.status().reboot().wanted(), - nodeRepository.clock().instant()), () -> {}); + nodeRepository.nodes().write(node.withCurrentRebootGeneration(node.status().reboot().wanted(), + nodeRepository.clock().instant()), () -> {}); } } @@ -129,10 +129,10 @@ public class NodeRebooterTest { private void simulateOsUpgrade(NodeRepository nodeRepository) { var wantedOsVersion = nodeRepository.osVersions().targetFor(NodeType.host); if (wantedOsVersion.isEmpty()) return; - for (Node node : nodeRepository.getNodes(Node.State.ready, Node.State.active)) { + for (Node node : nodeRepository.nodes().getNodes(Node.State.ready, Node.State.active)) { if (wantedOsVersion.get().isAfter(node.status().osVersion().current().orElse(Version.emptyVersion))) - nodeRepository.write(node.withCurrentOsVersion(wantedOsVersion.get(), nodeRepository.clock().instant()), - () -> {}); + nodeRepository.nodes().write(node.withCurrentOsVersion(wantedOsVersion.get(), nodeRepository.clock().instant()), + () -> {}); } } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OperatorChangeApplicationMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OperatorChangeApplicationMaintainerTest.java index 9d58c30a2c6..f331f3bcb4a 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OperatorChangeApplicationMaintainerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OperatorChangeApplicationMaintainerTest.java @@ -51,19 +51,19 @@ public class OperatorChangeApplicationMaintainerTest { maintainer.maintain(); assertEquals("No changes -> no redeployments", 3, fixture.deployer.redeployments); - nodeRepository.fail(nodeRepository.getNodes(fixture.app1).get(3).hostname(), Agent.system, "Failing to unit test"); + nodeRepository.nodes().fail(nodeRepository.nodes().getNodes(fixture.app1).get(3).hostname(), Agent.system, "Failing to unit test"); clock.advance(Duration.ofMinutes(2)); maintainer.maintain(); assertEquals("System change -> no redeployments", 3, fixture.deployer.redeployments); clock.advance(Duration.ofSeconds(1)); - nodeRepository.fail(nodeRepository.getNodes(fixture.app2).get(4).hostname(), Agent.operator, "Manual node failing"); + nodeRepository.nodes().fail(nodeRepository.nodes().getNodes(fixture.app2).get(4).hostname(), Agent.operator, "Manual node failing"); clock.advance(Duration.ofMinutes(2)); maintainer.maintain(); assertEquals("Operator change -> redeployment", 4, fixture.deployer.redeployments); clock.advance(Duration.ofSeconds(1)); - nodeRepository.fail(nodeRepository.getNodes(fixture.app3).get(1).hostname(), Agent.operator, "Manual node failing"); + nodeRepository.nodes().fail(nodeRepository.nodes().getNodes(fixture.app3).get(1).hostname(), Agent.operator, "Manual node failing"); clock.advance(Duration.ofMinutes(2)); maintainer.maintain(); assertEquals("Operator change -> redeployment", 5, fixture.deployer.redeployments); @@ -104,9 +104,9 @@ public class OperatorChangeApplicationMaintainerTest { deployer.deployFromLocalActive(app1, false).get().activate(); deployer.deployFromLocalActive(app2, false).get().activate(); deployer.deployFromLocalActive(app3, false).get().activate(); - assertEquals(wantedNodesApp1, nodeRepository.getNodes(app1, Node.State.active).size()); - assertEquals(wantedNodesApp2, nodeRepository.getNodes(app2, Node.State.active).size()); - assertEquals(wantedNodesApp3, nodeRepository.getNodes(app3, Node.State.active).size()); + assertEquals(wantedNodesApp1, nodeRepository.nodes().getNodes(app1, Node.State.active).size()); + assertEquals(wantedNodesApp2, nodeRepository.nodes().getNodes(app2, Node.State.active).size()); + assertEquals(wantedNodesApp3, nodeRepository.nodes().getNodes(app3, Node.State.active).size()); } } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OsUpgradeActivatorTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OsUpgradeActivatorTest.java index f795dbaaa1c..36452e05bb6 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OsUpgradeActivatorTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OsUpgradeActivatorTest.java @@ -76,7 +76,7 @@ public class OsUpgradeActivatorTest { assertFalse("OS version " + osVersion0 + " is inactive", isOsVersionActive(NodeType.host)); // One tenant host fails and is no longer considered - tester.nodeRepository().fail(tenantHostNodes.get(0).hostname(), Agent.system, this.getClass().getSimpleName()); + tester.nodeRepository().nodes().fail(tenantHostNodes.get(0).hostname(), Agent.system, this.getClass().getSimpleName()); // Remaining hosts complete their Vespa upgrade var healthyTenantHostNodes = tenantHostNodes.subList(1, tenantHostNodes.size()); @@ -91,7 +91,7 @@ public class OsUpgradeActivatorTest { private boolean isOsVersionActive(NodeType... types) { var active = true; for (var type : types) { - active &= tester.nodeRepository().list().nodeType(type).changingOsVersion().size() > 0; + active &= tester.nodeRepository().nodes().list().nodeType(type).changingOsVersion().size() > 0; } return active; } @@ -103,7 +103,7 @@ public class OsUpgradeActivatorTest { private Stream<Node> streamUpdatedNodes(List<Node> nodes) { Stream<Node> stream = Stream.empty(); for (var node : nodes) { - stream = Stream.concat(stream, tester.nodeRepository().getNode(node.hostname()).stream()); + stream = Stream.concat(stream, tester.nodeRepository().nodes().getNode(node.hostname()).stream()); } return stream; } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java index ae1e36d73dd..1f1e6a79317 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java @@ -64,32 +64,32 @@ public class PeriodicApplicationMaintainerTest { fixture.setBootstrapping(false); // Fail and park some nodes - nodeRepository.fail(nodeRepository.getNodes(fixture.app1).get(3).hostname(), Agent.system, "Failing to unit test"); - nodeRepository.fail(nodeRepository.getNodes(fixture.app2).get(0).hostname(), Agent.system, "Failing to unit test"); - nodeRepository.park(nodeRepository.getNodes(fixture.app2).get(4).hostname(), true, Agent.system, "Parking to unit test"); + nodeRepository.nodes().fail(nodeRepository.nodes().getNodes(fixture.app1).get(3).hostname(), Agent.system, "Failing to unit test"); + nodeRepository.nodes().fail(nodeRepository.nodes().getNodes(fixture.app2).get(0).hostname(), Agent.system, "Failing to unit test"); + nodeRepository.nodes().park(nodeRepository.nodes().getNodes(fixture.app2).get(4).hostname(), true, Agent.system, "Parking to unit test"); int failedInApp1 = 1; int failedOrParkedInApp2 = 2; - assertEquals(fixture.wantedNodesApp1 - failedInApp1, nodeRepository.getNodes(fixture.app1, Node.State.active).size()); - assertEquals(fixture.wantedNodesApp2 - failedOrParkedInApp2, nodeRepository.getNodes(fixture.app2, Node.State.active).size()); - assertEquals(failedInApp1 + failedOrParkedInApp2, nodeRepository.getNodes(NodeType.tenant, Node.State.failed, Node.State.parked).size()); - assertEquals(3, nodeRepository.getNodes(NodeType.tenant, Node.State.ready).size()); - assertEquals(2, nodeRepository.getNodes(NodeType.host, Node.State.ready).size()); + assertEquals(fixture.wantedNodesApp1 - failedInApp1, nodeRepository.nodes().getNodes(fixture.app1, Node.State.active).size()); + assertEquals(fixture.wantedNodesApp2 - failedOrParkedInApp2, nodeRepository.nodes().getNodes(fixture.app2, Node.State.active).size()); + assertEquals(failedInApp1 + failedOrParkedInApp2, nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed, Node.State.parked).size()); + assertEquals(3, nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.ready).size()); + assertEquals(2, nodeRepository.nodes().getNodes(NodeType.host, Node.State.ready).size()); // Cause maintenance deployment which will allocate replacement nodes fixture.runApplicationMaintainer(); - assertEquals(fixture.wantedNodesApp1, nodeRepository.getNodes(fixture.app1, Node.State.active).size()); - assertEquals(fixture.wantedNodesApp2, nodeRepository.getNodes(fixture.app2, Node.State.active).size()); - assertEquals(0, nodeRepository.getNodes(NodeType.tenant, Node.State.ready).size()); + assertEquals(fixture.wantedNodesApp1, nodeRepository.nodes().getNodes(fixture.app1, Node.State.active).size()); + assertEquals(fixture.wantedNodesApp2, nodeRepository.nodes().getNodes(fixture.app2, Node.State.active).size()); + assertEquals(0, nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.ready).size()); // Reactivate the previously failed nodes - nodeRepository.reactivate(nodeRepository.getNodes(NodeType.tenant, Node.State.failed).get(0).hostname(), Agent.system, getClass().getSimpleName()); - nodeRepository.reactivate(nodeRepository.getNodes(NodeType.tenant, Node.State.failed).get(0).hostname(), Agent.system, getClass().getSimpleName()); - nodeRepository.reactivate(nodeRepository.getNodes(NodeType.tenant, Node.State.parked).get(0).hostname(), Agent.system, getClass().getSimpleName()); + nodeRepository.nodes().reactivate(nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed).get(0).hostname(), Agent.system, getClass().getSimpleName()); + nodeRepository.nodes().reactivate(nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed).get(0).hostname(), Agent.system, getClass().getSimpleName()); + nodeRepository.nodes().reactivate(nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.parked).get(0).hostname(), Agent.system, getClass().getSimpleName()); int reactivatedInApp1 = 1; int reactivatedInApp2 = 2; - assertEquals(0, nodeRepository.getNodes(NodeType.tenant, Node.State.failed).size()); - assertEquals(fixture.wantedNodesApp1 + reactivatedInApp1, nodeRepository.getNodes(fixture.app1, Node.State.active).size()); - assertEquals(fixture.wantedNodesApp2 + reactivatedInApp2, nodeRepository.getNodes(fixture.app2, Node.State.active).size()); + assertEquals(0, nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed).size()); + assertEquals(fixture.wantedNodesApp1 + reactivatedInApp1, nodeRepository.nodes().getNodes(fixture.app1, Node.State.active).size()); + assertEquals(fixture.wantedNodesApp2 + reactivatedInApp2, nodeRepository.nodes().getNodes(fixture.app2, Node.State.active).size()); assertEquals("The reactivated nodes are now active but not part of the application", 0, fixture.getNodes(Node.State.active).retired().size()); @@ -108,17 +108,17 @@ public class PeriodicApplicationMaintainerTest { fixture.activate(); // Freeze active nodes to simulate an application being deleted during a maintenance run - List<Node> frozenActiveNodes = nodeRepository.getNodes(Node.State.active); + List<Node> frozenActiveNodes = nodeRepository.nodes().getNodes(Node.State.active); // Remove one application without letting the application maintainer know about it fixture.remove(fixture.app2); - assertEquals(fixture.wantedNodesApp2, nodeRepository.getNodes(fixture.app2, Node.State.inactive).size()); + assertEquals(fixture.wantedNodesApp2, nodeRepository.nodes().getNodes(fixture.app2, Node.State.inactive).size()); // Nodes belonging to app2 are inactive after maintenance fixture.maintainer.setOverriddenNodesNeedingMaintenance(frozenActiveNodes); fixture.runApplicationMaintainer(); assertEquals("Inactive nodes were incorrectly activated after maintenance", fixture.wantedNodesApp2, - nodeRepository.getNodes(fixture.app2, Node.State.inactive).size()); + nodeRepository.nodes().getNodes(fixture.app2, Node.State.inactive).size()); } @Test(timeout = 60_000) @@ -232,8 +232,8 @@ public class PeriodicApplicationMaintainerTest { void activate() { deployer.deployFromLocalActive(app1, false).get().activate(); deployer.deployFromLocalActive(app2, false).get().activate(); - assertEquals(wantedNodesApp1, nodeRepository.getNodes(app1, Node.State.active).size()); - assertEquals(wantedNodesApp2, nodeRepository.getNodes(app2, Node.State.active).size()); + assertEquals(wantedNodesApp1, nodeRepository.nodes().getNodes(app1, Node.State.active).size()); + assertEquals(wantedNodesApp2, nodeRepository.nodes().getNodes(app2, Node.State.active).size()); } void remove(ApplicationId application) { @@ -250,7 +250,7 @@ public class PeriodicApplicationMaintainerTest { } NodeList getNodes(Node.State ... states) { - return NodeList.copyOf(nodeRepository.getNodes(NodeType.tenant, states)); + return NodeList.copyOf(nodeRepository.nodes().getNodes(NodeType.tenant, states)); } void setBootstrapping(boolean bootstrapping) { diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RebalancerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RebalancerTest.java index 21003324696..bc2676c0acf 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RebalancerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RebalancerTest.java @@ -68,7 +68,7 @@ public class RebalancerTest { // --- Deploying a mem heavy application - allocated to the best option and causing increased skew tester.deployApp(memoryApp); assertEquals("Assigned to a flat node as that causes least skew", "flat", - tester.nodeRepository().list().parentOf(tester.getNode(memoryApp)).get().flavor().name()); + tester.nodeRepository().nodes().list().parentOf(tester.getNode(memoryApp)).get().flavor().name()); tester.maintain(); assertEquals("Deploying the mem skewed app increased skew", 0.00734, tester.metric().values.get("hostedVespa.docker.skew").doubleValue(), 0.00001); @@ -83,8 +83,8 @@ public class RebalancerTest { // --- Making the system stable enables rebalancing NestedTransaction tx = new NestedTransaction(); - tester.nodeRepository().deactivate(List.of(cpuSkewedNode), - new ApplicationTransaction(new ProvisionLock(cpuApp, () -> {}), tx)); + tester.nodeRepository().nodes().deactivate(List.of(cpuSkewedNode), + new ApplicationTransaction(new ProvisionLock(cpuApp, () -> {}), tx)); tx.commit(); // ... if activation fails when trying, we clean up the state @@ -93,8 +93,8 @@ public class RebalancerTest { assertTrue("Want to retire is reset", tester.getNodes(Node.State.active).stream().noneMatch(node -> node.status().wantToRetire())); assertEquals("Reserved node was moved to dirty", 1, tester.getNodes(Node.State.dirty).size()); String reservedHostname = tester.getNodes(Node.State.dirty).get(0).hostname(); - tester.nodeRepository().setReady(reservedHostname, Agent.system, "Cleanup"); - tester.nodeRepository().removeRecursively(reservedHostname); + tester.nodeRepository().nodes().setReady(reservedHostname, Agent.system, "Cleanup"); + tester.nodeRepository().nodes().removeRecursively(reservedHostname); // ... otherwise we successfully rebalance, again reducing skew tester.deployer().setFailActivate(false); @@ -176,18 +176,18 @@ public class RebalancerTest { } List<Node> getNodes(ApplicationId applicationId, Node.State nodeState) { - return tester.nodeRepository().getNodes(applicationId, nodeState); + return tester.nodeRepository().nodes().getNodes(applicationId, nodeState); } boolean isNodeRetired(Node node) { return getNode(node.hostname()).get().allocation().get().membership().retired(); } - Optional<Node> getNode(String hostname) { return tester.nodeRepository().getNode(hostname); } + Optional<Node> getNode(String hostname) { return tester.nodeRepository().nodes().getNode(hostname); } - List<Node> getNodes(Node.State nodeState) { return tester.nodeRepository().getNodes(nodeState); } + List<Node> getNodes(Node.State nodeState) { return tester.nodeRepository().nodes().getNodes(nodeState); } - Node getNode(ApplicationId applicationId) { return tester.nodeRepository().getNodes(applicationId).get(0); } + Node getNode(ApplicationId applicationId) { return tester.nodeRepository().nodes().getNodes(applicationId).get(0); } ManualClock clock() { return tester.clock(); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ReservationExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ReservationExpirerTest.java index 4d29343214e..5b67c7bc358 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ReservationExpirerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ReservationExpirerTest.java @@ -40,19 +40,19 @@ public class ReservationExpirerTest { tester.makeReadyHosts(1, hostResources); // Reserve 2 nodes - assertEquals(2, nodeRepository.getNodes(NodeType.tenant, Node.State.ready).size()); + assertEquals(2, nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.ready).size()); ApplicationId applicationId = new ApplicationId.Builder().tenant("foo").applicationName("bar").instanceName("fuz").build(); ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("test")).vespaVersion("6.42").build(); tester.provisioner().prepare(applicationId, cluster, Capacity.from(new ClusterResources(2, 1, nodeResources)), null); - assertEquals(2, nodeRepository.getNodes(NodeType.tenant, Node.State.reserved).size()); + assertEquals(2, nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.reserved).size()); // Reservation times out clock.advance(Duration.ofMinutes(14)); // Reserved but not used time out new ReservationExpirer(nodeRepository, Duration.ofMinutes(10), metric).run(); // Assert nothing is reserved - assertEquals(0, nodeRepository.getNodes(NodeType.tenant, Node.State.reserved).size()); - List<Node> dirty = nodeRepository.getNodes(NodeType.tenant, Node.State.dirty); + assertEquals(0, nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.reserved).size()); + List<Node> dirty = nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.dirty); assertEquals(2, dirty.size()); assertFalse(dirty.get(0).allocation().isPresent()); assertFalse(dirty.get(1).allocation().isPresent()); 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 952f52c44e0..fa492c3a3e9 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 @@ -71,8 +71,8 @@ public class RetiredExpirerTest { activate(applicationId, cluster, wantedNodes=7, 1); activate(applicationId, cluster, wantedNodes=2, 1); activate(applicationId, cluster, wantedNodes=3, 1); - assertEquals(7, nodeRepository.getNodes(applicationId, Node.State.active).size()); - assertEquals(0, nodeRepository.getNodes(applicationId, Node.State.inactive).size()); + assertEquals(7, nodeRepository.nodes().getNodes(applicationId, Node.State.active).size()); + assertEquals(0, nodeRepository.nodes().getNodes(applicationId, Node.State.inactive).size()); // Cause inactivation of retired nodes clock.advance(Duration.ofHours(30)); // Retire period spent @@ -83,12 +83,12 @@ public class RetiredExpirerTest { cluster, Capacity.from(new ClusterResources(wantedNodes, 1, nodeResources))))); createRetiredExpirer(deployer).run(); - assertEquals(3, nodeRepository.getNodes(applicationId, Node.State.active).size()); - assertEquals(4, nodeRepository.getNodes(applicationId, Node.State.inactive).size()); + assertEquals(3, nodeRepository.nodes().getNodes(applicationId, Node.State.active).size()); + assertEquals(4, nodeRepository.nodes().getNodes(applicationId, Node.State.inactive).size()); assertEquals(1, deployer.redeployments); // inactivated nodes are not retired - for (Node node : nodeRepository.getNodes(applicationId, Node.State.inactive)) + for (Node node : nodeRepository.nodes().getNodes(applicationId, Node.State.inactive)) assertFalse(node.allocation().get().membership().retired()); } @@ -106,8 +106,8 @@ public class RetiredExpirerTest { activate(applicationId, cluster, wantedNodes=7, 1); activate(applicationId, cluster, wantedNodes=2, 1); activate(applicationId, cluster, wantedNodes=3, 1); - assertEquals(7, nodeRepository.getNodes(applicationId, Node.State.active).size()); - assertEquals(0, nodeRepository.getNodes(applicationId, Node.State.inactive).size()); + assertEquals(7, nodeRepository.nodes().getNodes(applicationId, Node.State.active).size()); + assertEquals(0, nodeRepository.nodes().getNodes(applicationId, Node.State.inactive).size()); // Cause inactivation of retired nodes MockDeployer deployer = @@ -128,27 +128,27 @@ public class RetiredExpirerTest { RetiredExpirer retiredExpirer = createRetiredExpirer(deployer); retiredExpirer.run(); - assertEquals(5, nodeRepository.getNodes(applicationId, Node.State.active).size()); - assertEquals(2, nodeRepository.getNodes(applicationId, Node.State.inactive).size()); + assertEquals(5, nodeRepository.nodes().getNodes(applicationId, Node.State.active).size()); + assertEquals(2, nodeRepository.nodes().getNodes(applicationId, Node.State.inactive).size()); assertEquals(1, deployer.redeployments); verify(orchestrator, times(4)).acquirePermissionToRemove(any()); // Running it again has no effect retiredExpirer.run(); - assertEquals(5, nodeRepository.getNodes(applicationId, Node.State.active).size()); - assertEquals(2, nodeRepository.getNodes(applicationId, Node.State.inactive).size()); + assertEquals(5, nodeRepository.nodes().getNodes(applicationId, Node.State.active).size()); + assertEquals(2, nodeRepository.nodes().getNodes(applicationId, Node.State.inactive).size()); assertEquals(1, deployer.redeployments); verify(orchestrator, times(6)).acquirePermissionToRemove(any()); clock.advance(RETIRED_EXPIRATION.plusMinutes(1)); retiredExpirer.run(); - assertEquals(3, nodeRepository.getNodes(applicationId, Node.State.active).size()); - assertEquals(4, nodeRepository.getNodes(applicationId, Node.State.inactive).size()); + assertEquals(3, nodeRepository.nodes().getNodes(applicationId, Node.State.active).size()); + assertEquals(4, nodeRepository.nodes().getNodes(applicationId, Node.State.inactive).size()); assertEquals(2, deployer.redeployments); verify(orchestrator, times(6)).acquirePermissionToRemove(any()); // inactivated nodes are not retired - for (Node node : nodeRepository.getNodes(applicationId, Node.State.inactive)) + for (Node node : nodeRepository.nodes().getNodes(applicationId, Node.State.inactive)) assertFalse(node.allocation().get().membership().retired()); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java index aac9122f8ab..4d334147212 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java @@ -114,14 +114,14 @@ public class ScalingSuggestionsMaintainerTest { } private boolean shouldSuggest(ApplicationId app, ClusterSpec cluster, ProvisioningTester tester) { - var currentResources = tester.nodeRepository().list(app).cluster(cluster.id()).not().retired().toResources(); + var currentResources = tester.nodeRepository().nodes().list(app).cluster(cluster.id()).not().retired().toResources(); return tester.nodeRepository().applications().get(app).get().cluster(cluster.id()).get() .shouldSuggestResources(currentResources); } public void addMeasurements(float cpu, float memory, float disk, int generation, int count, ApplicationId applicationId, NodeRepository nodeRepository, MetricsDb db) { - List<Node> nodes = nodeRepository.getNodes(applicationId, Node.State.active); + List<Node> nodes = nodeRepository.nodes().getNodes(applicationId, Node.State.active); for (int i = 0; i < count; i++) { for (Node node : nodes) db.add(List.of(new Pair<>(node.hostname(), new MetricSnapshot(nodeRepository.clock().instant(), 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 e276ea22ea2..1c7b24ba783 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 @@ -47,7 +47,7 @@ public class SpareCapacityMaintainerTest { var tester = new SpareCapacityMaintainerTester(); tester.maintainer.maintain(); assertEquals(0, tester.deployer.redeployments); - assertEquals(0, tester.nodeRepository.list().retired().size()); + assertEquals(0, tester.nodeRepository.nodes().list().retired().size()); } @Test @@ -57,7 +57,7 @@ public class SpareCapacityMaintainerTest { tester.addNodes(0, 1, new NodeResources(10, 100, 1000, 1), 0); tester.maintainer.maintain(); assertEquals(0, tester.deployer.redeployments); - assertEquals(0, tester.nodeRepository.list().retired().size()); + assertEquals(0, tester.nodeRepository.nodes().list().retired().size()); assertEquals(1, tester.metric.values.get("spareHostCapacity")); } @@ -68,7 +68,7 @@ public class SpareCapacityMaintainerTest { tester.addNodes(0, 1, new NodeResources(10, 100, 1000, 1), 0); tester.maintainer.maintain(); assertEquals(0, tester.deployer.redeployments); - assertEquals(0, tester.nodeRepository.list().retired().size()); + assertEquals(0, tester.nodeRepository.nodes().list().retired().size()); assertEquals(2, tester.metric.values.get("spareHostCapacity")); } @@ -79,7 +79,7 @@ public class SpareCapacityMaintainerTest { tester.addNodes(0, 2, new NodeResources(10, 100, 1000, 1), 0); tester.maintainer.maintain(); assertEquals(0, tester.deployer.redeployments); - assertEquals(0, tester.nodeRepository.list().retired().size()); + assertEquals(0, tester.nodeRepository.nodes().list().retired().size()); assertEquals(0, tester.metric.values.get("spareHostCapacity")); } @@ -91,7 +91,7 @@ public class SpareCapacityMaintainerTest { tester.addNodes(1, 2, new NodeResources(5, 50, 500, 0.5), 2); tester.maintainer.maintain(); assertEquals(0, tester.deployer.redeployments); - assertEquals(0, tester.nodeRepository.list().retired().size()); + assertEquals(0, tester.nodeRepository.nodes().list().retired().size()); assertEquals(2, tester.metric.values.get("spareHostCapacity")); } @@ -105,13 +105,13 @@ public class SpareCapacityMaintainerTest { tester.addNodes(2, 2, new NodeResources(5, 50, 500, 0.5), 4); tester.maintainer.maintain(); assertEquals(1, tester.deployer.redeployments); - assertEquals(1, tester.nodeRepository.list().retired().size()); + assertEquals(1, tester.nodeRepository.nodes().list().retired().size()); assertEquals(1, tester.metric.values.get("spareHostCapacity")); // Maintaining again is a no-op since the node to move is already retired tester.maintainer.maintain(); assertEquals(1, tester.deployer.redeployments); - assertEquals(1, tester.nodeRepository.list().retired().size()); + assertEquals(1, tester.nodeRepository.nodes().list().retired().size()); assertEquals(1, tester.metric.values.get("spareHostCapacity")); } @@ -128,7 +128,7 @@ public class SpareCapacityMaintainerTest { tester.addNodes(3, 2, new NodeResources(5, 50, 500, 0.5), 6); tester.maintainer.maintain(); assertEquals(1, tester.deployer.redeployments); - assertEquals(1, tester.nodeRepository.list().retired().size()); + assertEquals(1, tester.nodeRepository.nodes().list().retired().size()); assertEquals(1, tester.metric.values.get("spareHostCapacity")); } @@ -141,7 +141,7 @@ public class SpareCapacityMaintainerTest { tester.maintainer.maintain(); assertEquals(1, tester.deployer.redeployments); - assertEquals(1, tester.nodeRepository.list().retired().size()); + assertEquals(1, tester.nodeRepository.nodes().list().retired().size()); assertEquals(1, tester.metric.values.get("spareHostCapacity")); } @@ -152,7 +152,7 @@ public class SpareCapacityMaintainerTest { tester.maintainer.maintain(); assertEquals(0, tester.deployer.redeployments); - assertEquals(0, tester.nodeRepository.list().retired().size()); + assertEquals(0, tester.nodeRepository.nodes().list().retired().size()); assertEquals(0, tester.metric.values.get("spareHostCapacity")); } @@ -195,7 +195,7 @@ public class SpareCapacityMaintainerTest { tester.maintainer.maintain(); assertEquals(0, tester.deployer.redeployments); - assertEquals(0, tester.nodeRepository.list().retired().size()); + assertEquals(0, tester.nodeRepository.nodes().list().retired().size()); assertEquals(0, tester.metric.values.get("spareHostCapacity")); } @@ -212,7 +212,7 @@ public class SpareCapacityMaintainerTest { tester.maintainer.maintain(); assertEquals(2, tester.metric.values.get("overcommittedHosts")); assertEquals(1, tester.deployer.redeployments); - assertEquals(List.of(new NodeResources( 1.1, 10, 100, 0.1)), tester.nodeRepository.list().retired().mapToList(Node::resources)); + assertEquals(List.of(new NodeResources( 1.1, 10, 100, 0.1)), tester.nodeRepository.nodes().list().retired().mapToList(Node::resources)); } /** Microbenchmark */ @@ -235,7 +235,7 @@ public class SpareCapacityMaintainerTest { long totalTime = System.currentTimeMillis() - startTime; System.out.println("Complete in " + ( totalTime / 1000) + " seconds"); assertEquals(0, tester.deployer.redeployments); - assertEquals(0, tester.nodeRepository.list().retired().size()); + assertEquals(0, tester.nodeRepository.nodes().list().retired().size()); assertEquals(0, tester.metric.values.get("spareHostCapacity")); } @@ -304,16 +304,16 @@ public class SpareCapacityMaintainerTest { } private void allocate(ApplicationId application, ClusterSpec clusterSpec, List<Node> nodes) { - nodes = nodeRepository.addNodes(nodes, Agent.system); + nodes = nodeRepository.nodes().addNodes(nodes, Agent.system); for (int i = 0; i < nodes.size(); i++) { Node node = nodes.get(i); ClusterMembership membership = ClusterMembership.from(clusterSpec, i); node = node.allocate(application, membership, node.resources(), Instant.now()); nodes.set(i, node); } - nodes = nodeRepository.reserve(nodes); + nodes = nodeRepository.nodes().reserve(nodes); var transaction = new NestedTransaction(); - nodes = nodeRepository.activate(nodes, transaction); + nodes = nodeRepository.nodes().activate(nodes, transaction); transaction.commit(); } @@ -326,9 +326,9 @@ public class SpareCapacityMaintainerTest { } private void dumpState() { - for (Node host : nodeRepository.list().hosts().asList()) { + for (Node host : nodeRepository.nodes().list().hosts().asList()) { System.out.println("Host " + host.hostname() + " " + host.resources()); - for (Node node : nodeRepository.list().childrenOf(host).asList()) + for (Node node : nodeRepository.nodes().list().childrenOf(host).asList()) System.out.println(" Node " + node.hostname() + " " + node.resources() + " allocation " +node.allocation()); } } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/SwitchRebalancerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/SwitchRebalancerTest.java index a44f566d380..9109d992f4a 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/SwitchRebalancerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/SwitchRebalancerTest.java @@ -80,7 +80,7 @@ public class SwitchRebalancerTest { for (var cluster : List.of(cluster1, cluster2)) { tester.clock().advance(SwitchRebalancer.waitTimeAfterPreviousDeployment); rebalancer.maintain(); - NodeList allNodes = tester.nodeRepository().list(); + NodeList allNodes = tester.nodeRepository().nodes().list(); NodeList clusterNodes = allNodes.owner(app).cluster(cluster).state(Node.State.active); NodeList retired = clusterNodes.retired(); assertEquals("Node is retired in " + cluster, 1, retired.size()); @@ -90,7 +90,7 @@ public class SwitchRebalancerTest { // Retired node becomes inactive and makes zone stable try (var lock = tester.provisioner().lock(app)) { NestedTransaction removeTransaction = new NestedTransaction(); - tester.nodeRepository().deactivate(retired.asList(), new ApplicationTransaction(lock, removeTransaction)); + tester.nodeRepository().nodes().deactivate(retired.asList(), new ApplicationTransaction(lock, removeTransaction)); removeTransaction.commit(); } } @@ -134,7 +134,7 @@ public class SwitchRebalancerTest { // Rebalance tester.clock().advance(SwitchRebalancer.waitTimeAfterPreviousDeployment); rebalancer.maintain(); - NodeList activeNodes = tester.nodeRepository().list().owner(app).cluster(spec.id()).state(Node.State.active); + NodeList activeNodes = tester.nodeRepository().nodes().list().owner(app).cluster(spec.id()).state(Node.State.active); NodeList retired = activeNodes.retired(); assertEquals("Node is retired", 1, retired.size()); assertFalse("Retired node was not on exclusive switch", nodesOnExclusiveSwitch.contains(retired.first().get())); @@ -142,7 +142,7 @@ public class SwitchRebalancerTest { // Retired node becomes inactive and makes zone stable try (var lock = tester.provisioner().lock(app)) { NestedTransaction removeTransaction = new NestedTransaction(); - tester.nodeRepository().deactivate(retired.asList(), new ApplicationTransaction(lock, removeTransaction)); + tester.nodeRepository().nodes().deactivate(retired.asList(), new ApplicationTransaction(lock, removeTransaction)); removeTransaction.commit(); } @@ -152,9 +152,9 @@ public class SwitchRebalancerTest { } private void assertNoMoves(SwitchRebalancer rebalancer, ProvisioningTester tester) { - NodeList nodes0 = tester.nodeRepository().list(Node.State.active).owner(app); + NodeList nodes0 = tester.nodeRepository().nodes().list(Node.State.active).owner(app); rebalancer.maintain(); - NodeList nodes1 = tester.nodeRepository().list(Node.State.active).owner(app); + NodeList nodes1 = tester.nodeRepository().nodes().list(Node.State.active).owner(app); assertEquals("Node allocation is unchanged", nodes0.asList(), nodes1.asList()); assertEquals("No nodes are retired", List.of(), nodes1.retired().asList()); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/os/OsVersionsTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/os/OsVersionsTest.java index c40f265db51..7005a64127a 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/os/OsVersionsTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/os/OsVersionsTest.java @@ -40,7 +40,7 @@ public class OsVersionsTest { public void upgrade() { var versions = new OsVersions(tester.nodeRepository(), new DelegatingUpgrader(tester.nodeRepository(), Integer.MAX_VALUE)); provisionInfraApplication(10); - Supplier<List<Node>> hostNodes = () -> tester.nodeRepository().getNodes(NodeType.host); + Supplier<List<Node>> hostNodes = () -> tester.nodeRepository().nodes().getNodes(NodeType.host); // Upgrade OS assertTrue("No versions set", versions.readChange().targets().isEmpty()); @@ -94,7 +94,7 @@ public class OsVersionsTest { int maxActiveUpgrades = 5; var versions = new OsVersions(tester.nodeRepository(), new DelegatingUpgrader(tester.nodeRepository(), maxActiveUpgrades)); provisionInfraApplication(totalNodes); - Supplier<NodeList> hostNodes = () -> tester.nodeRepository().list().state(Node.State.active).hosts(); + Supplier<NodeList> hostNodes = () -> tester.nodeRepository().nodes().list().state(Node.State.active).hosts(); // 5 nodes have no version. The other 15 are spread across different versions var hostNodesList = hostNodes.get().asList(); @@ -104,10 +104,10 @@ public class OsVersionsTest { // Deprovisioned hosts are not considered for (var host : tester.makeReadyNodes(10, "default", NodeType.host)) { - tester.nodeRepository().fail(host.hostname(), Agent.system, OsVersions.class.getSimpleName()); - tester.nodeRepository().removeRecursively(host.hostname()); + tester.nodeRepository().nodes().fail(host.hostname(), Agent.system, OsVersions.class.getSimpleName()); + tester.nodeRepository().nodes().removeRecursively(host.hostname()); } - assertEquals(10, tester.nodeRepository().getNodes(Node.State.deprovisioned).size()); + assertEquals(10, tester.nodeRepository().nodes().getNodes(Node.State.deprovisioned).size()); // Set target var version1 = Version.fromString("7.1"); @@ -140,7 +140,7 @@ public class OsVersionsTest { public void newer_upgrade_aborts_upgrade_to_stale_version() { var versions = new OsVersions(tester.nodeRepository(), new DelegatingUpgrader(tester.nodeRepository(), Integer.MAX_VALUE)); provisionInfraApplication(10); - Supplier<NodeList> hostNodes = () -> tester.nodeRepository().list().hosts(); + Supplier<NodeList> hostNodes = () -> tester.nodeRepository().nodes().list().hosts(); // Some nodes are targeting an older version var version1 = Version.fromString("7.1"); @@ -166,7 +166,7 @@ public class OsVersionsTest { for (var host : hosts) { tester.makeReadyVirtualDockerNodes(2, resources, host.hostname()); } - Supplier<NodeList> hostNodes = () -> tester.nodeRepository().list() + Supplier<NodeList> hostNodes = () -> tester.nodeRepository().nodes().list() .hosts() .not().state(Node.State.deprovisioned); @@ -206,7 +206,7 @@ public class OsVersionsTest { // All hosts upgraded and none are deprovisioning assertEquals(hostCount, hostNodes.get().onOsVersion(version1).not().deprovisioning().size()); - assertEquals(hostCount, tester.nodeRepository().list().state(Node.State.deprovisioned).size()); + assertEquals(hostCount, tester.nodeRepository().nodes().list().state(Node.State.deprovisioned).size()); var lastRetiredAt = clock.instant().truncatedTo(ChronoUnit.MILLIS); // Resuming after everything has upgraded does nothing @@ -225,7 +225,7 @@ public class OsVersionsTest { var versions = new OsVersions(tester.nodeRepository(), new RetiringUpgrader(tester.nodeRepository())); int hostCount = 3; provisionInfraApplication(hostCount, NodeType.confighost); - Supplier<NodeList> hostNodes = () -> tester.nodeRepository().list() + Supplier<NodeList> hostNodes = () -> tester.nodeRepository().nodes().list() .nodeType(NodeType.confighost) .not().state(Node.State.deprovisioned); @@ -244,7 +244,7 @@ public class OsVersionsTest { } private NodeList retiringChildrenOf(Node parent) { - return tester.nodeRepository().list().childrenOf(parent).matching(child -> child.status().wantToRetire()); + return tester.nodeRepository().nodes().list().childrenOf(parent).matching(child -> child.status().wantToRetire()); } private List<Node> provisionInfraApplication(int nodeCount) { @@ -256,7 +256,7 @@ public class OsVersionsTest { tester.prepareAndActivateInfraApplication(infraApplication, nodeType); return nodes.stream() .map(Node::hostname) - .flatMap(hostname -> tester.nodeRepository().getNode(hostname).stream()) + .flatMap(hostname -> tester.nodeRepository().nodes().getNode(hostname).stream()) .collect(Collectors.toList()); } @@ -289,9 +289,9 @@ public class OsVersionsTest { Optional<Version> wantedOsVersion = node.status().osVersion().wanted(); if (node.status().wantToDeprovision()) { // Complete upgrade by deprovisioning stale hosts and provisioning new ones - tester.nodeRepository().park(node.hostname(), false, Agent.system, - OsVersionsTest.class.getSimpleName()); - tester.nodeRepository().removeRecursively(node.hostname()); + tester.nodeRepository().nodes().park(node.hostname(), false, Agent.system, + OsVersionsTest.class.getSimpleName()); + tester.nodeRepository().nodes().removeRecursively(node.hostname()); node = provisionInfraApplication(1, nodeType).get(0); } return node.with(node.status().withOsVersion(node.status().osVersion().withCurrent(wantedOsVersion))); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java index 7ef13cc0be2..23a8af045af 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java @@ -51,8 +51,8 @@ public class AclProvisioningTest { // Get trusted nodes for the first active node Node node = activeNodes.get(0); - List<Node> host = node.parentHostname().flatMap(tester.nodeRepository()::getNode).map(List::of).orElseGet(List::of); - Supplier<NodeAcl> nodeAcls = () -> node.acl(tester.nodeRepository().list(), tester.nodeRepository().loadBalancers()); + List<Node> host = node.parentHostname().flatMap(tester.nodeRepository().nodes()::getNode).map(List::of).orElseGet(List::of); + Supplier<NodeAcl> nodeAcls = () -> node.acl(tester.nodeRepository().nodes().list(), tester.nodeRepository().loadBalancers()); // Trusted nodes are active nodes in same application, proxy nodes and config servers assertAcls(List.of(activeNodes, proxyNodes, configServers, host), @@ -72,9 +72,9 @@ public class AclProvisioningTest { deploy(2); // Get trusted nodes for a ready tenant node - Node node = tester.nodeRepository().getNodes(NodeType.tenant, Node.State.ready).get(0); - NodeAcl nodeAcl = node.acl(tester.nodeRepository().list(), tester.nodeRepository().loadBalancers()); - List<Node> tenantNodes = tester.nodeRepository().getNodes(NodeType.tenant); + Node node = tester.nodeRepository().nodes().getNodes(NodeType.tenant, Node.State.ready).get(0); + NodeAcl nodeAcl = node.acl(tester.nodeRepository().nodes().list(), tester.nodeRepository().loadBalancers()); + List<Node> tenantNodes = tester.nodeRepository().nodes().getNodes(NodeType.tenant); // Trusted nodes are all proxy-, config-, and, tenant-nodes assertAcls(List.of(proxyNodes, configServers, tenantNodes), List.of(nodeAcl)); @@ -90,12 +90,12 @@ public class AclProvisioningTest { // Allocate 2 nodes deploy(4); - List<Node> tenantNodes = tester.nodeRepository().getNodes(NodeType.tenant); + List<Node> tenantNodes = tester.nodeRepository().nodes().getNodes(NodeType.tenant); // Get trusted nodes for the first config server - Node node = tester.nodeRepository().getNode("cfg1") + Node node = tester.nodeRepository().nodes().getNode("cfg1") .orElseThrow(() -> new RuntimeException("Failed to find cfg1")); - NodeAcl nodeAcl = node.acl(tester.nodeRepository().list(), tester.nodeRepository().loadBalancers()); + NodeAcl nodeAcl = node.acl(tester.nodeRepository().nodes().list(), tester.nodeRepository().loadBalancers()); // Trusted nodes is all tenant nodes, all proxy nodes, all config servers and load balancer subnets assertAcls(List.of(tenantNodes, proxyNodes, configServers), Set.of("10.2.3.0/24", "10.4.5.0/24"), List.of(nodeAcl)); @@ -114,9 +114,9 @@ public class AclProvisioningTest { tester.deploy(zoneApplication, Capacity.fromRequiredNodeType(NodeType.proxy)); // Get trusted nodes for first proxy node - List<Node> proxyNodes = tester.nodeRepository().getNodes(zoneApplication); + List<Node> proxyNodes = tester.nodeRepository().nodes().getNodes(zoneApplication); Node node = proxyNodes.get(0); - NodeAcl nodeAcl = node.acl(tester.nodeRepository().list(), tester.nodeRepository().loadBalancers()); + NodeAcl nodeAcl = node.acl(tester.nodeRepository().nodes().list(), tester.nodeRepository().loadBalancers()); // Trusted nodes is all config servers and all proxy nodes assertAcls(List.of(proxyNodes, configServers), List.of(nodeAcl)); @@ -156,7 +156,7 @@ public class AclProvisioningTest { List<Node> controllers = tester.deploy(controllerApplication, Capacity.fromRequiredNodeType(NodeType.controller)); // Controllers and hosts all trust each other - NodeAcl controllerAcl = controllers.get(0).acl(tester.nodeRepository().list(), tester.nodeRepository().loadBalancers()); + NodeAcl controllerAcl = controllers.get(0).acl(tester.nodeRepository().nodes().list(), tester.nodeRepository().loadBalancers()); assertAcls(List.of(controllers), List.of(controllerAcl)); assertEquals(Set.of(22, 4443, 443), controllerAcl.trustedPorts()); } @@ -197,7 +197,7 @@ public class AclProvisioningTest { tester.makeConfigServers(3, "default", Version.fromString("6.123.456")); List<Node> readyNodes = tester.makeReadyNodes(1, "default", NodeType.proxy); - NodeAcl nodeAcl = readyNodes.get(0).acl(tester.nodeRepository().list(), tester.nodeRepository().loadBalancers()); + NodeAcl nodeAcl = readyNodes.get(0).acl(tester.nodeRepository().nodes().list(), tester.nodeRepository().loadBalancers()); assertEquals(3, nodeAcl.trustedNodes().size()); Iterator<Node> trustedNodes = nodeAcl.trustedNodes().iterator(); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java index ef0e6d4ddc4..02ee41a5226 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java @@ -365,8 +365,8 @@ public class DockerProvisioningTest { tester.activate(app1, cluster1, Capacity.from(new ClusterResources(5, 1, r))); tester.activate(app1, cluster1, Capacity.from(new ClusterResources(2, 1, r))); - var tx = new ApplicationTransaction(new ProvisionLock(app1, tester.nodeRepository().lock(app1)), new NestedTransaction()); - tester.nodeRepository().deactivate(tester.nodeRepository().list(app1, Node.State.active).retired().asList(), tx); + var tx = new ApplicationTransaction(new ProvisionLock(app1, tester.nodeRepository().nodes().lock(app1)), new NestedTransaction()); + tester.nodeRepository().nodes().deactivate(tester.nodeRepository().nodes().list(app1, Node.State.active).retired().asList(), tx); tx.nested().commit(); assertEquals(2, tester.getNodes(app1, Node.State.active).size()); @@ -403,7 +403,7 @@ public class DockerProvisioningTest { tester.activate(app1, cluster1, Capacity.from(new ClusterResources(2, 1, r))); // Deactivate any retired nodes - usually done by the RetiredExpirer - tester.nodeRepository().setRemovable(app1, tester.getNodes(app1).retired().asList()); + tester.nodeRepository().nodes().setRemovable(app1, tester.getNodes(app1).retired().asList()); tester.activate(app1, cluster1, Capacity.from(new ClusterResources(2, 1, r))); if (expectedReuse) { @@ -413,8 +413,8 @@ public class DockerProvisioningTest { } else { assertEquals(0, tester.getNodes(app1, Node.State.inactive).size()); - assertEquals(2, tester.nodeRepository().getNodes(Node.State.dirty).size()); - tester.nodeRepository().setReady(tester.nodeRepository().getNodes(Node.State.dirty), Agent.system, "test"); + assertEquals(2, tester.nodeRepository().nodes().getNodes(Node.State.dirty).size()); + tester.nodeRepository().nodes().setReady(tester.nodeRepository().nodes().getNodes(Node.State.dirty), Agent.system, "test"); tester.activate(app1, cluster1, Capacity.from(new ClusterResources(4, 1, r))); } @@ -434,13 +434,13 @@ public class DockerProvisioningTest { private void assertNodeParentReservation(List<Node> nodes, Optional<TenantName> reservation, ProvisioningTester tester) { for (Node node : nodes) - assertEquals(reservation, tester.nodeRepository().getNode(node.parentHostname().get()).get().reservedTo()); + assertEquals(reservation, tester.nodeRepository().nodes().getNode(node.parentHostname().get()).get().reservedTo()); } private void assertHostSpecParentReservation(List<HostSpec> hostSpecs, Optional<TenantName> reservation, ProvisioningTester tester) { for (HostSpec hostSpec : hostSpecs) { - Node node = tester.nodeRepository().getNode(hostSpec.hostname()).get(); - assertEquals(reservation, tester.nodeRepository().getNode(node.parentHostname().get()).get().reservedTo()); + Node node = tester.nodeRepository().nodes().getNode(hostSpec.hostname()).get(); + assertEquals(reservation, tester.nodeRepository().nodes().getNode(node.parentHostname().get()).get().reservedTo()); } } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerAllocationTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerAllocationTest.java index 3c6e39702e4..0c8e19e0793 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerAllocationTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerAllocationTest.java @@ -69,7 +69,7 @@ public class DynamicDockerAllocationTest { .build(); tester.makeReadyNodes(4, "host-small", NodeType.host, 32); tester.activateTenantHosts(); - List<Node> dockerHosts = tester.nodeRepository().getNodes(NodeType.host, State.active); + List<Node> dockerHosts = tester.nodeRepository().nodes().getNodes(NodeType.host, State.active); NodeResources flavor = new NodeResources(1, 4, 100, 1); // Application 1 @@ -90,7 +90,7 @@ public class DynamicDockerAllocationTest { // Assert that we have two spare nodes (two hosts that are don't have allocations) Set<String> hostsWithChildren = new HashSet<>(); - for (Node node : tester.nodeRepository().list(State.active).nodeType(NodeType.tenant).not().state(State.inactive).not().retired()) { + for (Node node : tester.nodeRepository().nodes().list(State.active).nodeType(NodeType.tenant).not().state(State.inactive).not().retired()) { hostsWithChildren.add(node.parentHostname().get()); } assertEquals(4 - spareCount, hostsWithChildren.size()); @@ -110,7 +110,7 @@ public class DynamicDockerAllocationTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).flavorsConfig(flavorsConfig()).build(); tester.makeReadyNodes(5, "host-small", NodeType.host, 32); tester.activateTenantHosts(); - List<Node> dockerHosts = tester.nodeRepository().getNodes(NodeType.host, State.active); + List<Node> dockerHosts = tester.nodeRepository().nodes().getNodes(NodeType.host, State.active); NodeResources resources = new NodeResources(1, 4, 100, 0.3); // Application 1 @@ -130,7 +130,7 @@ public class DynamicDockerAllocationTest { // App 2 and 3 should have been allocated to the same nodes - fail one of the parent hosts from there String parent = "host-1.yahoo.com"; - tester.nodeRepository().failRecursively(parent, Agent.system, "Testing"); + tester.nodeRepository().nodes().failRecursively(parent, Agent.system, "Testing"); // Redeploy all applications deployApp(application1, clusterSpec1, resources, tester, 3); @@ -139,7 +139,7 @@ public class DynamicDockerAllocationTest { Map<Integer, Integer> numberOfChildrenStat = new HashMap<>(); for (Node host : dockerHosts) { - int nofChildren = tester.nodeRepository().list().childrenOf(host).size(); + int nofChildren = tester.nodeRepository().nodes().list().childrenOf(host).size(); if (!numberOfChildrenStat.containsKey(nofChildren)) { numberOfChildrenStat.put(nofChildren, 0); } @@ -202,7 +202,7 @@ public class DynamicDockerAllocationTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).flavorsConfig(flavorsConfig()).build(); tester.makeReadyNodes(2, "host-small", NodeType.host, 32); tester.activateTenantHosts(); - List<Node> dockerHosts = tester.nodeRepository().getNodes(NodeType.host, State.active); + List<Node> dockerHosts = tester.nodeRepository().nodes().getNodes(NodeType.host, State.active); NodeResources flavor = new NodeResources(1, 4, 100, 1); // Application 1 @@ -216,7 +216,7 @@ public class DynamicDockerAllocationTest { // Assert that we have two spare nodes (two hosts that are don't have allocations) Set<String> hostsWithChildren = new HashSet<>(); - for (Node node : tester.nodeRepository().list(State.active).nodeType(NodeType.tenant).not().state(State.inactive).not().retired()) { + for (Node node : tester.nodeRepository().nodes().list(State.active).nodeType(NodeType.tenant).not().state(State.inactive).not().retired()) { hostsWithChildren.add(node.parentHostname().get()); } assertEquals(2, hostsWithChildren.size()); @@ -299,7 +299,7 @@ public class DynamicDockerAllocationTest { public void allocation_should_fail_when_host_is_not_in_allocatable_state() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).flavorsConfig(flavorsConfig()).build(); tester.makeProvisionedNodes(3, "host-small", NodeType.host, 32).forEach(node -> - tester.nodeRepository().fail(node.hostname(), Agent.system, getClass().getSimpleName())); + tester.nodeRepository().nodes().fail(node.hostname(), Agent.system, getClass().getSimpleName())); ApplicationId application = ProvisioningTester.applicationId(); tester.prepare(application, clusterSpec("myContent.t2.a2"), 2, 1, new NodeResources(1, 40, 100, 1)); @@ -315,7 +315,7 @@ public class DynamicDockerAllocationTest { List<HostSpec> hosts = tester.prepare(application, clusterSpec("myContent.t1.a1"), 2, 1, new NodeResources(1, 4, 100, 1)); tester.activate(application, hosts); - List<Node> activeNodes = tester.nodeRepository().getNodes(application); + List<Node> activeNodes = tester.nodeRepository().nodes().getNodes(application); assertEquals(ImmutableSet.of("127.0.127.13", "::13"), activeNodes.get(0).ipConfig().primary()); assertEquals(ImmutableSet.of("127.0.127.2", "::2"), activeNodes.get(1).ipConfig().primary()); } @@ -437,16 +437,16 @@ public class DynamicDockerAllocationTest { // Redeploy does not change allocation as a host with switch information is no better or worse than hosts // without switch information - List<Node> allocatedNodes = tester.nodeRepository().getNodes(app1); + List<Node> allocatedNodes = tester.nodeRepository().nodes().getNodes(app1); tester.activate(app1, tester.prepare(app1, cluster, Capacity.from(new ClusterResources(2, 1, resources)))); - assertEquals("Allocation unchanged", allocatedNodes, tester.nodeRepository().getNodes(app1)); + assertEquals("Allocation unchanged", allocatedNodes, tester.nodeRepository().nodes().getNodes(app1)); // Initial hosts are attached to the same switch tester.patchNodes(hosts0, (host) -> host.withSwitchHostname(switch0)); // Redeploy does not change allocation tester.activate(app1, tester.prepare(app1, cluster, Capacity.from(new ClusterResources(2, 1, resources)))); - assertEquals("Allocation unchanged", allocatedNodes, tester.nodeRepository().getNodes(app1)); + assertEquals("Allocation unchanged", allocatedNodes, tester.nodeRepository().nodes().getNodes(app1)); // One regular host and one slow-disk host are provisioned on the same switch String switch1 = "switch1"; @@ -465,13 +465,13 @@ public class DynamicDockerAllocationTest { tester.assertSwitches(Set.of(switch0), app1, cluster.id()); // A node is retired - tester.patchNode(tester.nodeRepository().list().owner(app1).asList().get(0), + tester.patchNode(tester.nodeRepository().nodes().list().owner(app1).asList().get(0), (node) -> node.withWantToRetire(true, Agent.system, tester.clock().instant())); // Redeploy allocates new node on a distinct switch, and the host with slowest disk (cheapest) on that switch tester.activate(app1, tester.prepare(app1, cluster, Capacity.from(new ClusterResources(2, 1, resources)))); tester.assertSwitches(Set.of(switch0, switch1), app1, cluster.id()); - assertTrue("Host with slow disk on " + switch1 + " is chosen", tester.nodeRepository().list().owner(app1).state(State.active).stream() + assertTrue("Host with slow disk on " + switch1 + " is chosen", tester.nodeRepository().nodes().list().owner(app1).state(State.active).stream() .anyMatch(node -> node.hasParent(hostWithSlowDisk.hostname()))); // Growing cluster picks new node on exclusive switch @@ -515,14 +515,14 @@ public class DynamicDockerAllocationTest { clusterSpec.with(Optional.of(ClusterSpec.Group.from(0))), index); // Need to add group here so that group is serialized in node allocation Node node1aAllocation = node1a.allocate(id, clusterMembership1, node1a.resources(), Instant.now()); - tester.nodeRepository().addNodes(Collections.singletonList(node1aAllocation), Agent.system); + tester.nodeRepository().nodes().addNodes(Collections.singletonList(node1aAllocation), Agent.system); NestedTransaction transaction = new NestedTransaction().add(new CuratorTransaction(tester.getCurator())); - tester.nodeRepository().activate(Collections.singletonList(node1aAllocation), transaction); + tester.nodeRepository().nodes().activate(Collections.singletonList(node1aAllocation), transaction); transaction.commit(); } private List<Node> findSpareCapacity(ProvisioningTester tester) { - List<Node> nodes = tester.nodeRepository().getNodes(State.values()); + List<Node> nodes = tester.nodeRepository().nodes().getNodes(State.values()); NodeList nl = NodeList.copyOf(nodes); return nodes.stream() .filter(n -> n.type() == NodeType.host) 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 37aeff82ed6..1d9c04999a1 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 @@ -66,7 +66,7 @@ public class DynamicDockerProvisionTest { @Test public void dynamically_provision_with_empty_node_repo() { - assertEquals(0, tester.nodeRepository().list().size()); + assertEquals(0, tester.nodeRepository().nodes().list().size()); ApplicationId application1 = ProvisioningTester.applicationId(); NodeResources resources = new NodeResources(1, 4, 10, 1); @@ -77,10 +77,10 @@ public class DynamicDockerProvisionTest { Version.emptyVersion, HostSharing.any); // Total of 8 nodes should now be in node-repo, 4 active hosts and 4 active nodes - assertEquals(8, tester.nodeRepository().list().size()); - assertEquals(4, tester.nodeRepository().getNodes(NodeType.host, Node.State.active).size()); + assertEquals(8, tester.nodeRepository().nodes().list().size()); + assertEquals(4, tester.nodeRepository().nodes().getNodes(NodeType.host, Node.State.active).size()); assertEquals(List.of("host-100-1", "host-101-1", "host-102-1", "host-103-1"), - tester.nodeRepository().getNodes(NodeType.tenant, Node.State.active).stream() + tester.nodeRepository().nodes().getNodes(NodeType.tenant, Node.State.active).stream() .map(Node::hostname).sorted().collect(Collectors.toList())); // Deploy new application @@ -88,11 +88,11 @@ public class DynamicDockerProvisionTest { prepareAndActivate(application2, clusterSpec("mycluster"), 4, 1, resources); // Total of 12 nodes should now be in node-repo, 4 active hosts and 8 active nodes - assertEquals(12, tester.nodeRepository().list().size()); - assertEquals(4, tester.nodeRepository().getNodes(NodeType.host, Node.State.active).size()); + assertEquals(12, tester.nodeRepository().nodes().list().size()); + assertEquals(4, tester.nodeRepository().nodes().getNodes(NodeType.host, Node.State.active).size()); assertEquals(List.of("host-100-1", "host-100-2", "host-101-1", "host-101-2", "host-102-1", "host-102-2", "host-103-1", "host-103-2"), - tester.nodeRepository().getNodes(NodeType.tenant, Node.State.active).stream() + tester.nodeRepository().nodes().getNodes(NodeType.tenant, Node.State.active).stream() .map(Node::hostname).sorted().collect(Collectors.toList())); // Deploy new exclusive application @@ -103,9 +103,9 @@ public class DynamicDockerProvisionTest { Version.emptyVersion, HostSharing.exclusive); // Total of 20 nodes should now be in node-repo, 8 active hosts and 12 active nodes - assertEquals(20, tester.nodeRepository().list().size()); - assertEquals(8, tester.nodeRepository().getNodes(NodeType.host, Node.State.active).size()); - assertEquals(12, tester.nodeRepository().getNodes(NodeType.tenant, Node.State.active).size()); + assertEquals(20, tester.nodeRepository().nodes().list().size()); + assertEquals(8, tester.nodeRepository().nodes().getNodes(NodeType.host, Node.State.active).size()); + assertEquals(12, tester.nodeRepository().nodes().getNodes(NodeType.tenant, Node.State.active).size()); verifyNoMoreInteractions(hostProvisioner); } @@ -124,14 +124,14 @@ public class DynamicDockerProvisionTest { prepareAndActivate(application2, clusterSpec("mycluster", true), 4, 1, initialResources); // Total of 16 nodes should now be in node-repo, 8 active hosts and 8 active nodes - assertEquals(16, tester.nodeRepository().list().size()); - assertEquals(8, tester.nodeRepository().getNodes(NodeType.tenant, Node.State.active).size()); + assertEquals(16, tester.nodeRepository().nodes().list().size()); + assertEquals(8, tester.nodeRepository().nodes().getNodes(NodeType.tenant, Node.State.active).size()); prepareAndActivate(application1, clusterSpec("mycluster"), 4, 1, smallResources); prepareAndActivate(application2, clusterSpec("mycluster", true), 4, 1, smallResources); // 24 nodes: 4 shared hosts with 4 app1 nodes + 8 exclusive hosts with 8 nodes of app2, 4 of which are retired - NodeList nodes = tester.nodeRepository().list(); + NodeList nodes = tester.nodeRepository().nodes().list(); assertEquals(24, nodes.size()); assertEquals(12, nodes.nodeType(NodeType.host).state(Node.State.active).size()); assertEquals(12, nodes.nodeType(NodeType.tenant).state(Node.State.active).size()); @@ -153,11 +153,11 @@ public class DynamicDockerProvisionTest { ApplicationId application3 = ProvisioningTester.applicationId(); prepareAndActivate(application3, clusterSpec("mycluster"), 3, 1, resources); - assertEquals(4, tester.nodeRepository().getNodes(NodeType.tenant).stream().map(Node::parentHostname).distinct().count()); + assertEquals(4, tester.nodeRepository().nodes().getNodes(NodeType.tenant).stream().map(Node::parentHostname).distinct().count()); ApplicationId application4 = ProvisioningTester.applicationId(); prepareAndActivate(application4, clusterSpec("mycluster"), 3, 1, resources); - assertEquals(5, tester.nodeRepository().getNodes(NodeType.tenant).stream().map(Node::parentHostname).distinct().count()); + assertEquals(5, tester.nodeRepository().nodes().getNodes(NodeType.tenant).stream().map(Node::parentHostname).distinct().count()); } @Test @@ -167,19 +167,19 @@ public class DynamicDockerProvisionTest { mockHostProvisioner(hostProvisioner, "large", 3, null); // Provision shared hosts prepareAndActivate(application1, clusterSpec("mycluster"), 4, 1, resources); - Set<Node> initialNodes = tester.nodeRepository().list(application1).stream().collect(Collectors.toSet()); + Set<Node> initialNodes = tester.nodeRepository().nodes().list(application1).stream().collect(Collectors.toSet()); assertEquals(4, initialNodes.size()); // Redeploy same application with exclusive=true mockHostProvisioner(hostProvisioner, "large", 3, application1); prepareAndActivate(application1, clusterSpec("mycluster", true), 4, 1, resources); - assertEquals(8, tester.nodeRepository().list(application1).size()); - assertEquals(initialNodes, tester.nodeRepository().list(application1).retired().stream().collect(Collectors.toSet())); + assertEquals(8, tester.nodeRepository().nodes().list(application1).size()); + assertEquals(initialNodes, tester.nodeRepository().nodes().list(application1).retired().stream().collect(Collectors.toSet())); // Redeploy without exclusive again is no-op prepareAndActivate(application1, clusterSpec("mycluster"), 4, 1, resources); - assertEquals(8, tester.nodeRepository().list(application1).size()); - assertEquals(initialNodes, tester.nodeRepository().list(application1).retired().stream().collect(Collectors.toSet())); + assertEquals(8, tester.nodeRepository().nodes().list(application1).size()); + assertEquals(initialNodes, tester.nodeRepository().nodes().list(application1).retired().stream().collect(Collectors.toSet())); } @Test @@ -188,7 +188,7 @@ public class DynamicDockerProvisionTest { ApplicationId app = ProvisioningTester.applicationId(); Function<Node, Node> retireNode = node -> tester.patchNode(node, (n) -> n.withWantToRetire(true, Agent.system, Instant.now())); - Function<Integer, Node> getNodeInGroup = group -> tester.nodeRepository().getNodes(app).stream() + Function<Integer, Node> getNodeInGroup = group -> tester.nodeRepository().nodes().getNodes(app).stream() .filter(node -> node.allocation().get().membership().cluster().group().get().index() == group) .findAny().orElseThrow(); @@ -209,7 +209,7 @@ public class DynamicDockerProvisionTest { tester.prepare(app, clusterSpec("content"), 8, 2, resources); // Verify that nodes have unique indices from 0..9 - var indices = tester.nodeRepository().getNodes(app).stream() + var indices = tester.nodeRepository().nodes().getNodes(app).stream() .map(node -> node.allocation().get().membership().index()) .collect(Collectors.toSet()); assertTrue(indices.containsAll(IntStream.range(0, 10).boxed().collect(Collectors.toList()))); @@ -398,9 +398,9 @@ public class DynamicDockerProvisionTest { private void prepareAndActivate(ApplicationId application, ClusterSpec clusterSpec, int nodes, int groups, NodeResources resources) { List<HostSpec> prepared = tester.prepare(application, clusterSpec, nodes, groups, resources); - List<Node> provisionedHosts = tester.nodeRepository().getNodes(NodeType.host, Node.State.provisioned); + List<Node> provisionedHosts = tester.nodeRepository().nodes().getNodes(NodeType.host, Node.State.provisioned); if (!provisionedHosts.isEmpty()) { - tester.nodeRepository().setReady(provisionedHosts, Agent.system, DynamicDockerProvisionTest.class.getSimpleName()); + tester.nodeRepository().nodes().setReady(provisionedHosts, Agent.system, DynamicDockerProvisionTest.class.getSimpleName()); tester.activateTenantHosts(); } tester.activate(application, prepared); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/InPlaceResizeProvisionTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/InPlaceResizeProvisionTest.java index 62b153c7e12..4fd51f38fb6 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/InPlaceResizeProvisionTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/InPlaceResizeProvisionTest.java @@ -198,7 +198,7 @@ public class InPlaceResizeProvisionTest { // Failing one of the new nodes should cause another new node to be allocated rather than // unretiring one of the existing nodes, to avoid resizing during unretiring Node nodeToFail = listCluster(content1).not().retired().asList().get(0); - tester.nodeRepository().fail(nodeToFail.hostname(), Agent.system, "testing"); + tester.nodeRepository().nodes().fail(nodeToFail.hostname(), Agent.system, "testing"); new PrepareHelper(tester, app).prepare(content1, 8, 1, halvedResources).activate(); assertFalse(listCluster(content1).stream().anyMatch(n -> n.equals(nodeToFail))); assertSizeAndResources(listCluster(content1).retired(), 4, resources); @@ -206,8 +206,8 @@ public class InPlaceResizeProvisionTest { // ... same with setting a node to want to retire Node nodeToWantoToRetire = listCluster(content1).not().retired().asList().get(0); - try (NodeMutex lock = tester.nodeRepository().lockAndGetRequired(nodeToWantoToRetire)) { - tester.nodeRepository().write(lock.node().withWantToRetire(true, Agent.system, + try (NodeMutex lock = tester.nodeRepository().nodes().lockAndGetRequired(nodeToWantoToRetire)) { + tester.nodeRepository().nodes().write(lock.node().withWantToRetire(true, Agent.system, tester.clock().instant()), lock); } new PrepareHelper(tester, app).prepare(content1, 8, 1, halvedResources).activate(); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/InfraDeployerImplTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/InfraDeployerImplTest.java index d21e4c22006..f4d8bbfcb21 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/InfraDeployerImplTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/InfraDeployerImplTest.java @@ -123,7 +123,7 @@ public class InfraDeployerImplTest { addNode(5, Node.State.dirty, Optional.empty()); addNode(6, Node.State.ready, Optional.empty()); Node node7 = addNode(7, Node.State.active, Optional.of(target)); - nodeRepository.setRemovable(application.getApplicationId(), List.of(node7)); + nodeRepository.nodes().setRemovable(application.getApplicationId(), List.of(node7)); infraDeployer.getDeployment(application.getApplicationId()).orElseThrow().activate(); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java index 14f068d89a7..fece475852a 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java @@ -76,7 +76,7 @@ public class LoadBalancerProvisionerTest { // A container is failed Supplier<List<Node>> containers = () -> tester.getNodes(app1).container().asList(); Node toFail = containers.get().get(0); - tester.nodeRepository().fail(toFail.hostname(), Agent.system, this.getClass().getSimpleName()); + tester.nodeRepository().nodes().fail(toFail.hostname(), Agent.system, this.getClass().getSimpleName()); // Redeploying replaces failed node and removes it from load balancer tester.activate(app1, prepare(app1, @@ -136,7 +136,7 @@ public class LoadBalancerProvisionerTest { // Entire application is removed: Nodes and load balancer are deactivated tester.remove(app1); dirtyNodesOf(app1); - assertTrue("No nodes are allocated to " + app1, tester.nodeRepository().getNodes(app1, Node.State.reserved, Node.State.active).isEmpty()); + assertTrue("No nodes are allocated to " + app1, tester.nodeRepository().nodes().getNodes(app1, Node.State.reserved, Node.State.active).isEmpty()); assertEquals(2, lbApp1.get().size()); assertTrue("Deactivated load balancers", lbApp1.get().stream().allMatch(lb -> lb.state() == LoadBalancer.State.inactive)); assertTrue("Load balancers for " + app2 + " remain active", lbApp2.get().stream().allMatch(lb -> lb.state() == LoadBalancer.State.active)); @@ -167,20 +167,20 @@ public class LoadBalancerProvisionerTest { var nodes = tester.prepare(app1, clusterRequest(ClusterSpec.Type.container, ClusterSpec.Id.from("qrs")), 2 , 1, resources); Supplier<LoadBalancer> lb = () -> tester.nodeRepository().loadBalancers().list(app1).asList().get(0); assertTrue("Load balancer provisioned with empty reals", tester.loadBalancerService().instances().get(lb.get().id()).reals().isEmpty()); - assignIps(tester.nodeRepository().getNodes(app1)); + assignIps(tester.nodeRepository().nodes().getNodes(app1)); tester.activate(app1, nodes); assertFalse("Load balancer is reconfigured with reals", tester.loadBalancerService().instances().get(lb.get().id()).reals().isEmpty()); // Application is removed, nodes are deleted and load balancer is deactivated tester.remove(app1); - tester.nodeRepository().database().removeNodes(tester.nodeRepository().getNodes(NodeType.tenant)); - assertTrue("Nodes are deleted", tester.nodeRepository().getNodes(NodeType.tenant).isEmpty()); + tester.nodeRepository().database().removeNodes(tester.nodeRepository().nodes().getNodes(NodeType.tenant)); + assertTrue("Nodes are deleted", tester.nodeRepository().nodes().getNodes(NodeType.tenant).isEmpty()); assertSame("Load balancer is deactivated", LoadBalancer.State.inactive, lb.get().state()); // Application is redeployed nodes = tester.prepare(app1, clusterRequest(ClusterSpec.Type.container, ClusterSpec.Id.from("qrs")), 2 , 1, resources); assertTrue("Load balancer is reconfigured with empty reals", tester.loadBalancerService().instances().get(lb.get().id()).reals().isEmpty()); - assignIps(tester.nodeRepository().getNodes(app1)); + assignIps(tester.nodeRepository().nodes().getNodes(app1)); tester.activate(app1, nodes); assertFalse("Load balancer is reconfigured with reals", tester.loadBalancerService().instances().get(lb.get().id()).reals().isEmpty()); } @@ -269,7 +269,7 @@ public class LoadBalancerProvisionerTest { } private void dirtyNodesOf(ApplicationId application) { - tester.nodeRepository().deallocate(tester.nodeRepository().getNodes(application), Agent.system, this.getClass().getSimpleName()); + tester.nodeRepository().nodes().deallocate(tester.nodeRepository().nodes().getNodes(application), Agent.system, this.getClass().getSimpleName()); } private Set<HostSpec> prepare(ApplicationId application, ClusterSpec... specs) { @@ -286,9 +286,9 @@ public class LoadBalancerProvisionerTest { } private void assignIps(List<Node> nodes) { - try (var lock = tester.nodeRepository().lockUnallocated()) { + try (var lock = tester.nodeRepository().nodes().lockUnallocated()) { for (int i = 0; i < nodes.size(); i++) { - tester.nodeRepository().write(nodes.get(i).with(IP.Config.EMPTY.withPrimary(Set.of("127.0.0." + i))), lock); + tester.nodeRepository().nodes().write(nodes.get(i).with(IP.Config.EMPTY.withPrimary(Set.of("127.0.0." + i))), lock); } } } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/NodeTypeProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/NodeTypeProvisioningTest.java index bf2a6ba3627..9b564232111 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/NodeTypeProvisioningTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/NodeTypeProvisioningTest.java @@ -53,7 +53,7 @@ public class NodeTypeProvisioningTest { List<HostSpec> hosts = deployProxies(application, tester); assertEquals("Reserved all proxies", 11, hosts.size()); tester.activate(application, new HashSet<>(hosts)); - List<Node> nodes = tester.nodeRepository().getNodes(NodeType.proxy, Node.State.active); + List<Node> nodes = tester.nodeRepository().nodes().getNodes(NodeType.proxy, Node.State.active); assertEquals("Activated all proxies", 11, nodes.size()); } @@ -61,7 +61,7 @@ public class NodeTypeProvisioningTest { List<HostSpec> hosts = deployProxies(application, tester); assertEquals(11, hosts.size()); tester.activate(application, new HashSet<>(hosts)); - List<Node> nodes = tester.nodeRepository().getNodes(NodeType.proxy, Node.State.active); + List<Node> nodes = tester.nodeRepository().nodes().getNodes(NodeType.proxy, Node.State.active); assertEquals(11, nodes.size()); } @@ -70,20 +70,20 @@ public class NodeTypeProvisioningTest { List<HostSpec> hosts = deployProxies(application, tester); assertEquals(13, hosts.size()); tester.activate(application, new HashSet<>(hosts)); - List<Node> nodes = tester.nodeRepository().getNodes(NodeType.proxy, Node.State.active); + List<Node> nodes = tester.nodeRepository().nodes().getNodes(NodeType.proxy, Node.State.active); assertEquals(13, nodes.size()); } { // Remove 3 proxies then redeploy - List<Node> nodes = tester.nodeRepository().getNodes(NodeType.proxy, Node.State.active); - tester.nodeRepository().fail(nodes.get(0).hostname(), Agent.system, "Failing to unit test"); - tester.nodeRepository().fail(nodes.get(1).hostname(), Agent.system, "Failing to unit test"); - tester.nodeRepository().fail(nodes.get(5).hostname(), Agent.system, "Failing to unit test"); + List<Node> nodes = tester.nodeRepository().nodes().getNodes(NodeType.proxy, Node.State.active); + tester.nodeRepository().nodes().fail(nodes.get(0).hostname(), Agent.system, "Failing to unit test"); + tester.nodeRepository().nodes().fail(nodes.get(1).hostname(), Agent.system, "Failing to unit test"); + tester.nodeRepository().nodes().fail(nodes.get(5).hostname(), Agent.system, "Failing to unit test"); List<HostSpec> hosts = deployProxies(application, tester); assertEquals(10, hosts.size()); tester.activate(application, new HashSet<>(hosts)); - nodes = tester.nodeRepository().getNodes(NodeType.proxy, Node.State.active); + nodes = tester.nodeRepository().nodes().getNodes(NodeType.proxy, Node.State.active); assertEquals(10, nodes.size()); } } @@ -107,22 +107,22 @@ public class NodeTypeProvisioningTest { List<HostSpec> hosts = deployProxies(application, tester); assertEquals("Reserved all proxies", 11, hosts.size()); tester.activate(application, new HashSet<>(hosts)); - List<Node> nodes = tester.nodeRepository().getNodes(NodeType.proxy, Node.State.active); + List<Node> nodes = tester.nodeRepository().nodes().getNodes(NodeType.proxy, Node.State.active); assertEquals("Activated all proxies", 11, nodes.size()); } - Node nodeToRetire = tester.nodeRepository().getNodes(NodeType.proxy, Node.State.active).get(5); + Node nodeToRetire = tester.nodeRepository().nodes().getNodes(NodeType.proxy, Node.State.active).get(5); { // Pick out a node and retire it - tester.nodeRepository().write(nodeToRetire.withWantToRetire(true, Agent.system, tester.clock().instant()), () -> {}); + tester.nodeRepository().nodes().write(nodeToRetire.withWantToRetire(true, Agent.system, tester.clock().instant()), () -> {}); List<HostSpec> hosts = deployProxies(application, tester); assertEquals(11, hosts.size()); tester.activate(application, new HashSet<>(hosts)); - List<Node> nodes = tester.nodeRepository().getNodes(NodeType.proxy, Node.State.active); + List<Node> nodes = tester.nodeRepository().nodes().getNodes(NodeType.proxy, Node.State.active); assertEquals(11, nodes.size()); // Verify that wantToRetire has been propagated - assertTrue(tester.nodeRepository().getNode(nodeToRetire.hostname()) + assertTrue(tester.nodeRepository().nodes().getNode(nodeToRetire.hostname()) .flatMap(Node::allocation) .map(allocation -> allocation.membership().retired()) .orElseThrow(RuntimeException::new)); @@ -132,11 +132,11 @@ public class NodeTypeProvisioningTest { List<HostSpec> hosts = deployProxies(application, tester); assertEquals(11, hosts.size()); tester.activate(application, new HashSet<>(hosts)); - List<Node> nodes = tester.nodeRepository().getNodes(NodeType.proxy, Node.State.active); + List<Node> nodes = tester.nodeRepository().nodes().getNodes(NodeType.proxy, Node.State.active); assertEquals(11, nodes.size()); // Verify that the node is still marked as retired - assertTrue(tester.nodeRepository().getNode(nodeToRetire.hostname()) + assertTrue(tester.nodeRepository().nodes().getNode(nodeToRetire.hostname()) .flatMap(Node::allocation) .map(allocation -> allocation.membership().retired()) .orElseThrow(RuntimeException::new)); @@ -149,11 +149,11 @@ public class NodeTypeProvisioningTest { List<HostSpec> hosts = deployProxies(application, tester); assertEquals(10, hosts.size()); tester.activate(application, new HashSet<>(hosts)); - List<Node> nodes = tester.nodeRepository().getNodes(NodeType.proxy, Node.State.active); + List<Node> nodes = tester.nodeRepository().nodes().getNodes(NodeType.proxy, Node.State.active); assertEquals(10, nodes.size()); // Verify that the node is now inactive - assertEquals(Node.State.dirty, tester.nodeRepository().getNode(nodeToRetire.hostname()) + assertEquals(Node.State.dirty, tester.nodeRepository().nodes().getNode(nodeToRetire.hostname()) .orElseThrow(RuntimeException::new).state()); } } @@ -176,21 +176,21 @@ public class NodeTypeProvisioningTest { List<HostSpec> hosts = deployProxies(application, tester); assertEquals("Reserved all proxies", 11, hosts.size()); tester.activate(application, new HashSet<>(hosts)); - List<Node> nodes = tester.nodeRepository().getNodes(NodeType.proxy, Node.State.active); + List<Node> nodes = tester.nodeRepository().nodes().getNodes(NodeType.proxy, Node.State.active); assertEquals("Activated all proxies", 11, nodes.size()); } - List<Node> nodesToRetire = tester.nodeRepository().getNodes(NodeType.proxy, Node.State.active) + List<Node> nodesToRetire = tester.nodeRepository().nodes().getNodes(NodeType.proxy, Node.State.active) .subList(3, 3 + numNodesToRetire); String currentyRetiringHostname; { nodesToRetire.forEach(nodeToRetire -> - tester.nodeRepository().write(nodeToRetire.withWantToRetire(true, Agent.system, tester.clock().instant()), () -> {})); + tester.nodeRepository().nodes().write(nodeToRetire.withWantToRetire(true, Agent.system, tester.clock().instant()), () -> {})); List<HostSpec> hosts = deployProxies(application, tester); assertEquals(11, hosts.size()); tester.activate(application, new HashSet<>(hosts)); - List<Node> nodes = tester.nodeRepository().getNodes(NodeType.proxy, Node.State.active); + List<Node> nodes = tester.nodeRepository().nodes().getNodes(NodeType.proxy, Node.State.active); assertEquals(11, nodes.size()); // Verify that wantToRetire has been propagated @@ -208,7 +208,7 @@ public class NodeTypeProvisioningTest { List<HostSpec> hosts = deployProxies(application, tester); assertEquals(11, hosts.size()); tester.activate(application, new HashSet<>(hosts)); - List<Node> nodes = tester.nodeRepository().getNodes(NodeType.proxy, Node.State.active); + List<Node> nodes = tester.nodeRepository().nodes().getNodes(NodeType.proxy, Node.State.active); assertEquals(11, nodes.size()); // Verify that wantToRetire has been propagated @@ -228,11 +228,11 @@ public class NodeTypeProvisioningTest { List<HostSpec> hosts = deployProxies(application, tester); assertEquals(10, hosts.size()); tester.activate(application, new HashSet<>(hosts)); - List<Node> nodes = tester.nodeRepository().getNodes(NodeType.proxy, Node.State.active); + List<Node> nodes = tester.nodeRepository().nodes().getNodes(NodeType.proxy, Node.State.active); assertEquals(10, nodes.size()); // Verify the node we previously set to retire has finished retiring - assertEquals(Node.State.dirty, tester.nodeRepository().getNode(currentyRetiringHostname) + assertEquals(Node.State.dirty, tester.nodeRepository().nodes().getNode(currentyRetiringHostname) .orElseThrow(RuntimeException::new).state()); // Verify that a node is currently retiring @@ -257,7 +257,7 @@ public class NodeTypeProvisioningTest { } // After a long time, all currently active proxy nodes are not marked with wantToRetire or as retired - long numRetiredActiveProxyNodes = tester.nodeRepository().getNodes(NodeType.proxy, Node.State.active).stream() + long numRetiredActiveProxyNodes = tester.nodeRepository().nodes().getNodes(NodeType.proxy, Node.State.active).stream() .filter(node -> !node.status().wantToRetire()) .filter(node -> !node.allocation().get().membership().retired()) .count(); @@ -265,7 +265,7 @@ public class NodeTypeProvisioningTest { // All the nodes that were marked with wantToRetire earlier are now dirty assertEquals(nodesToRetire.stream().map(Node::hostname).collect(Collectors.toSet()), - tester.nodeRepository().getNodes(Node.State.dirty).stream().map(Node::hostname).collect(Collectors.toSet())); + tester.nodeRepository().nodes().getNodes(Node.State.dirty).stream().map(Node::hostname).collect(Collectors.toSet())); } private List<HostSpec> deployProxies(ApplicationId application, ProvisioningTester tester) { 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 7778077110a..33f33836b8d 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 @@ -95,7 +95,7 @@ public class ProvisioningTest { SystemState state5 = prepare(application1, 2, 2, 3, 3, defaultResources, tester); HostSpec removed = tester.removeOne(state5.allHosts); tester.activate(application1, state5.allHosts); - assertEquals(removed.hostname(), tester.nodeRepository().getNodes(application1, Node.State.inactive).get(0).hostname()); + assertEquals(removed.hostname(), tester.nodeRepository().nodes().getNodes(application1, Node.State.inactive).get(0).hostname()); // remove some of the clusters SystemState state6 = prepare(application1, 0, 2, 0, 3, defaultResources, tester); @@ -108,13 +108,13 @@ public class ProvisioningTest { NodeList previouslyInactive = tester.getNodes(application1, Node.State.inactive); tester.remove(application1); assertEquals(tester.toHostNames(previouslyActive.not().container().asList()), - tester.toHostNames(tester.nodeRepository().getNodes(application1, Node.State.inactive))); - assertTrue(tester.nodeRepository().getNodes(Node.State.dirty).containsAll(previouslyActive.container().asList())); + tester.toHostNames(tester.nodeRepository().nodes().getNodes(application1, Node.State.inactive))); + assertTrue(tester.nodeRepository().nodes().getNodes(Node.State.dirty).containsAll(previouslyActive.container().asList())); assertEquals(0, tester.getNodes(application1, Node.State.active).size()); assertTrue(tester.nodeRepository().applications().get(application1).isEmpty()); // other application is unaffected - assertEquals(state1App2.hostNames(), tester.toHostNames(tester.nodeRepository().getNodes(application2, Node.State.active))); + assertEquals(state1App2.hostNames(), tester.toHostNames(tester.nodeRepository().nodes().getNodes(application2, Node.State.active))); // fail a node from app2 and make sure it does not get inactive nodes from first HostSpec failed = tester.removeOne(state1App2.allHosts); @@ -127,7 +127,7 @@ public class ProvisioningTest { tester.activate(application2, state2App2.allHosts); // deploy first app again - tester.nodeRepository().setReady(tester.nodeRepository().getNodes(Node.State.dirty), Agent.system, "recycled"); + tester.nodeRepository().nodes().setReady(tester.nodeRepository().nodes().getNodes(Node.State.dirty), Agent.system, "recycled"); SystemState state7 = prepare(application1, 2, 2, 3, 3, defaultResources, tester); state7.assertEquals(state1); tester.activate(application1, state7.allHosts); @@ -160,8 +160,8 @@ public class ProvisioningTest { HostSpec host1 = state1.container0.iterator().next(); assertFalse(host1.version().isPresent()); - Node node1 = tester.nodeRepository().getNode(host1.hostname()).get(); - tester.nodeRepository().write(node1.with(node1.status().withVespaVersion(Version.fromString("1.2.3"))), () -> {}); + Node node1 = tester.nodeRepository().nodes().getNode(host1.hostname()).get(); + tester.nodeRepository().nodes().write(node1.with(node1.status().withVespaVersion(Version.fromString("1.2.3"))), () -> {}); // redeploy SystemState state2 = prepare(application1, 1, 1, 1, 1, defaultResources, tester); @@ -186,16 +186,16 @@ public class ProvisioningTest { tester.activate(application1, state1.allHosts); HostSpec host1 = state1.container0.iterator().next(); - Node node1 = tester.nodeRepository().getNode(host1.hostname()).get(); + Node node1 = tester.nodeRepository().nodes().getNode(host1.hostname()).get(); DockerImage dockerImage = DockerImage.fromString(dockerImageRepo).withTag(Version.fromString("1.2.3")); - tester.nodeRepository().write(node1.with(node1.status().withContainerImage(dockerImage)), () -> {}); + tester.nodeRepository().nodes().write(node1.with(node1.status().withContainerImage(dockerImage)), () -> {}); // redeploy SystemState state2 = prepare(application1, tester, 1, 1, 1 ,1 , false, defaultResources, "1.2.3", Optional.of(dockerImageRepo)); tester.activate(application1, state2.allHosts); host1 = state2.container0.iterator().next(); - node1 = tester.nodeRepository().getNode(host1.hostname()).get(); + node1 = tester.nodeRepository().nodes().getNode(host1.hostname()).get(); assertEquals(dockerImage, node1.status().containerImage().get()); } @@ -222,7 +222,7 @@ public class ProvisioningTest { SystemState state3 = prepare(application1, 2, 2, 3, 3, defaultResources, tester); tester.activate(application1, state3.allHosts); assertEquals("Superfluous container nodes are dirtyed", - 3-2 + 4-2, tester.nodeRepository().getNodes(Node.State.dirty).size()); + 3-2 + 4-2, tester.nodeRepository().nodes().getNodes(Node.State.dirty).size()); assertEquals("Superfluous content nodes are retired", 4-3 + 5-3, tester.getNodes(application1, Node.State.active).retired().size()); @@ -245,7 +245,7 @@ public class ProvisioningTest { SystemState state5 = prepare(application1, 2, 2, 3, 3, defaultResources, tester); tester.activate(application1, state5.allHosts); assertEquals("Superfluous container nodes are also dirtyed", - 4-2 + 5-2 + 1 + 4-2, tester.nodeRepository().getNodes(Node.State.dirty).size()); + 4-2 + 5-2 + 1 + 4-2, tester.nodeRepository().nodes().getNodes(Node.State.dirty).size()); assertEquals("Superfluous content nodes are retired", 5-3 + 6-3 - 1, tester.getNodes(application1, Node.State.active).retired().size()); @@ -289,7 +289,7 @@ public class ProvisioningTest { // redeploy with increased sizes and new flavor SystemState state3 = prepare(application1, 3, 4, 4, 5, large, tester); - assertEquals("New nodes are reserved", 16, tester.nodeRepository().getNodes(application1, Node.State.reserved).size()); + assertEquals("New nodes are reserved", 16, tester.nodeRepository().nodes().getNodes(application1, Node.State.reserved).size()); tester.activate(application1, state3.allHosts); assertEquals("small container nodes are retired because we are swapping the entire cluster", 2 + 2, tester.getNodes(application1, Node.State.active).retired().type(ClusterSpec.Type.container).resources(small).size()); @@ -316,8 +316,8 @@ public class ProvisioningTest { SystemState state1 = prepare(application1, 2, 2, 4, 4, small, tester); tester.activate(application1, state1.allHosts); - tester.nodeRepository().getNodes(application1) - .forEach(n -> assertEquals(large, tester.nodeRepository().getNode(n.parentHostname().get()).get().resources())); + tester.nodeRepository().nodes().getNodes(application1) + .forEach(n -> assertEquals(large, tester.nodeRepository().nodes().getNode(n.parentHostname().get()).get().resources())); } @Test @@ -374,7 +374,7 @@ public class ProvisioningTest { assertEquals(6, state.allHosts.size()); tester.activate(application, state.allHosts); assertTrue(state.allHosts.stream().allMatch(host -> host.requestedResources().get().diskSpeed() == NodeResources.DiskSpeed.any)); - assertTrue(tester.nodeRepository().getNodes(application).stream().allMatch(node -> node.allocation().get().requestedResources().diskSpeed() == NodeResources.DiskSpeed.any)); + assertTrue(tester.nodeRepository().nodes().getNodes(application).stream().allMatch(node -> node.allocation().get().requestedResources().diskSpeed() == NodeResources.DiskSpeed.any)); } { @@ -386,7 +386,7 @@ public class ProvisioningTest { assertEquals(8, state.allHosts.size()); tester.activate(application, state.allHosts); assertTrue(state.allHosts.stream().allMatch(host -> host.requestedResources().get().diskSpeed() == NodeResources.DiskSpeed.fast)); - assertTrue(tester.nodeRepository().getNodes(application).stream().allMatch(node -> node.allocation().get().requestedResources().diskSpeed() == NodeResources.DiskSpeed.fast)); + assertTrue(tester.nodeRepository().nodes().getNodes(application).stream().allMatch(node -> node.allocation().get().requestedResources().diskSpeed() == NodeResources.DiskSpeed.fast)); } { @@ -397,7 +397,7 @@ public class ProvisioningTest { assertEquals(8, state.allHosts.size()); tester.activate(application, state.allHosts); assertTrue(state.allHosts.stream().allMatch(host -> host.requestedResources().get().diskSpeed() == NodeResources.DiskSpeed.any)); - assertTrue(tester.nodeRepository().getNodes(application).stream().allMatch(node -> node.allocation().get().requestedResources().diskSpeed() == NodeResources.DiskSpeed.any)); + assertTrue(tester.nodeRepository().nodes().getNodes(application).stream().allMatch(node -> node.allocation().get().requestedResources().diskSpeed() == NodeResources.DiskSpeed.any)); } } @@ -692,25 +692,25 @@ public class ProvisioningTest { // Allocate 5 nodes ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("music")).vespaVersion("4.5.6").build(); tester.activate(application, tester.prepare(application, cluster, capacity)); - assertEquals(5, NodeList.copyOf(tester.nodeRepository().getNodes(application, Node.State.active)).not().retired().size()); - assertEquals(0, NodeList.copyOf(tester.nodeRepository().getNodes(application, Node.State.active)).retired().size()); + assertEquals(5, NodeList.copyOf(tester.nodeRepository().nodes().getNodes(application, Node.State.active)).not().retired().size()); + assertEquals(0, NodeList.copyOf(tester.nodeRepository().nodes().getNodes(application, Node.State.active)).retired().size()); // Mark the nodes as want to retire - tester.nodeRepository().getNodes(application, Node.State.active).forEach(node -> tester.patchNode(node, (n) -> n.withWantToRetire(true, Agent.system, tester.clock().instant()))); + tester.nodeRepository().nodes().getNodes(application, Node.State.active).forEach(node -> tester.patchNode(node, (n) -> n.withWantToRetire(true, Agent.system, tester.clock().instant()))); // redeploy without allow failing tester.activate(application, tester.prepare(application, cluster, capacityFORCED)); // Nodes are not retired since that is unsafe when we cannot fail - assertEquals(5, NodeList.copyOf(tester.nodeRepository().getNodes(application, Node.State.active)).not().retired().size()); - assertEquals(0, NodeList.copyOf(tester.nodeRepository().getNodes(application, Node.State.active)).retired().size()); + assertEquals(5, NodeList.copyOf(tester.nodeRepository().nodes().getNodes(application, Node.State.active)).not().retired().size()); + assertEquals(0, NodeList.copyOf(tester.nodeRepository().nodes().getNodes(application, Node.State.active)).retired().size()); // ... but we still want to - tester.nodeRepository().getNodes(application, Node.State.active).forEach(node -> assertTrue(node.status().wantToRetire())); + tester.nodeRepository().nodes().getNodes(application, Node.State.active).forEach(node -> assertTrue(node.status().wantToRetire())); // redeploy with allowing failing tester.activate(application, tester.prepare(application, cluster, capacity)); // ... old nodes are now retired - assertEquals(5, NodeList.copyOf(tester.nodeRepository().getNodes(application, Node.State.active)).not().retired().size()); - assertEquals(5, NodeList.copyOf(tester.nodeRepository().getNodes(application, Node.State.active)).retired().size()); + assertEquals(5, NodeList.copyOf(tester.nodeRepository().nodes().getNodes(application, Node.State.active)).not().retired().size()); + assertEquals(5, NodeList.copyOf(tester.nodeRepository().nodes().getNodes(application, Node.State.active)).retired().size()); } @Test @@ -723,17 +723,17 @@ public class ProvisioningTest { ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("music")).vespaVersion("4.5.6").build(); tester.activate(application, tester.prepare(application, cluster, capacityCanFail)); - assertEquals(0, NodeList.copyOf(tester.nodeRepository().getNodes(application, Node.State.active)).retired().size()); + assertEquals(0, NodeList.copyOf(tester.nodeRepository().nodes().getNodes(application, Node.State.active)).retired().size()); - tester.patchNode(tester.nodeRepository().getNodes(application).stream().findAny().orElseThrow(), n -> n.withWantToRetire(true, Agent.system, tester.clock().instant())); + tester.patchNode(tester.nodeRepository().nodes().getNodes(application).stream().findAny().orElseThrow(), n -> n.withWantToRetire(true, Agent.system, tester.clock().instant())); tester.activate(application, tester.prepare(application, cluster, capacityCanFail)); - assertEquals(1, NodeList.copyOf(tester.nodeRepository().getNodes(application, Node.State.active)).retired().size()); - assertEquals(6, tester.nodeRepository().getNodes(application, Node.State.active).size()); + assertEquals(1, NodeList.copyOf(tester.nodeRepository().nodes().getNodes(application, Node.State.active)).retired().size()); + assertEquals(6, tester.nodeRepository().nodes().getNodes(application, Node.State.active).size()); Capacity capacityCannotFail = Capacity.from(new ClusterResources(5, 1, defaultResources), false, false); tester.activate(application, tester.prepare(application, cluster, capacityCannotFail)); - assertEquals(1, NodeList.copyOf(tester.nodeRepository().getNodes(application, Node.State.active)).retired().size()); - assertEquals(6, tester.nodeRepository().getNodes(application, Node.State.active).size()); + assertEquals(1, NodeList.copyOf(tester.nodeRepository().nodes().getNodes(application, Node.State.active)).retired().size()); + assertEquals(6, tester.nodeRepository().nodes().getNodes(application, Node.State.active).size()); } @Test @@ -777,14 +777,14 @@ public class ProvisioningTest { tester.deploy(application, spec, Capacity.from(new ClusterResources(6, 1, defaultResources))); // Pick out a random application node and make it's parent larger, this will make it the spare host - NodeList nodes = tester.nodeRepository().list(); + NodeList nodes = tester.nodeRepository().nodes().list(); Node randomNode = nodes.owner(application).shuffle(new Random()).first().get(); - tester.nodeRepository().write(nodes.parentOf(randomNode).get().with(new Flavor(new NodeResources(2, 10, 20, 8))), () -> {}); + tester.nodeRepository().nodes().write(nodes.parentOf(randomNode).get().with(new Flavor(new NodeResources(2, 10, 20, 8))), () -> {}); // Re-deploy application with 1 node less, the retired node should be on the spare host tester.deploy(application, spec, Capacity.from(new ClusterResources(5, 1, defaultResources))); - assertTrue(tester.nodeRepository().getNode(randomNode.hostname()).get().allocation().get().membership().retired()); + assertTrue(tester.nodeRepository().nodes().getNode(randomNode.hostname()).get().allocation().get().membership().retired()); } @Test @@ -892,7 +892,7 @@ public class ProvisioningTest { 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.nodeRepository().setReady(tester.nodeRepository().addNodes(nodes, Agent.system), Agent.system, ProvisioningTest.class.getSimpleName()); + tester.nodeRepository().nodes().setReady(tester.nodeRepository().nodes().addNodes(nodes, Agent.system), Agent.system, ProvisioningTest.class.getSimpleName()); InfraApplication cfgHostApp = new ConfigServerHostApplication(); InfraApplication cfgApp = new ConfigServerApplication(); @@ -901,13 +901,13 @@ public class ProvisioningTest { try { prepareAndActivate.apply(cfgApp); } catch (ParentHostUnavailableException ignored) { } - assertEquals(2, tester.nodeRepository().list(cfgApp.getApplicationId()).state(Node.State.reserved).size()); + assertEquals(2, tester.nodeRepository().nodes().list(cfgApp.getApplicationId()).state(Node.State.reserved).size()); prepareAndActivate.apply(cfgHostApp); // After activating cfg hosts, we can activate cfgs and all 4 should become active prepareAndActivate.apply(cfgApp); - assertEquals(4, tester.nodeRepository().list().state(Node.State.active).size()); + assertEquals(4, tester.nodeRepository().nodes().list().state(Node.State.active).size()); } @Test 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 7c43a8d5859..fde02c083dd 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 @@ -143,7 +143,7 @@ public class ProvisioningTester { public NodeRepositoryProvisioner provisioner() { return provisioner; } public LoadBalancerServiceMock loadBalancerService() { return loadBalancerService; } public CapacityPolicies capacityPolicies() { return capacityPolicies; } - public NodeList getNodes(ApplicationId id, Node.State ... inState) { return NodeList.copyOf(nodeRepository.getNodes(id, inState)); } + public NodeList getNodes(ApplicationId id, Node.State ... inState) { return NodeList.copyOf(nodeRepository.nodes().getNodes(id, inState)); } public Node patchNode(Node node, UnaryOperator<Node> patcher) { return patchNodes(List.of(node), patcher).get(0); @@ -152,9 +152,9 @@ public class ProvisioningTester { public List<Node> patchNodes(List<Node> nodes, UnaryOperator<Node> patcher) { List<Node> updated = new ArrayList<>(); for (var node : nodes) { - try (var lock = nodeRepository.lockAndGetRequired(node)) { + try (var lock = nodeRepository.nodes().lockAndGetRequired(node)) { node = patcher.apply(lock.node()); - nodeRepository.write(node, lock); + nodeRepository.nodes().write(node, lock); updated.add(node); } } @@ -170,12 +170,12 @@ public class ProvisioningTester { } public List<HostSpec> prepare(ApplicationId application, ClusterSpec cluster, Capacity capacity) { - Set<String> reservedBefore = toHostNames(nodeRepository.getNodes(application, Node.State.reserved)); - Set<String> inactiveBefore = toHostNames(nodeRepository.getNodes(application, Node.State.inactive)); + Set<String> reservedBefore = toHostNames(nodeRepository.nodes().getNodes(application, Node.State.reserved)); + Set<String> inactiveBefore = toHostNames(nodeRepository.nodes().getNodes(application, Node.State.inactive)); List<HostSpec> hosts1 = provisioner.prepare(application, cluster, capacity, provisionLogger); List<HostSpec> hosts2 = provisioner.prepare(application, cluster, capacity, provisionLogger); assertEquals("Prepare is idempotent", hosts1, hosts2); - Set<String> newlyActivated = toHostNames(nodeRepository.getNodes(application, Node.State.reserved)); + Set<String> newlyActivated = toHostNames(nodeRepository.nodes().getNodes(application, Node.State.reserved)); newlyActivated.removeAll(reservedBefore); newlyActivated.removeAll(inactiveBefore); return hosts1; @@ -186,19 +186,19 @@ public class ProvisioningTester { // Add ip addresses and activate parent host if necessary for (HostSpec prepared : preparedNodes) { - try (var lock = nodeRepository.lockAndGetRequired(prepared.hostname())) { + try (var lock = nodeRepository.nodes().lockAndGetRequired(prepared.hostname())) { Node node = lock.node(); if (node.ipConfig().primary().isEmpty()) { node = node.with(new IP.Config(Set.of("::" + 0 + ":0"), Set.of())); - nodeRepository.write(node, lock); + nodeRepository.nodes().write(node, lock); } if (node.parentHostname().isEmpty()) continue; - Node parent = nodeRepository.getNode(node.parentHostname().get()).get(); + Node parent = nodeRepository.nodes().getNode(node.parentHostname().get()).get(); if (parent.state() == Node.State.active) continue; NestedTransaction t = new NestedTransaction(); if (parent.ipConfig().primary().isEmpty()) parent = parent.with(new IP.Config(Set.of("::" + 0 + ":0"), Set.of("::" + 0 + ":2"))); - nodeRepository.activate(List.of(parent), t); + nodeRepository.nodes().activate(List.of(parent), t); t.commit(); } } @@ -213,7 +213,7 @@ public class ProvisioningTester { provisioner.activate(hosts, new ActivationContext(0), new ApplicationTransaction(lock, transaction)); transaction.commit(); } - assertEquals(toHostNames(hosts), toHostNames(nodeRepository.getNodes(application, Node.State.active))); + assertEquals(toHostNames(hosts), toHostNames(nodeRepository.nodes().getNodes(application, Node.State.active))); return hosts; } @@ -238,7 +238,7 @@ public class ProvisioningTester { } public void deactivate(ApplicationId applicationId) { - try (var lock = nodeRepository.lock(applicationId)) { + try (var lock = nodeRepository.nodes().lock(applicationId)) { NestedTransaction deactivateTransaction = new NestedTransaction(); nodeRepository.remove(new ApplicationTransaction(new ProvisionLock(applicationId, lock), deactivateTransaction)); @@ -259,7 +259,7 @@ public class ProvisioningTester { * number of matches to the given filters */ public void assertRestartCount(ApplicationId application, HostFilter... filters) { - for (Node node : nodeRepository.getNodes(application, Node.State.active)) { + for (Node node : nodeRepository.nodes().getNodes(application, Node.State.active)) { int expectedRestarts = 0; for (HostFilter filter : filters) if (NodeHostFilter.from(filter).matches(node)) @@ -291,7 +291,7 @@ public class ProvisioningTester { double vcpu, double memory, double disk, double bandwidth, DiskSpeed diskSpeed, StorageType storageType, ApplicationId app, ClusterSpec cluster) { - List<Node> nodeList = nodeRepository.list().owner(app).cluster(cluster.id()).state(Node.State.active).not().retired().asList(); + List<Node> nodeList = nodeRepository.nodes().list().owner(app).cluster(cluster.id()).state(Node.State.active).not().retired().asList(); assertEquals(explanation + ": Node count", nodes, nodeList.size()); @@ -316,9 +316,9 @@ public class ProvisioningTester { } public void fail(String hostname) { - int beforeFailCount = nodeRepository.getNode(hostname, Node.State.active).get().status().failCount(); - Node failedNode = nodeRepository.fail(hostname, Agent.system, "Failing to unit test"); - assertTrue(nodeRepository.getNodes(NodeType.tenant, Node.State.failed).contains(failedNode)); + int beforeFailCount = nodeRepository.nodes().getNode(hostname, Node.State.active).get().status().failCount(); + Node failedNode = nodeRepository.nodes().fail(hostname, Agent.system, "Failing to unit test"); + assertTrue(nodeRepository.nodes().getNodes(NodeType.tenant, Node.State.failed).contains(failedNode)); assertEquals(beforeFailCount + 1, failedNode.status().failCount()); } @@ -437,7 +437,7 @@ public class ProvisioningTester { reservedTo.ifPresent(builder::reservedTo); nodes.add(builder.build()); } - nodes = nodeRepository.addNodes(nodes, Agent.system); + nodes = nodeRepository.nodes().addNodes(nodes, Agent.system); return nodes; } @@ -455,16 +455,16 @@ public class ProvisioningTester { nodes.add(node); } - nodes = nodeRepository.addNodes(nodes, Agent.system); - nodes = nodeRepository.deallocate(nodes, Agent.system, getClass().getSimpleName()); - nodeRepository.setReady(nodes, Agent.system, getClass().getSimpleName()); + nodes = nodeRepository.nodes().addNodes(nodes, Agent.system); + nodes = nodeRepository.nodes().deallocate(nodes, Agent.system, getClass().getSimpleName()); + nodeRepository.nodes().setReady(nodes, Agent.system, getClass().getSimpleName()); ConfigServerApplication application = new ConfigServerApplication(); List<HostSpec> hosts = prepare(application.getApplicationId(), application.getClusterSpecWithVersion(configServersVersion), application.getCapacity()); activate(application.getApplicationId(), new HashSet<>(hosts)); - return nodeRepository.getNodes(application.getApplicationId(), Node.State.active); + return nodeRepository.nodes().getNodes(application.getApplicationId(), Node.State.active); } public List<Node> makeReadyNodes(int n, String flavor, NodeType type, int ipAddressPoolSize) { @@ -482,8 +482,8 @@ public class ProvisioningTester { } public List<Node> makeReadyNodes(int n, Flavor flavor, Optional<TenantName> reservedTo, NodeType type, int ipAddressPoolSize, boolean dualStack) { List<Node> nodes = makeProvisionedNodes(n, flavor, reservedTo, type, ipAddressPoolSize, dualStack); - nodes = nodeRepository.deallocate(nodes, Agent.system, getClass().getSimpleName()); - return nodeRepository.setReady(nodes, Agent.system, getClass().getSimpleName()); + nodes = nodeRepository.nodes().deallocate(nodes, Agent.system, getClass().getSimpleName()); + return nodeRepository.nodes().setReady(nodes, Agent.system, getClass().getSimpleName()); } private Flavor asFlavor(String flavorString, NodeType type) { @@ -522,9 +522,9 @@ public class ProvisioningTester { parentHostname.ifPresent(builder::parentHostname); nodes.add(builder.build()); } - nodes = nodeRepository.addNodes(nodes, Agent.system); - nodes = nodeRepository.deallocate(nodes, Agent.system, getClass().getSimpleName()); - nodeRepository.setReady(nodes, Agent.system, getClass().getSimpleName()); + nodes = nodeRepository.nodes().addNodes(nodes, Agent.system); + nodes = nodeRepository.nodes().deallocate(nodes, Agent.system, getClass().getSimpleName()); + nodeRepository.nodes().setReady(nodes, Agent.system, getClass().getSimpleName()); return nodes; } @@ -560,20 +560,20 @@ public class ProvisioningTester { } public void assertAllocatedOn(String explanation, String hostFlavor, ApplicationId app) { - for (Node node : nodeRepository.getNodes(app)) { - Node parent = nodeRepository.getNode(node.parentHostname().get()).get(); + for (Node node : nodeRepository.nodes().getNodes(app)) { + Node parent = nodeRepository.nodes().getNode(node.parentHostname().get()).get(); assertEquals(node + ": " + explanation, hostFlavor, parent.flavor().name()); } } public void assertSwitches(Set<String> expectedSwitches, ApplicationId application, ClusterSpec.Id cluster) { - NodeList allNodes = nodeRepository.list(); + NodeList allNodes = nodeRepository.nodes().list(); NodeList activeNodes = allNodes.owner(application).state(Node.State.active).cluster(cluster); assertEquals(expectedSwitches, switchesOf(activeNodes, allNodes)); } public List<Node> activeNodesOn(String switchHostname, ApplicationId application, ClusterSpec.Id cluster) { - NodeList allNodes = nodeRepository.list(); + NodeList allNodes = nodeRepository.nodes().list(); NodeList activeNodes = allNodes.state(Node.State.active).owner(application).cluster(cluster); return activeNodes.stream().filter(node -> { Optional<String> allocatedSwitchHostname = allNodes.parentOf(node).flatMap(Node::switchHostname); @@ -594,8 +594,8 @@ public class ProvisioningTester { } public int hostFlavorCount(String hostFlavor, ApplicationId app) { - return (int)nodeRepository().getNodes(app).stream() - .map(n -> nodeRepository().getNode(n.parentHostname().get()).get()) + return (int)nodeRepository().nodes().getNodes(app).stream() + .map(n -> nodeRepository().nodes().getNode(n.parentHostname().get()).get()) .filter(p -> p.flavor().name().equals(hostFlavor)) .count(); } |