/** * @return {@link NodeType} of the node(s) that run on this host * @throws IllegalStateException if this type is not a host */ public NodeType childNodeType() { if (! isDockerHost()) throw new IllegalStateException(this + " has no children"); return childNodeType; } }
/** * 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.getNodes(inState).stream().filter(node -> node.type().equals(type)).collect(Collectors.toList()); }
public String toString(NodeType type) { switch (type) { case tenant: return "tenant"; case host: return "host"; case proxy: return "proxy"; case proxyhost: return "proxyhost"; case config: return "config"; case confighost: return "confighost"; case controller: return "controller"; case controllerhost: return "controllerhost"; default: throw new IllegalArgumentException("Unknown node type '" + type.name() + "'"); } }
object.setString("id", node.hostname()); object.setString("state", serializer.toString(node.state())); object.setString("type", node.type().name()); object.setString("hostname", node.hostname()); object.setString("type", serializer.toString(node.type())); nodeRepository.osVersions().targetFor(node.type()).ifPresent(version -> object.setString("wantedOsVersion", version.toFullString())); node.status().firmwareVerifiedAt().ifPresent(instant -> object.setLong("currentFirmwareCheck", instant.toEpochMilli())); if (node.type().isDockerHost()) nodeRepository.firmwareChecks().requiredAfter().ifPresent(after -> object.setLong("wantedFirmwareCheck", after.toEpochMilli())); node.status().vespaVersion()
private List<Container> createNodesFromNodeType(ContainerCluster cluster, Element nodesElement, ConfigModelContext context) { NodeType type = NodeType.valueOf(nodesElement.getAttribute("type")); ClusterSpec clusterSpec = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from(cluster.getName()), context.getDeployState().getWantedNodeVespaVersion(), false, Collections.emptySet()); Map<HostResource, ClusterMembership> hosts = cluster.getRoot().getHostSystem().allocateHosts(clusterSpec, Capacity.fromRequiredNodeType(type), 1, log); return createNodesFromHosts(context.getDeployLogger(), hosts, cluster); }
/** Outputs the nodes in the given state to a node array */ private void nodesToSlime(Node.State state, Cursor parentObject) { Cursor nodeArray = parentObject.setArray("nodes"); for (NodeType type : NodeType.values()) toSlime(nodeRepository.getNodes(type, state), nodeArray); }
private MessageResponse setTargetVersions(HttpRequest request) { NodeType nodeType = NodeType.valueOf(lastElement(request.getUri().getPath()).toLowerCase()); Inspector inspector = toSlime(request.getData()).get(); List<String> messageParts = new ArrayList<>(3); boolean force = inspector.field("force").asBool(); Inspector versionField = inspector.field("version"); Inspector osVersionField = inspector.field("osVersion"); if (versionField.valid()) { Version version = Version.fromString(versionField.asString()); maintenance.infrastructureVersions().setTargetVersion(nodeType, version, force); messageParts.add("version to " + version.toFullString()); } if (osVersionField.valid()) { String v = osVersionField.asString(); if (v.isEmpty()) { nodeRepository.osVersions().removeTarget(nodeType); messageParts.add("osVersion to null"); } else { Version osVersion = Version.fromString(v); nodeRepository.osVersions().setTarget(nodeType, osVersion, force); messageParts.add("osVersion to " + osVersion.toFullString()); } } if (messageParts.isEmpty()) { throw new IllegalArgumentException("At least one of 'version' and 'osVersion' must be set"); } return new MessageResponse("Set " + String.join(", ", messageParts) + " for nodes of type " + nodeType); }
private boolean expectConfigRequests(Node node) { return !node.type().isDockerHost() || configserverConfig.nodeAdminInContainer(); }
public int freeCapacityInFlavorEquivalence(Flavor flavor) { return allNodes.asList().stream() .filter(n -> n.type().equals(NodeType.host)) .map(n -> canFitNumberOf(n, flavor)) .reduce(0, (a, b) -> a + b); }
@Override public void render(OutputStream stream) throws IOException { Slime slime = new Slime(); Cursor root = slime.setObject(); Cursor versionsObject = root.setObject("versions"); infrastructureVersions.getTargetVersions().forEach((nodeType, version) -> versionsObject.setString(nodeType.name(), version.toFullString())); Cursor osVersionsObject = root.setObject("osVersions"); osVersions.targets().forEach((nodeType, version) -> osVersionsObject.setString(nodeType.name(), version.toFullString())); new JsonFormat(true).encode(stream, slime); }
public List<Node> dirtyRecursively(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().isDockerHost() ? 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) .map(Node::hostname) .collect(Collectors.toList()); if (!hostnamesNotAllowedToDirty.isEmpty()) { throw new IllegalArgumentException("Could not deallocate " + hostname + ": " + String.join(", ", hostnamesNotAllowedToDirty) + " must be in either provisioned, failed or parked state"); } return nodesToDirty.stream() .map(node -> setDirty(node, agent, reason)) .collect(Collectors.toList()); }
public ResourceCapacity getCapacityTotal() { return allNodes.asList().stream() .filter(n -> n.type().equals(NodeType.host)) .map(ResourceCapacity::new) .reduce(new ResourceCapacity(), ResourceCapacity::add); }
private void toSlime(NodeAcl nodeAcl, Cursor array) { nodeAcl.trustedNodes().forEach(node -> node.ipAddresses().forEach(ipAddress -> { Cursor object = array.addObject(); object.setString("hostname", node.hostname()); object.setString("type", node.type().name()); object.setString("ipAddress", ipAddress); object.setString("trustedBy", nodeAcl.node().hostname()); })); }
/** Set the target OS version for nodes of given type */ public void setTarget(NodeType nodeType, Version newTarget, boolean force) { if (!nodeType.isDockerHost()) { throw new IllegalArgumentException("Setting target OS version for " + nodeType + " nodes is unsupported"); } if (newTarget.isEmpty()) { throw new IllegalArgumentException("Invalid target version: " + newTarget.toFullString()); } try (Lock lock = db.lockOsVersions()) { Map<NodeType, Version> osVersions = db.readOsVersions(); Optional<Version> oldTarget = Optional.ofNullable(osVersions.get(nodeType)); if (oldTarget.filter(v -> v.equals(newTarget)).isPresent()) { return; // Old target matches new target, nothing to do } if (!force && oldTarget.filter(v -> v.isAfter(newTarget)).isPresent()) { throw new IllegalArgumentException("Cannot set target OS version to " + newTarget + " without setting 'force', as it's lower than the current version: " + oldTarget.get()); } osVersions.put(nodeType, newTarget); db.writeOsVersions(osVersions); createCache(); // Throw away current cache log.info("Set OS target version for " + nodeType + " nodes to " + newTarget.toFullString()); } }
public ResourceCapacity getFreeCapacityTotal() { return allNodes.asList().stream() .filter(n -> n.type().equals(NodeType.host)) .map(n -> freeCapacityOf(n, false)) .reduce(new ResourceCapacity(), ResourceCapacity::add); }
private List<Node> removeRecursively(Node node, boolean force) { try (Mutex lock = lockAllocation()) { List<Node> removed = new ArrayList<>(); if (node.type().isDockerHost()) { list().childrenOf(node).asList().stream() .filter(child -> force || canRemove(child, true)) .forEach(removed::add); } if (force || canRemove(node, false)) removed.add(node); db.removeNodes(removed); return removed; } catch (RuntimeException e) { throw new IllegalArgumentException("Failed to delete " + node.hostname(), e); } }
/** * Spare hosts are the two hosts in the system with the most free capacity. * * We do not count retired or inactive nodes as used capacity (as they could have been * moved to create space for the spare node in the first place). */ private static Set<Node> findSpareHosts(List<Node> nodes, int spares) { DockerHostCapacity capacity = new DockerHostCapacity(new ArrayList<>(nodes)); return nodes.stream() .filter(node -> node.type().equals(NodeType.host)) .filter(dockerHost -> dockerHost.state().equals(Node.State.active)) .filter(dockerHost -> capacity.freeIPs(dockerHost) > 0) .sorted(capacity::compareWithoutInactive) .limit(spares) .collect(Collectors.toSet()); }
/** Move eligible nodes to dirty. This may be a subset of the given nodes */ private void recycle(List<Node> nodes) { List<Node> nodesToRecycle = new ArrayList<>(); for (Node candidate : nodes) { if (hasHardwareIssue(candidate)) { List<String> unparkedChildren = !candidate.type().isDockerHost() ? Collections.emptyList() : nodeRepository.list().childrenOf(candidate).asList().stream() .filter(node -> node.state() != Node.State.parked) .map(Node::hostname) .collect(Collectors.toList()); if (unparkedChildren.isEmpty()) { nodeRepository.park(candidate.hostname(), Agent.system, "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(), String.join(", ", unparkedChildren))); } } else if (!failCountIndicatesHardwareIssue(candidate)) { nodesToRecycle.add(candidate); } } nodeRepository.setDirty(nodesToRecycle, Agent.system, "Expired by FailedExpirer"); }
/** * Add nodes already provisioned, but not allocated to any application */ void addReadyNodes() { allNodes.stream() .filter(node -> node.type().equals(requestedNodes.type())) .filter(node -> node.state().equals(Node.State.ready)) .map(node -> toNodePriority(node, false, false)) .filter(n -> !n.violatesSpares || isAllocatingForReplacement) .forEach(prioritizableNode -> nodes.put(prioritizableNode.node, prioritizableNode)); }
/** Returns whether to reboot node as part of transition to given state. This is done to get rid of any lingering * unwanted state (e.g. processes) on non-host nodes. */ private boolean rebootOnTransitionTo(Node.State state, Node node) { if (node.type().isDockerHost()) return false; // Reboot of host nodes is handled by NodeRebooter if (zone.environment().isTest()) return false; // We want to reuse nodes quickly in test environments return node.state() != Node.State.dirty && state == Node.State.dirty; }