private void updateIdealStateWithNewPartitionsForFullAuto(String dcName,
      Map<String, Set<String>> partitionsToInstancesInDc, Map<String, Integer> instanceNameToOneResource,
      Map<Integer, Set<String>> resourceIdToInstances, Map<Integer, IdealState> resourceIdToIdealState) {
    HelixAdmin dcAdmin = adminForDc.get(dcName);

    // Find the partitions whose instances already exist in resources and assign those partitions to the corresponding resources.
    int round = 1;
    boolean allPartitionsDontHaveResources;
    while (round >= 0) {
      allPartitionsDontHaveResources = true;
      for (Map.Entry<String, Set<String>> ent : partitionsToInstancesInDc.entrySet()) {
        int numReplica = ent.getValue().size();
        Set<String> instanceNames = ent.getValue();
        Set<Integer> resources = instanceNames.stream()
            .map(in -> instanceNameToOneResource.get(in + "_" + numReplica))
            .filter(Objects::nonNull)
            .collect(Collectors.toSet());
        if (resources.isEmpty()) {
          // Partition doesn't belong to any host that are already in the helix
        } else if (resources.size() == 1) {
          info("[{}] Partition {} belongs to resource {} at round {}", dcName, ent.getKey(),
              resources.iterator().next(), round);
          allPartitionsDontHaveResources = false;
          int resourceId = resources.iterator().next();
          // Some instance names might not have a resource name, now assign the resource name to it
          instanceNames.forEach(in -> instanceNameToOneResource.put(in + "_" + numReplica, resourceId));
          resourceIdToInstances.get(resourceId).addAll(instanceNames);
        } else {
          String errorMessage =
              String.format("Partition %s belong to different hosts of different resources, hosts: %s, resources %s",
                  ent.getKey(), instanceNames, resources);
          ensureOrThrow(false, errorMessage);
        }
      }
      // Run this logic for two rounds so that we can use the later partitions to exam prior partitions
      if (allPartitionsDontHaveResources) {
        info("[{}] All new partitions don't have hosts exist in old resources for cluster {}.", dcName.toUpperCase(),
            clusterName);
        break;
      }
      round--;
    }

    Map<Integer, IdealState> resourceToUpdate = new HashMap<>();
    Map<Integer, Integer> resourceToPartitionSize = new HashMap<>();
    Iterator<Map.Entry<String, Set<String>>> partitionIterator = partitionsToInstancesInDc.entrySet().iterator();
    int numPartitions = 0;
    while (partitionIterator.hasNext()) {
      Map.Entry<String, Set<String>> partitionToInstances = partitionIterator.next();
      // If we are here, we know that all partitions' instances would either belong to one resource or no resource at all
      String anyInstance = partitionToInstances.getValue().iterator().next();
      int numReplica = partitionToInstances.getValue().size();
      if (instanceNameToOneResource.containsKey(anyInstance + "_" + numReplica)) {
        Integer resourceId = instanceNameToOneResource.get(anyInstance + "_" + numReplica);
        if (!resourceToUpdate.containsKey(resourceId)) {
          resourceToUpdate.put(resourceId, resourceIdToIdealState.get(resourceId));
          resourceToPartitionSize.put(resourceId, resourceIdToIdealState.get(resourceId).getPartitionSet().size());
        }
        IdealState idealState = resourceToUpdate.get(resourceId);
        ArrayList<String> newInstances = new ArrayList<>(partitionToInstances.getValue());
        Collections.shuffle(newInstances);
        idealState.setPreferenceList(partitionToInstances.getKey(), newInstances);
        partitionIterator.remove();
        numPartitions++;
      }
    }

    if (numPartitions > 0) {
      info(
          "[{}] We have {} partitions to add to existing resources, and we have {} existing resources to update for cluster {}",
          dcName.toUpperCase(), numPartitions, resourceToUpdate.size(), clusterName);
      for (Map.Entry<Integer, IdealState> entry : resourceToUpdate.entrySet()) {
        if (isIdealStateInFullAuto(resourceIdToIdealState.get(entry.getKey()))) {
          info("[{}] resource {} is already in FULL AUTO mode, don't update it", dcName, entry.getKey());
          continue;
        }
        String resourceName = String.valueOf(entry.getKey());
        IdealState idealState = entry.getValue();
        int sizeBefore = resourceToPartitionSize.get(entry.getKey());
        if (!dryRun) {
          dcAdmin.setResourceIdealState(clusterName, resourceName, idealState);
          info("[{}] Update resource {} in datacenter {} from {} partitions to {} partitions", dcName.toUpperCase(),
              resourceName, dcName, sizeBefore, idealState.getPartitionSet().size());
        } else {
          info("[{}] Under DryRun mode, update resource {} in datacenter {} from {} partitions to {} partitions",
              dcName.toUpperCase(), resourceName, dcName, sizeBefore, idealState.getPartitionSet().size());
        }
        resourcesUpdated.incrementAndGet();
      }
      info("[{}] Successfully add partitions to existing resources for cluster {}", dcName.toUpperCase(), clusterName);
    } else {
      info("[{}] We don't have any partition to add to existing resources for cluster {}", dcName.toUpperCase(),
          clusterName);
    }
  }
When resources and static partition layout are both FULL_AUTO compatible, this method would iterate through the new
partitions and find corresponding resources for them if possible.
Before calling this method, we should already verify that each instance has only one assigned resource. So if a
partition's instances are already assigned to the same resource, then this partition would be assigned to this resource
as well. If a partition's instances are assigned to different resources, then this method would fail.

This method would also remove all the new partitions that are assigned to an existing resource from partitionToInstancesInDc.
@param dcName The name of the datacenter
@param partitionsToInstancesInDc The map of partition layout.
@param instanceNameToOneResource The map from instance name to its corresponding assigned resource id
@param resourceIdToInstances The map from resource id to a list of instance names that are assigned to this resource
@param resourceIdToIdealState The map from resource id to IdealState
ambry-clustermap/src/main/java/com/github/ambry/clustermap/HelixBootstrapUpgradeUtil.java