diff options
Diffstat (limited to 'node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java')
-rw-r--r-- | node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java | 146 |
1 files changed, 21 insertions, 125 deletions
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 8e14b61db9a..2642983dd2a 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 @@ -20,10 +20,7 @@ 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.LoadBalancer; -import com.yahoo.vespa.hosted.provision.lb.LoadBalancerId; -import com.yahoo.vespa.hosted.provision.lb.LoadBalancerInstance; -import com.yahoo.vespa.hosted.provision.lb.LoadBalancerList; +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; @@ -50,17 +47,13 @@ import java.time.Clock; import java.time.Duration; import java.time.Instant; import java.util.ArrayList; -import java.util.Comparator; import java.util.EnumSet; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; -import java.util.TreeSet; import java.util.function.BiFunction; -import java.util.function.Predicate; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -111,6 +104,7 @@ public class NodeRepository extends AbstractComponent { private final ContainerImages containerImages; private final JobControl jobControl; private final Applications applications; + private final LoadBalancers loadBalancers; private final int spareCount; /** @@ -171,6 +165,7 @@ public class NodeRepository extends AbstractComponent { this.containerImages = new ContainerImages(db, containerImage); this.jobControl = new JobControl(new JobControlFlags(db, flagSource)); this.applications = new Applications(db); + this.loadBalancers = new LoadBalancers(db); this.spareCount = spareCount; rewriteNodes(); } @@ -213,15 +208,30 @@ public class NodeRepository extends AbstractComponent { /** Returns this node repo's view of the applications deployed to it */ public Applications applications() { return applications; } - public NodeFlavors flavors() { - return flavors; - } + /** Returns the load balancers available in this node repo */ + public LoadBalancers loadBalancers() { return loadBalancers; } + + public NodeFlavors flavors() { return flavors; } public HostResourcesCalculator resourcesCalculator() { return resourcesCalculator; } /** The number of nodes we should ensure has free capacity for node failures whenever possible */ public int spareCount() { return spareCount; } + /** + * Returns ACLs for the children of the given host. + * + * @param host node for which to generate ACLs + * @return the list of node ACLs + */ + 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() + .map(childNode -> childNode.acl(allNodes, loadBalancers)) + .collect(Collectors.toUnmodifiableList()); + } + // ---------------- Query API ---------------------------------------------------------------- /** @@ -274,125 +284,11 @@ public class NodeRepository extends AbstractComponent { return new LockedNodeList(getNodes(), lock); } - /** Returns a filterable list of all load balancers in this repository */ - public LoadBalancerList loadBalancers() { - return loadBalancers((ignored) -> true); - } - - /** Returns a filterable list of load balancers belonging to given application */ - public LoadBalancerList loadBalancers(ApplicationId application) { - return loadBalancers((id) -> id.application().equals(application)); - } - - private LoadBalancerList loadBalancers(Predicate<LoadBalancerId> predicate) { - return LoadBalancerList.copyOf(db.readLoadBalancers(predicate).values()); - } - 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 the ACL for the node (trusted nodes, networks and ports) - */ - private NodeAcl getNodeAcl(Node node, NodeList candidates) { - Set<Node> trustedNodes = new TreeSet<>(Comparator.comparing(Node::hostname)); - Set<Integer> trustedPorts = new LinkedHashSet<>(); - Set<String> trustedNetworks = new LinkedHashSet<>(); - - // For all cases below, trust: - // - SSH: If the Docker host has one container, and it is using the Docker host's network namespace, - // opening up SSH to the Docker host is done here as a trusted port. For simplicity all nodes have - // SSH opened (which is safe for 2 reasons: SSH daemon is not run inside containers, and NPT networks - // will (should) not forward port 22 traffic to container). - // - parent host (for health checks and metrics) - // - nodes in same application - // - load balancers allocated to application - trustedPorts.add(22); - candidates.parentOf(node).ifPresent(trustedNodes::add); - node.allocation().ifPresent(allocation -> { - trustedNodes.addAll(candidates.owner(allocation.owner()).asList()); - loadBalancers(allocation.owner()).asList().stream() - .map(LoadBalancer::instance) - .map(LoadBalancerInstance::networks) - .forEach(trustedNetworks::addAll); - }); - - switch (node.type()) { - case tenant: - // Tenant nodes in other states than ready, trust: - // - config servers - // - proxy nodes - // - parents of the nodes in the same application: If some of the nodes are on a different IP versions - // or only a subset of them are dual-stacked, the communication between the nodes may be NATed - // with via parent's IP address. - trustedNodes.addAll(candidates.nodeType(NodeType.config).asList()); - trustedNodes.addAll(candidates.nodeType(NodeType.proxy).asList()); - node.allocation().ifPresent(allocation -> - trustedNodes.addAll(candidates.parentsOf(candidates.owner(allocation.owner())).asList())); - - if (node.state() == State.ready) { - // Tenant nodes in state ready, trust: - // - All tenant nodes in zone. When a ready node is allocated to a an application there's a brief - // window where current ACLs have not yet been applied on the node. To avoid service disruption - // during this window, ready tenant nodes trust all other tenant nodes. - trustedNodes.addAll(candidates.nodeType(NodeType.tenant).asList()); - } - break; - - case config: - // Config servers trust: - // - all nodes - // - port 4443 from the world - trustedNodes.addAll(candidates.asList()); - trustedPorts.add(4443); - break; - - case proxy: - // Proxy nodes trust: - // - config servers - // - all connections from the world on 4080 (insecure tb removed), and 4443 - trustedNodes.addAll(candidates.nodeType(NodeType.config).asList()); - trustedPorts.add(443); - trustedPorts.add(4080); - trustedPorts.add(4443); - break; - - case controller: - // Controllers: - // - port 4443 (HTTPS + Athenz) from the world - // - port 443 (HTTPS + Okta) from the world - // - port 80 (HTTP) from the world - for redirect to HTTPS/443 only - trustedPorts.add(4443); - trustedPorts.add(443); - trustedPorts.add(80); - break; - - default: - illegal("Don't know how to create ACL for " + node + " of type " + node.type()); - } - - return new NodeAcl(node, trustedNodes, trustedNetworks, trustedPorts); - } - - /** - * Creates a list of node ACLs which identify which nodes the given node should trust - * - * @param node Node for which to generate ACLs - * @param children Return ACLs for the children of the given node (e.g. containers on a Docker host) - * @return List of node ACLs - */ - public List<NodeAcl> getNodeAcls(Node node, boolean children) { - NodeList candidates = list(); - if (children) { - return candidates.childrenOf(node).asList().stream() - .map(childNode -> getNodeAcl(childNode, candidates)) - .collect(Collectors.toUnmodifiableList()); - } - return List.of(getNodeAcl(node, candidates)); - } - - /** * 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. |