private List<Grouping> getDowngradeGroupsForRolling() {
    List<Grouping> reverse = new ArrayList<>();

    // !!! Testing exposed groups.size() == 1 issue.  Normally there's no precedent for
    // a one-group upgrade pack, so take it into account anyway.
    if (groups.size() == 1) {
      return groups;
    }

    int idx = 0;
    int iter = 0;
    Iterator<Grouping> it = groups.iterator();

    while (it.hasNext()) {
      Grouping g = it.next();
      if (ClusterGrouping.class.isInstance(g)) {
        reverse.add(g);
        idx++;
      } else {
        if (iter+1 < groups.size()) {
          Grouping peek = groups.get(iter+1);
          if (ServiceCheckGrouping.class.isInstance(peek)) {
            reverse.add(idx, it.next());
            reverse.add(idx, g);
            iter++;
          } else {
            reverse.add(idx, g);
          }
        }
      }
      iter++;
    }

    return reverse;
  }
Calculates the group orders when performing a rolling downgrade
<ul>
  <li>ClusterGroupings must remain at the same positions (first/last).</li>
  <li>When there is a ServiceCheck group, it must ALWAYS follow the same</li>
      preceding group, whether for an upgrade or a downgrade.</li>
  <li>All other groups must follow the reverse order.</li>
</ul>
For example, give the following order of groups:
<ol>
  <li>PRE_CLUSTER</li>
  <li>ZK</li>
  <li>CORE_MASTER</li>
  <li>SERVICE_CHECK_1</li>
  <li>CLIENTS</li>
  <li>FLUME</li>
  <li>SERVICE_CHECK_2</li>
  <li>POST_CLUSTER</li>
</ol>
The reverse would be:
<ol>
  <li>PRE_CLUSTER</li>
  <li>FLUME</li>
  <li>SERVICE_CHECK_2</li>
  <li>CLIENTS</li>
  <li>CORE_MASTER</li>
  <li>SERVICE_CHECK_1</li>
  <li>ZK</li>
  <li>POST_CLUSTER</li>
</ol>
@return the list of groups, reversed appropriately for a downgrade.
ambari-server/src/main/java/org/apache/ambari/server/stack/upgrade/UpgradePack.java