'Given an atomic group host queue entry, locate an appropriate group
of hosts for the associated job to run on.
The caller is responsible for creating new HQEs for the additional
hosts returned in order to run the actual job on them.
:return: A list of Host instances in a ready state to satisfy this
atomic group scheduling.  Hosts will all belong to the same
atomic group label as specified by the queue_entry.
An empty list will be returned if no suitable atomic
group could be found.
TODO(gps): what is responsible for kicking off any attempted repairs on
a group of hosts?  not this function, but something needs to.  We do
not communicate that reason for returning [] outside of here...
For now, we\'ll just be unschedulable if enough hosts within one group
enter Repair Failed state.'

def find_eligible_atomic_group(self, queue_entry):

    assert (queue_entry.atomic_group_id is not None)
    job = queue_entry.job
    assert (job.synch_count and (job.synch_count > 0))
    atomic_group = queue_entry.atomic_group
    if (job.synch_count > atomic_group.max_number_of_machines):
        queue_entry.set_status(models.HostQueueEntry.Status.ABORTED)
        logging.error('Error:    job    %d    synch_count=%d    >    requested    atomic_group    %d    max_number_of_machines=%d.        Aborted    host_queue_entry    %d.', job.id, job.synch_count, atomic_group.id, atomic_group.max_number_of_machines, queue_entry.id)
        return []
    hosts_in_label = self.hosts_in_label(queue_entry.meta_host)
    ineligible_host_ids = self.ineligible_hosts_for_entry(queue_entry)
    for atomic_label_id in self._get_atomic_group_labels(atomic_group.id):
        group_hosts = set(self.hosts_in_label(atomic_label_id))
        if (queue_entry.meta_host is not None):
            group_hosts.intersection_update(hosts_in_label)
        group_hosts -= ineligible_host_ids
        eligible_host_ids_in_group = self._get_eligible_host_ids_in_group(group_hosts, queue_entry)
        min_hosts = job.synch_count
        max_hosts = atomic_group.max_number_of_machines
        if (len(eligible_host_ids_in_group) < min_hosts):
            continue
        eligible_hosts_in_group = [self._hosts_available[id] for id in eligible_host_ids_in_group]
        eligible_hosts_in_group.sort(cmp=scheduler_models.Host.cmp_for_sort)
        if (len(eligible_hosts_in_group) > max_hosts):
            eligible_hosts_in_group = eligible_hosts_in_group[:max_hosts]
        host_list = []
        for host in eligible_hosts_in_group:
            hosts_in_label.discard(host.id)
            self._hosts_available.pop(host.id)
            host_list.append(host)
        return host_list
    return []
