'Filter hosts and return only ones passing all filters.'

def get_filtered_hosts(self, hosts, spec_obj, index=0):

    def _strip_ignore_hosts(host_map, hosts_to_ignore):
        ignored_hosts = []
        for host in hosts_to_ignore:
            for (hostname, nodename) in list(host_map.keys()):
                if (host.lower() == hostname.lower()):
                    del host_map[(hostname, nodename)]
                    ignored_hosts.append(host)
        ignored_hosts_str = ',    '.join(ignored_hosts)
        LOG.info(_LI('Host    filter    ignoring    hosts:    %s'), ignored_hosts_str)
    def _match_forced_hosts(host_map, hosts_to_force):
        forced_hosts = []
        lowered_hosts_to_force = [host.lower() for host in hosts_to_force]
        for (hostname, nodename) in list(host_map.keys()):
            if (hostname.lower() not in lowered_hosts_to_force):
                del host_map[(hostname, nodename)]
            else:
                forced_hosts.append(hostname)
        if host_map:
            forced_hosts_str = ',    '.join(forced_hosts)
            msg = _LI('Host    filter    forcing    available    hosts    to    %s')
        else:
            forced_hosts_str = ',    '.join(hosts_to_force)
            msg = _LI("No    hosts    matched    due    to    not    matching    'force_hosts'    value    of    '%s'")
        LOG.info(msg, forced_hosts_str)
    def _match_forced_nodes(host_map, nodes_to_force):
        forced_nodes = []
        for (hostname, nodename) in list(host_map.keys()):
            if (nodename not in nodes_to_force):
                del host_map[(hostname, nodename)]
            else:
                forced_nodes.append(nodename)
        if host_map:
            forced_nodes_str = ',    '.join(forced_nodes)
            msg = _LI('Host    filter    forcing    available    nodes    to    %s')
        else:
            forced_nodes_str = ',    '.join(nodes_to_force)
            msg = _LI("No    nodes    matched    due    to    not    matching    'force_nodes'    value    of    '%s'")
        LOG.info(msg, forced_nodes_str)
    def _get_hosts_matching_request(hosts, requested_destination):
        (host, node) = (requested_destination.host, requested_destination.node)
        requested_nodes = [x for x in hosts if ((x.host == host) and (x.nodename == node))]
        if requested_nodes:
            LOG.info(_LI('Host    filter    only    checking    host    %(host)s    and    node    %(node)s'), {'host': host, 'node': node})
        else:
            LOG.info(_LI('No    hosts    matched    due    to    not    matching    requested    destination    (%(host)s,    %(node)s)'), {'host': host, 'node': node})
        return iter(requested_nodes)
    ignore_hosts = (spec_obj.ignore_hosts or [])
    force_hosts = (spec_obj.force_hosts or [])
    force_nodes = (spec_obj.force_nodes or [])
    requested_node = spec_obj.requested_destination
    if ((requested_node is not None) and ('host' in requested_node)):
        hosts = _get_hosts_matching_request(hosts, requested_node)
    if (ignore_hosts or force_hosts or force_nodes):
        name_to_cls_map = {(x.host, x.nodename): x for x in hosts}
        if ignore_hosts:
            _strip_ignore_hosts(name_to_cls_map, ignore_hosts)
            if (not name_to_cls_map):
                return []
        if force_hosts:
            _match_forced_hosts(name_to_cls_map, force_hosts)
        if force_nodes:
            _match_forced_nodes(name_to_cls_map, force_nodes)
        if (force_hosts or force_nodes):
            if name_to_cls_map:
                return name_to_cls_map.values()
            else:
                return []
        hosts = six.itervalues(name_to_cls_map)
    return self.filter_handler.get_filtered_objects(self.enabled_filters, hosts, spec_obj, index)
