private List<Node> provisionHosts(int count, NodeResources nodeResources, Optional<String> clusterType, NodeList allNodes) {
        try {
            if (throttler.throttle(allNodes, Agent.HostCapacityMaintainer)) {
                throw new NodeAllocationException("Host provisioning is being throttled", true);
            }
            Version osVersion = nodeRepository().osVersions().targetFor(NodeType.host).orElse(Version.emptyVersion);
            List<Integer> provisionIndices = nodeRepository().database().readProvisionIndices(count);
            HostSharing sharingMode = nodeRepository().exclusivity().allocation(asSpec(clusterType, 0)) ? HostSharing.exclusive : HostSharing.shared;
            HostProvisionRequest request = new HostProvisionRequest(provisionIndices, NodeType.host, nodeResources,
                                                                    ApplicationId.defaultId(), osVersion, Vtag.currentVersion,
                                                                    sharingMode, clusterType.map(ClusterSpec.Type::valueOf), Optional.empty(),
                                                                    nodeRepository().zone().cloud().account(), false, false);
            List<Node> hosts = new ArrayList<>();
            Runnable waiter;
            try (var lock = nodeRepository().nodes().lockUnallocated()) {
                waiter = hostProvisioner.provisionHosts(request,
                        resources -> true,
                        provisionedHosts -> {
                            hosts.addAll(provisionedHosts.stream()
                                    .map(host -> host.generateHost(Duration.ZERO))
                                    .map(host -> host.withExclusiveToApplicationId(null))
                                    .toList());
                            nodeRepository().nodes().addNodes(hosts, Agent.HostCapacityMaintainer);
                        });
            }
            waiter.run();
            return hosts;
        } catch (NodeAllocationException | IllegalArgumentException | IllegalStateException e) {
            throw new NodeAllocationException("Failed to provision " + count + " " + nodeResources + ": " + e.getMessage(),
                                              ! (e instanceof NodeAllocationException nae) || nae.retryable());
        } catch (RuntimeException e) {
            throw new RuntimeException("Failed to provision " + count + " " + nodeResources + ", will retry in " + interval(), e);
        }
    }
@return the nodes in {@code nodeList} plus all hosts provisioned, plus all preprovision capacity
        nodes that were allocated.
@throws NodeAllocationException if there were problems provisioning hosts, and in case message
        should be sufficient (avoid no stack trace)
@throws IllegalStateException if there was an algorithmic problem, and in case message
        should be sufficient (avoid no stack trace).
node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainer.java