private List<Node> deprovisionable(Instant instant, OsVersionTarget target, NodeList allNodes) {
        NodeList nodes = allNodes.state(Node.State.active, Node.State.provisioned).nodeType(target.nodeType());
        if (localStorageOnly) {
            // Consider only hosts with local storage
            nodes = nodes.not().remoteStorage();
        }
        // Retire hosts up to slot limit while ensuring that only one group is retired at a time
        NodeList activeNodes = allNodes.state(Node.State.active);
        Map<ClusterId, Set<ClusterSpec.Group>> retiringGroupsByCluster = groupsOf(activeNodes.retiring());
        int limit = upgradeSlots(target, nodes.deprovisioning());
        List<Node> result = new ArrayList<>();
        NodeList candidates = nodes.not().deprovisioning()
                                   .not().onOsVersion(target.version())
                                   .matching(node -> canUpgradeTo(target.version(), instant, node))
                                   .byIncreasingOsVersion();
        for (Node host : candidates) {
            if (result.size() == limit) break;
            // For all clusters residing on this host: Determine if deprovisioning the host would imply retiring nodes
            // in additional groups beyond those already having retired nodes. If true, defer deprovisioning the host
            boolean canDeprovision = true;
            Map<ClusterId, Set<ClusterSpec.Group>> groupsOnHost = groupsOf(activeNodes.childrenOf(host));
            for (var clusterAndGroups : groupsOnHost.entrySet()) {
                Set<ClusterSpec.Group> groups = clusterAndGroups.getValue();
                Set<ClusterSpec.Group> retiringGroups = retiringGroupsByCluster.get(clusterAndGroups.getKey());
                if (retiringGroups != null && !groups.equals(retiringGroups)) {
                    canDeprovision = false;
                    break;
                }
            }
            // Deprovision host and count all cluster groups on the host as being retired
            if (canDeprovision) {
                result.add(host);
                groupsOnHost.forEach((cluster, groups) -> retiringGroupsByCluster.merge(cluster, groups, (oldVal, newVal) -> {
                    oldVal.addAll(newVal);
                    return oldVal;
                }));
            }
        }
        return Collections.unmodifiableList(result);
    }
Returns nodes that can be deprovisioned at given instant
node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/RetiringOsUpgrader.java