static void rollbackToSemiAuto(String clusterName, String dcs, String zkLayoutPath, String commaSeparatedResources,
      HelixAdminFactory helixAdminFactory) throws Exception {
    Map<String, ClusterMapUtils.DcZkInfo> dataCenterToZkAddress = parseAndUpdateDcInfoFromArg(dcs, zkLayoutPath);
    for (Map.Entry<String, ClusterMapUtils.DcZkInfo> entry : dataCenterToZkAddress.entrySet()) {
      String dcName = entry.getKey();
      List<String> zkConnectStrs = entry.getValue().getZkConnectStrs();
      if (zkConnectStrs.size() != 1) {
        throw new IllegalArgumentException(
            entry.getKey() + " has invalid number of ZK endpoints: " + zkConnectStrs.size());
      }
      HelixAdmin admin = helixAdminFactory.getHelixAdmin(zkConnectStrs.get(0));
      info("Rollback to Semi-Auto. Cluster {}, dc {}, resources {}", clusterName, dcName, commaSeparatedResources);

      // Get resources to migrate from user input.
      Set<String> helixResources =
          admin.getResourcesInCluster(clusterName).stream().filter(s -> s.matches("\\d+")).collect(Collectors.toSet());
      Set<String> resources;
      if (commaSeparatedResources.equalsIgnoreCase(ALL)) {
        resources = helixResources;
      } else {
        resources =
            Arrays.stream(commaSeparatedResources.replaceAll("\\p{Space}", "").split(",")).collect(Collectors.toSet());
        resources.removeIf(resource -> {
          if (!helixResources.contains(resource)) {
            logger.info("Resource {} is not present in data center {}", resource, dcName);
            return true;
          }
          return false;
        });
      }

      // Update ideal state to semi-auto for all the resources
      for (String resourceName : resources) {
        IdealState idealState = admin.getResourceIdealState(clusterName, resourceName);
        idealState.setRebalanceMode(IdealState.RebalanceMode.SEMI_AUTO);
        idealState.setReplicas(ResourceConfig.ResourceConfigConstants.ANY_LIVEINSTANCE.name());
        admin.updateIdealState(clusterName, resourceName, idealState);
      }
    }
  }
Roll back resources in a cluster from Full-Auto to Semi-auto
@param clusterName              Cluster name in Helix.
@param dcs                      The comma-separated list of data centers that needs to be rolled back from Full-Auto
                                to Semi-Auto.
@param zkLayoutPath             The path to the zookeeper layout file.
@param commaSeparatedResources  Comma-separated list of resources that needs to be rolled back.
@param helixAdminFactory        The {@link HelixAdminFactory} to use to instantiate {@link HelixAdmin}
ambry-clustermap/src/main/java/com/github/ambry/clustermap/HelixBootstrapUpgradeUtil.java