public static Map<String, Set<String>> substituteHostIndexes(Map<String, Set<String>> clusterHostInfo) throws AmbariException {
    Set<String> keysToSkip = new HashSet<>(Arrays.asList(HOSTS_LIST, PORTS, AMBARI_SERVER_HOST, AMBARI_SERVER_PORT, AMBARI_SERVER_USE_SSL, RACKS, IPV4_ADDRESSES));
    String[] allHosts = {};
    if (clusterHostInfo.get(HOSTS_LIST) != null) {
      allHosts = clusterHostInfo.get(HOSTS_LIST).toArray(new String[clusterHostInfo.get(HOSTS_LIST).size()]);
    }
    Set<String> keys = clusterHostInfo.keySet();
    for (String key : keys) {
      if (keysToSkip.contains(key)) {
        continue;
      }
      Set<String> hosts = new HashSet<>();
      Set<String> currentHostsIndexes = clusterHostInfo.get(key);
      if (currentHostsIndexes == null) {
        continue;
      }
      for (String hostIndexRange : currentHostsIndexes) {
        for (Integer hostIndex : rangeToSet(hostIndexRange)) {
          try {
            hosts.add(allHosts[hostIndex]);
          } catch (ArrayIndexOutOfBoundsException ex) {
            throw new AmbariException("Failed to fill cluster host info  ", ex);
          }
        }
      }
      clusterHostInfo.put(key, hosts);
    }
    return clusterHostInfo;
  }
Given a clusterHostInfo map, replaces host indexes with the mapped host names.
<p/>
If all_hosts was <code>["host1", "host2", "host3", "host4", "host5"]</code>, then a value of
<code>["1-3", "5"]</code> for a given component would be converted to
<code>["host1", "host2", "host3", "host5"]</code>.
<p/>
Operations are performed inplace, meaning a new clusterHostInfo map is not created and updated.

@param clusterHostInfo the cluster host info map to perform the substitutions within
@return the updated cluster host info map.
@throws AmbariException if an index fails to map to a host name
ambari-server/src/main/java/org/apache/ambari/server/utils/StageUtils.java