public HostResource getHost(String hostAlias) { HostSpec hostSpec = provisioner.allocateHost(hostAlias); for (HostResource resource : hostname2host.values()) { if (resource.getHostname().equals(hostSpec.hostname())) { hostSpec.membership().ifPresent(resource::addClusterMembership); return resource; } } return addNewHost(hostSpec); }
private HostResource addNewHost(HostSpec hostSpec) { Host host = Host.createHost(this, hostSpec.hostname()); HostResource hostResource = new HostResource(host, hostSpec.version()); hostResource.setFlavor(hostSpec.flavor()); hostSpec.membership().ifPresent(hostResource::addClusterMembership); hostname2host.put(host.getHostname(), hostResource); log.log(DEBUG, () -> "Added new host resource for " + host.getHostname() + " with flavor " + hostResource.getFlavor()); return hostResource; }
@Override public List<HostSpec> prepare(ClusterSpec cluster, Capacity capacity, int groups, ProvisionLogger logger) { // TODO: This should fail if capacity requested is more than 1 List<HostSpec> hosts = new ArrayList<>(); hosts.add(new HostSpec(host.hostname(), host.aliases(), ClusterMembership.from(cluster, counter++))); return hosts; }
public Map<HostResource, ClusterMembership> allocateHosts(ClusterSpec cluster, Capacity capacity, int groups, DeployLogger logger) { List<HostSpec> allocatedHosts = provisioner.prepare(cluster, capacity, groups, new ProvisionDeployLogger(logger)); // TODO: Even if HostResource owns a set of memberships, we need to return a map because the caller needs the current membership. Map<HostResource, ClusterMembership> retAllocatedHosts = new LinkedHashMap<>(); for (HostSpec spec : allocatedHosts) { // This is needed for single node host provisioner to work in unit tests for hosted vespa applications. HostResource host = getExistingHost(spec).orElseGet(() -> addNewHost(spec)); retAllocatedHosts.put(host, spec.membership().orElse(null)); if (! host.getFlavor().isPresent()) { host.setFlavor(spec.flavor()); log.log(DEBUG, () -> "Host resource " + host.getHostname() + " had no flavor, setting to " + spec.flavor()); } } retAllocatedHosts.keySet().forEach(host -> log.log(DEBUG, () -> "Allocated host " + host.getHostname() + " with flavor " + host.getFlavor())); return retAllocatedHosts; }
private HostSpec getHost(String hostname, Collection<HostSpec> fromHosts) { for (HostSpec host : fromHosts) if (host.hostname().equals(hostname)) return host; return null; }
private void validate(Collection<HostSpec> hosts) { for (HostSpec host : hosts) { if ( ! host.membership().isPresent()) throw new IllegalArgumentException("Hosts must be assigned a cluster when activating, but got " + host); if ( ! host.membership().get().cluster().group().isPresent()) throw new IllegalArgumentException("Hosts must be assigned a group when activating, but got " + host); } }
private void toSlime(HostSpec host, Cursor cursor) { cursor.setString(hostSpecHostName, host.hostname()); host.membership().ifPresent(membership -> { cursor.setString(hostSpecMembership, membership.stringValue()); cursor.setString(hostSpecVespaVersion, membership.cluster().vespaVersion().toFullString()); }); host.flavor().ifPresent(flavor -> cursor.setString(hostSpecFlavor, flavor.name())); host.version().ifPresent(version -> cursor.setString(hostSpecCurrentVespaVersion, version.toFullString())); }
Set<HostSpec> getHostSpecs() { return getHosts().stream() .map(host -> new HostSpec(host.getHostname(), Collections.emptyList(), host.getFlavor(), host.primaryClusterMembership(), host.version())) .collect(Collectors.toCollection(LinkedHashSet::new)); }
/** * Returns the input nodes with the changes resulting from applying the settings in hosts to the given list of nodes. */ private List<Node> updateFrom(Collection<HostSpec> hosts, List<Node> nodes) { List<Node> updated = new ArrayList<>(); for (Node node : nodes) { HostSpec hostSpec = getHost(node.hostname(), hosts); node = hostSpec.membership().get().retired() ? node.retire(nodeRepository.clock().instant()) : node.unretire(); node = node.with(node.allocation().get().with(hostSpec.membership().get())); if (hostSpec.flavor().isPresent()) // Docker nodes may change flavor node = node.with(hostSpec.flavor().get()); updated.add(node); } return updated; }
private Optional<HostResource> getExistingHost(HostSpec key) { List<HostResource> hosts = hostname2host.values().stream() .filter(resource -> resource.getHostname().equals(key.hostname())) .collect(Collectors.toList()); if (hosts.isEmpty()) { return Optional.empty(); } else { log.log(DEBUG, () -> "Found existing host resource for " + key.hostname() + " with flavor " + hosts.get(0).getFlavor()); return Optional.of(hosts.get(0)); } }
@Override public HostSpec allocateHost(String alias) { if (legacyMapping.containsKey(alias)) return legacyMapping.get(alias); List<Host> defaultHosts = freeNodes.get("default"); if (defaultHosts.isEmpty()) throw new IllegalArgumentException("No more hosts of default flavor available"); Host newHost = freeNodes.removeValue("default", 0); HostSpec hostSpec = new HostSpec(newHost.hostname(), newHost.aliases(), newHost.flavor(), Optional.empty(), newHost.version()); legacyMapping.put(alias, hostSpec); return hostSpec; }
if (retiredHostNames.contains(host.hostname())) i.set(retire(host));
private HostSpec host2HostSpec(Host host) { return new HostSpec(host.hostname(), host.aliases()); }
private List<HostSpec> asSortedHosts(List<Node> nodes) { nodes.sort(Comparator.comparingInt(node -> node.allocation().get().membership().index())); List<HostSpec> hosts = new ArrayList<>(nodes.size()); for (Node node : nodes) { log.log(LogLevel.DEBUG, () -> "Prepared node " + node.hostname() + " - " + node.flavor()); hosts.add(new HostSpec(node.hostname(), node.allocation().orElseThrow(IllegalStateException::new).membership(), node.flavor(), node.status().vespaVersion())); } return hosts; }
static HostSpec hostFromSlime(Inspector object, Optional<NodeFlavors> nodeFlavors) { Optional<ClusterMembership> membership = object.field(hostSpecMembership).valid() ? Optional.of(membershipFromSlime(object)) : Optional.empty(); Optional<Flavor> flavor = object.field(hostSpecFlavor).valid() ? flavorFromSlime(object, nodeFlavors) : Optional.empty(); Optional<com.yahoo.component.Version> version = optionalString(object.field(hostSpecCurrentVespaVersion)).map(com.yahoo.component.Version::new); return new HostSpec(object.field(hostSpecHostName).asString(), Collections.emptyList(), flavor, membership, version); }
private List<HostSpec> allocateHostGroup(ClusterSpec clusterGroup, String flavor, int nodesInGroup, int startIndex, boolean canFail) { List<HostSpec> allocation = allocations.getOrDefault(clusterGroup, new ArrayList<>()); allocations.put(clusterGroup, allocation); int nextIndex = nextIndexInCluster.getOrDefault(new Pair<>(clusterGroup.type(), clusterGroup.id()), startIndex); while (allocation.size() < nodesInGroup) { if (freeNodes.get(flavor).isEmpty()) { if (canFail) throw new IllegalArgumentException("Insufficient capacity of flavor '" + flavor + "'"); else break; } Host newHost = freeNodes.removeValue(flavor, 0); ClusterMembership membership = ClusterMembership.from(clusterGroup, nextIndex++); allocation.add(new HostSpec(newHost.hostname(), newHost.aliases(), newHost.flavor(), Optional.of(membership), newHost.version())); } nextIndexInCluster.put(new Pair<>(clusterGroup.type(), clusterGroup.id()), nextIndex); while (allocation.size() > nodesInGroup) allocation.remove(0); return allocation; }
@Override public HostSpec allocateHost(String alias) { // Some special rules to allow no admin elements as well as jdisc element without nodes. if (alias.equals(IMPLICIT_ADMIN_HOSTALIAS)) { if (hosts.asCollection().size() > 1) { throw new IllegalArgumentException("More than 1 host specified (" + hosts.asCollection().size() + ") and <admin> not specified"); } else { return host2HostSpec(getFirstHost()); } } else if (alias.equals(Container.SINGLENODE_CONTAINER_SERVICESPEC)) { return host2HostSpec(getFirstHost()); } for (Host host : hosts.asCollection()) { if (host.aliases().contains(alias)) { return new HostSpec(host.hostname(), host.aliases()); } } throw new IllegalArgumentException("Unable to find host for alias '" + alias + "'"); }
public SingleNodeProvisioner() { host = new Host(HostName.getLocalhost()); this.hostSpec = new HostSpec(host.hostname(), host.aliases()); }