Forráskód Böngészése

AMBARI-10636. Merge Configs on Upgrade Across Stack Version (ncole)

Nate Cole 10 éve
szülő
commit
f23f126182

+ 2 - 31
ambari-server/src/main/java/org/apache/ambari/server/checks/ConfigurationMergeCheck.java

@@ -17,10 +17,7 @@
  */
  */
 package org.apache.ambari.server.checks;
 package org.apache.ambari.server.checks;
 
 
-import java.util.Collections;
-import java.util.Comparator;
 import java.util.HashSet;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Map;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.Set;
@@ -33,7 +30,6 @@ import org.apache.ambari.server.state.ConfigMergeHelper;
 import org.apache.ambari.server.state.ConfigMergeHelper.ThreeWayValue;
 import org.apache.ambari.server.state.ConfigMergeHelper.ThreeWayValue;
 import org.apache.ambari.server.state.stack.PrereqCheckStatus;
 import org.apache.ambari.server.state.stack.PrereqCheckStatus;
 import org.apache.ambari.server.state.stack.PrerequisiteCheck;
 import org.apache.ambari.server.state.stack.PrerequisiteCheck;
-import org.apache.ambari.server.utils.VersionUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.StringUtils;
 
 
 import com.google.inject.Inject;
 import com.google.inject.Inject;
@@ -57,7 +53,7 @@ public class ConfigurationMergeCheck extends AbstractCheckDescriptor {
       return false;
       return false;
     }
     }
 
 
-    RepositoryVersionEntity rve = findByVersion(repoVersion);
+    RepositoryVersionEntity rve = repositoryVersionDaoProvider.get().findMaxByVersion(repoVersion);
     if (null == rve) {
     if (null == rve) {
       return false;
       return false;
     }
     }
@@ -84,7 +80,7 @@ public class ConfigurationMergeCheck extends AbstractCheckDescriptor {
   public void perform(PrerequisiteCheck prerequisiteCheck, PrereqCheckRequest request)
   public void perform(PrerequisiteCheck prerequisiteCheck, PrereqCheckRequest request)
       throws AmbariException {
       throws AmbariException {
 
 
-    RepositoryVersionEntity rve = findByVersion(request.getRepositoryVersion());
+    RepositoryVersionEntity rve = repositoryVersionDaoProvider.get().findMaxByVersion(request.getRepositoryVersion());
 
 
     Map<String, Map<String, ThreeWayValue>> changes =
     Map<String, Map<String, ThreeWayValue>> changes =
         m_mergeHelper.getConflicts(request.getClusterName(), rve.getStackId());
         m_mergeHelper.getConflicts(request.getClusterName(), rve.getStackId());
@@ -120,31 +116,6 @@ public class ConfigurationMergeCheck extends AbstractCheckDescriptor {
     }
     }
   }
   }
 
 
-  /**
-   * Finds the repository version, making sure if there is more than one match
-   * (unlikely) that the latest stack is chosen.
-   * @param version the version to find
-   * @return the matching repo version entity
-   */
-  private RepositoryVersionEntity findByVersion(String version) {
-    List<RepositoryVersionEntity> list = repositoryVersionDaoProvider.get().findByVersion(version);
-    if (null == list || 0 == list.size()) {
-      return null;
-    } else if (1 == list.size()) {
-      return list.get(0);
-    } else {
-      Collections.sort(list, new Comparator<RepositoryVersionEntity>() {
-        @Override
-        public int compare(RepositoryVersionEntity o1, RepositoryVersionEntity o2) {
-          return VersionUtils.compareVersions(o1.getVersion(), o2.getVersion());
-        }
-      });
 
 
-      Collections.reverse(list);
-
-      return list.get(0);
-    }
-
-  }
 
 
 }
 }

+ 85 - 6
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java

@@ -67,12 +67,15 @@ import org.apache.ambari.server.orm.dao.RequestDAO;
 import org.apache.ambari.server.orm.dao.UpgradeDAO;
 import org.apache.ambari.server.orm.dao.UpgradeDAO;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.RequestEntity;
 import org.apache.ambari.server.orm.entities.RequestEntity;
+import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.orm.entities.UpgradeEntity;
 import org.apache.ambari.server.orm.entities.UpgradeEntity;
 import org.apache.ambari.server.orm.entities.UpgradeGroupEntity;
 import org.apache.ambari.server.orm.entities.UpgradeGroupEntity;
 import org.apache.ambari.server.orm.entities.UpgradeItemEntity;
 import org.apache.ambari.server.orm.entities.UpgradeItemEntity;
 import org.apache.ambari.server.stack.MasterHostResolver;
 import org.apache.ambari.server.stack.MasterHostResolver;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Config;
 import org.apache.ambari.server.state.ConfigHelper;
 import org.apache.ambari.server.state.ConfigHelper;
+import org.apache.ambari.server.state.PropertyInfo;
 import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.StackInfo;
 import org.apache.ambari.server.state.StackInfo;
@@ -405,7 +408,6 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     String version = (String) requestMap.get(UPGRADE_VERSION);
     String version = (String) requestMap.get(UPGRADE_VERSION);
     String versionForUpgradePack = (String) requestMap.get(UPGRADE_FROM_VERSION);
     String versionForUpgradePack = (String) requestMap.get(UPGRADE_FROM_VERSION);
 
 
-
     if (null == clusterName) {
     if (null == clusterName) {
       throw new AmbariException(String.format("%s is required", UPGRADE_CLUSTER_NAME));
       throw new AmbariException(String.format("%s is required", UPGRADE_CLUSTER_NAME));
     }
     }
@@ -423,8 +425,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
       repoVersion = versionForUpgradePack;
       repoVersion = versionForUpgradePack;
     }
     }
 
 
-    RepositoryVersionEntity versionEntity = s_repoVersionDAO.findByStackAndVersion(
-        stack, repoVersion);
+    RepositoryVersionEntity versionEntity = s_repoVersionDAO.findMaxByVersion(repoVersion);
 
 
     if (null == versionEntity) {
     if (null == versionEntity) {
       throw new AmbariException(String.format("Version %s for stack %s was not found",
       throw new AmbariException(String.format("Version %s for stack %s was not found",
@@ -432,7 +433,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     }
     }
 
 
     Map<String, UpgradePack> packs = s_metaProvider.get().getUpgradePacks(
     Map<String, UpgradePack> packs = s_metaProvider.get().getUpgradePacks(
-        stack.getStackName(), stack.getStackVersion());
+        versionEntity.getStackName(), versionEntity.getStackVersion());
 
 
     UpgradePack up = packs.get(versionEntity.getUpgradePackage());
     UpgradePack up = packs.get(versionEntity.getUpgradePackage());
 
 
@@ -444,8 +445,6 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
           repoVersion));
           repoVersion));
     }
     }
 
 
-    // !!! validate all hosts have the version installed
-
     return up;
     return up;
   }
   }
 
 
@@ -567,6 +566,9 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
 
 
     entity.setRequestId(req.getId());
     entity.setRequestId(req.getId());
 
 
+    // !!! in case persist() starts creating tasks right away, square away the configs
+    createConfigs(cluster, version);
+
     req.persist();
     req.persist();
 
 
     s_upgradeDAO.create(entity);
     s_upgradeDAO.create(entity);
@@ -574,6 +576,83 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
     return entity;
     return entity;
   }
   }
 
 
+  /**
+   * Merges and creates configs for the new stack.  No-op when the target stack version
+   * is the same as the cluster's current stack version.
+   * @param cluster the cluster
+   * @param version the version
+   * @throws AmbariException
+   */
+  private void createConfigs(Cluster cluster, String version) throws AmbariException {
+    RepositoryVersionEntity targetRve = s_repoVersionDAO.findMaxByVersion(version);
+    if (null == targetRve) {
+      LOG.info("Could not find version entity for {}; not setting new configs",
+          version);
+      return;
+    }
+
+    StackEntity oldStack = cluster.getCurrentClusterVersion().getRepositoryVersion().getStack();
+    StackEntity newStack = targetRve.getStack();
+
+    if (oldStack.equals(newStack)) {
+      return;
+    }
+
+    ConfigHelper configHelper = getManagementController().getConfigHelper();
+
+    Map<String, Map<String, String>> clusterConfigs = new HashMap<String, Map<String, String>>();
+
+    // !!! stack
+    Set<org.apache.ambari.server.state.PropertyInfo> pi = s_metaProvider.get().getStackProperties(newStack.getStackName(),
+        newStack.getStackVersion());
+
+    for (PropertyInfo stackProperty : pi) {
+      String type = ConfigHelper.fileNameToConfigType(stackProperty.getFilename());
+
+      if (!clusterConfigs.containsKey(type)) {
+        clusterConfigs.put(type, new HashMap<String, String>());
+      }
+
+      clusterConfigs.get(type).put(stackProperty.getName(),
+          stackProperty.getValue());
+    }
+
+    // !!! by service
+    for (String serviceName : cluster.getServices().keySet()) {
+      pi = s_metaProvider.get().getServiceProperties(newStack.getStackName(),
+          newStack.getStackVersion(), serviceName);
+
+      // !!! use new stack as the basis
+      for (PropertyInfo stackProperty : pi) {
+        String type = ConfigHelper.fileNameToConfigType(stackProperty.getFilename());
+
+        if (!clusterConfigs.containsKey(type)) {
+          clusterConfigs.put(type, new HashMap<String, String>());
+        }
+
+        clusterConfigs.get(type).put(stackProperty.getName(),
+            stackProperty.getValue());
+      }
+    }
+
+    // !!! upgrading the stack
+    cluster.setDesiredStackVersion(
+        new StackId(newStack.getStackName(), newStack.getStackVersion()));
+
+    // !!! overlay the currently defined values per type
+    for (Map.Entry<String, Map<String, String>> entry : clusterConfigs.entrySet()) {
+      Config config = cluster.getDesiredConfigByType(entry.getKey());
+      if (null != config) {
+        entry.getValue().putAll(config.getProperties());
+      }
+    }
+
+    configHelper.createConfigTypes(cluster, getManagementController(),
+        clusterConfigs, getManagementController().getAuthName(),
+        "Configuration created for Upgrade");
+
+  }
+
 
 
   private RequestStageContainer createRequest(Direction direction, String version) {
   private RequestStageContainer createRequest(Direction direction, String version) {
     ActionManager actionManager = getManagementController().getActionManager();
     ActionManager actionManager = getManagementController().getActionManager();

+ 31 - 0
ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RepositoryVersionDAO.java

@@ -17,6 +17,8 @@
  */
  */
 package org.apache.ambari.server.orm.dao;
 package org.apache.ambari.server.orm.dao;
 
 
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 import java.util.List;
 
 
 import javax.persistence.TypedQuery;
 import javax.persistence.TypedQuery;
@@ -26,6 +28,7 @@ import org.apache.ambari.server.orm.RequiresSession;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.utils.VersionUtils;
 
 
 import com.google.inject.Singleton;
 import com.google.inject.Singleton;
 
 
@@ -172,4 +175,32 @@ public class RepositoryVersionDAO extends CrudDAO<RepositoryVersionEntity, Long>
     return newEntity;
     return newEntity;
   }
   }
 
 
+  /**
+   * Finds the repository version, making sure if there is more than one match
+   * (unlikely) that the latest stack is chosen.
+   * @param version the version to find
+   * @return the matching repo version entity
+   */
+  public RepositoryVersionEntity findMaxByVersion(String version) {
+    List<RepositoryVersionEntity> list = findByVersion(version);
+    if (null == list || 0 == list.size()) {
+      return null;
+    } else if (1 == list.size()) {
+      return list.get(0);
+    } else {
+      Collections.sort(list, new Comparator<RepositoryVersionEntity>() {
+        @Override
+        public int compare(RepositoryVersionEntity o1, RepositoryVersionEntity o2) {
+          return VersionUtils.compareVersions(o1.getVersion(), o2.getVersion());
+        }
+      });
+
+      Collections.reverse(list);
+
+      return list.get(0);
+    }
+
+  }
+
+
 }
 }

+ 61 - 1
ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java

@@ -31,7 +31,6 @@ import java.util.Set;
 import java.util.TreeMap;
 import java.util.TreeMap;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeUnit;
 
 
-import com.google.common.collect.Maps;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.configuration.Configuration;
@@ -47,6 +46,7 @@ import org.slf4j.LoggerFactory;
 
 
 import com.google.common.cache.Cache;
 import com.google.common.cache.Cache;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheBuilder;
+import com.google.common.collect.Maps;
 import com.google.inject.Inject;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import com.google.inject.Singleton;
 import com.google.inject.persist.Transactional;
 import com.google.inject.persist.Transactional;
@@ -742,6 +742,66 @@ public class ConfigHelper {
     }
     }
   }
   }
 
 
+  /**
+   * Create configurations and assign them for services.
+   * @param cluster               the cluster
+   * @param controller            the controller
+   * @param batchProperties       the type->config map batch of properties
+   * @param authenticatedUserName the user that initiated the change
+   * @param serviceVersionNote    the service version note
+   * @throws AmbariException
+   */
+  public void createConfigTypes(Cluster cluster,
+      AmbariManagementController controller,
+      Map<String, Map<String, String>> batchProperties, String authenticatedUserName,
+      String serviceVersionNote) throws AmbariException {
+
+    Map<String, Set<Config>> serviceMapped = new HashMap<String, Set<Config>>();
+
+    for (Map.Entry<String, Map<String, String>> entry : batchProperties.entrySet()) {
+      String type = entry.getKey();
+      String tag = "version1";
+
+      if (cluster.getConfigsByType(type) != null) {
+        tag = "version" + System.currentTimeMillis();
+      }
+
+      // create the configuration
+      ConfigurationRequest configurationRequest = new ConfigurationRequest();
+      configurationRequest.setClusterName(cluster.getClusterName());
+      configurationRequest.setVersionTag(tag);
+      configurationRequest.setType(type);
+      configurationRequest.setProperties(entry.getValue());
+      configurationRequest.setServiceConfigVersionNote(serviceVersionNote);
+      controller.createConfiguration(configurationRequest);
+
+      Config baseConfig = cluster.getConfig(configurationRequest.getType(),
+          configurationRequest.getVersionTag());
+
+      if (null != baseConfig) {
+        try {
+          String service = cluster.getServiceForConfigTypes(Collections.singleton(type));
+          if (!serviceMapped.containsKey(service)) {
+            serviceMapped.put(service, new HashSet<Config>());
+          }
+          serviceMapped.get(service).add(baseConfig);
+
+        } catch (Exception e) {
+          // !!! ignore
+        }
+      }
+    }
+
+    // create the configuration history entries
+    for (Set<Config> configs : serviceMapped.values()) {
+      if (!configs.isEmpty()) {
+        cluster.addDesiredConfig(authenticatedUserName, configs, serviceVersionNote);
+      }
+    }
+
+  }
+
+
   /**
   /**
    * Since global configs are deprecated since 1.7.0, but still supported.
    * Since global configs are deprecated since 1.7.0, but still supported.
    * We should automatically map any globals used, to *-env dictionaries.
    * We should automatically map any globals used, to *-env dictionaries.

+ 4 - 0
ambari-server/src/main/java/org/apache/ambari/server/state/ConfigMergeHelper.java

@@ -27,6 +27,7 @@ import java.util.regex.Pattern;
 
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.collections.CollectionUtils;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
@@ -50,6 +51,9 @@ public class ConfigMergeHelper {
   @Inject
   @Inject
   private Provider<AmbariMetaInfo> m_ambariMetaInfo;
   private Provider<AmbariMetaInfo> m_ambariMetaInfo;
 
 
+  @Inject
+  private Provider<RepositoryVersionDAO> repositoryVersionDaoProvider;
+
   @SuppressWarnings("unchecked")
   @SuppressWarnings("unchecked")
   public Map<String, Map<String, ThreeWayValue>> getConflicts(String clusterName, StackId targetStack) throws AmbariException {
   public Map<String, Map<String, ThreeWayValue>> getConflicts(String clusterName, StackId targetStack) throws AmbariException {
     Cluster cluster = m_clusters.get().getCluster(clusterName);
     Cluster cluster = m_clusters.get().getCluster(clusterName);

+ 5 - 11
ambari-server/src/test/java/org/apache/ambari/server/checks/ConfigurationMergeCheckTest.java

@@ -89,13 +89,9 @@ public class ConfigurationMergeCheckTest {
     Assert.assertFalse(cmc.isApplicable(request));
     Assert.assertFalse(cmc.isApplicable(request));
 
 
     final RepositoryVersionDAO repositoryVersionDAO = EasyMock.createMock(RepositoryVersionDAO.class);
     final RepositoryVersionDAO repositoryVersionDAO = EasyMock.createMock(RepositoryVersionDAO.class);
-    expect(repositoryVersionDAO.findByVersion("1.0")).andReturn(
-        Collections.singletonList(createFor("1.0"))).anyTimes();
-    expect(repositoryVersionDAO.findByVersion("1.1")).andReturn(
-        Collections.singletonList(createFor("1.1"))).anyTimes();
-    expect(repositoryVersionDAO.findByVersion("1.2")).andReturn(
-        Collections.<RepositoryVersionEntity>emptyList()).anyTimes();
-
+    expect(repositoryVersionDAO.findMaxByVersion("1.0")).andReturn(createFor("1.0")).anyTimes();
+    expect(repositoryVersionDAO.findMaxByVersion("1.1")).andReturn(createFor("1.1")).anyTimes();
+    expect(repositoryVersionDAO.findMaxByVersion("1.2")).andReturn(null).anyTimes();
 
 
     replay(repositoryVersionDAO);
     replay(repositoryVersionDAO);
 
 
@@ -129,10 +125,8 @@ public class ConfigurationMergeCheckTest {
     ConfigurationMergeCheck cmc = new ConfigurationMergeCheck();
     ConfigurationMergeCheck cmc = new ConfigurationMergeCheck();
 
 
     final RepositoryVersionDAO repositoryVersionDAO = EasyMock.createMock(RepositoryVersionDAO.class);
     final RepositoryVersionDAO repositoryVersionDAO = EasyMock.createMock(RepositoryVersionDAO.class);
-    expect(repositoryVersionDAO.findByVersion("1.0")).andReturn(
-        Collections.singletonList(createFor("1.0"))).anyTimes();
-    expect(repositoryVersionDAO.findByVersion("1.1")).andReturn(
-        Collections.singletonList(createFor("1.1"))).anyTimes();
+    expect(repositoryVersionDAO.findMaxByVersion("1.0")).andReturn(createFor("1.0")).anyTimes();
+    expect(repositoryVersionDAO.findMaxByVersion("1.1")).andReturn(createFor("1.1")).anyTimes();
 
 
     replay(repositoryVersionDAO);
     replay(repositoryVersionDAO);
 
 

+ 59 - 0
ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java

@@ -64,7 +64,9 @@ import org.apache.ambari.server.orm.entities.UpgradeGroupEntity;
 import org.apache.ambari.server.orm.entities.UpgradeItemEntity;
 import org.apache.ambari.server.orm.entities.UpgradeItemEntity;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.Config;
 import org.apache.ambari.server.state.ConfigHelper;
 import org.apache.ambari.server.state.ConfigHelper;
+import org.apache.ambari.server.state.ConfigImpl;
 import org.apache.ambari.server.state.Host;
 import org.apache.ambari.server.state.Host;
 import org.apache.ambari.server.state.HostState;
 import org.apache.ambari.server.state.HostState;
 import org.apache.ambari.server.state.RepositoryVersionState;
 import org.apache.ambari.server.state.RepositoryVersionState;
@@ -154,6 +156,13 @@ public class UpgradeResourceProviderTest {
     repoVersionEntity.setVersion("2.2.2.2");
     repoVersionEntity.setVersion("2.2.2.2");
     repoVersionDao.create(repoVersionEntity);
     repoVersionDao.create(repoVersionEntity);
 
 
+    repoVersionEntity = new RepositoryVersionEntity();
+    repoVersionEntity.setDisplayName("For Stack Version 2.2.0");
+    repoVersionEntity.setOperatingSystems("");
+    repoVersionEntity.setStack(stackDAO.find("HDP", "2.2.0"));
+    repoVersionEntity.setUpgradePackage("upgrade_test");
+    repoVersionEntity.setVersion("2.2.0.0");
+    repoVersionDao.create(repoVersionEntity);
 
 
     clusters = injector.getInstance(Clusters.class);
     clusters = injector.getInstance(Clusters.class);
 
 
@@ -607,6 +616,53 @@ public class UpgradeResourceProviderTest {
     assertEquals(100d, calc.getPercent(), 0.01d);
     assertEquals(100d, calc.getPercent(), 0.01d);
   }
   }
 
 
+  @Test
+  public void testCreateCrossStackUpgrade() throws Exception {
+    Cluster cluster = clusters.getCluster("c1");
+
+    // add a single ZK server
+//    Service service = cluster.addService("HDFS");
+//    service.setDesiredStackVersion(cluster.getDesiredStackVersion());
+//    service.persist();
+//
+//    ServiceComponent component = service.addServiceComponent("NAMENODE");
+//    ServiceComponentHost sch = component.addServiceComponentHost("h1");
+//    sch.setVersion("2.2.2.1");
+//
+//    component = service.addServiceComponent("HDFS_CLIENT");
+//    sch = component.addServiceComponentHost("h1");
+//    sch.setVersion("2.2.2.1");
+
+    Config config = new ConfigImpl("zoo.cfg");
+    config.setProperties(new HashMap<String, String>() {{
+      put("a", "b");
+    }});
+    config.setTag("abcdefg");
+
+    cluster.addConfig(config);
+    cluster.addDesiredConfig("admin", Collections.singleton(config));
+
+
+    Map<String, Object> requestProps = new HashMap<String, Object>();
+    requestProps.put(UpgradeResourceProvider.UPGRADE_CLUSTER_NAME, "c1");
+    requestProps.put(UpgradeResourceProvider.UPGRADE_VERSION, "2.2.0.0");
+
+    ResourceProvider upgradeResourceProvider = createProvider(amc);
+
+    Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProps), null);
+    upgradeResourceProvider.createResources(request);
+
+    List<UpgradeEntity> upgrades = upgradeDao.findUpgrades(cluster.getClusterId());
+    assertEquals(1, upgrades.size());
+
+    UpgradeEntity upgrade = upgrades.get(0);
+    assertEquals(3, upgrade.getUpgradeGroups().size());
+    UpgradeGroupEntity group = upgrade.getUpgradeGroups().get(2);
+    assertEquals(2, group.getItems().size());
+
+    assertTrue(cluster.getDesiredConfigs().containsKey("zoo.cfg"));
+  }
+
   /**
   /**
    * @param amc
    * @param amc
    * @return the provider
    * @return the provider
@@ -627,4 +683,7 @@ public class UpgradeResourceProviderTest {
       binder.bind(ConfigHelper.class).toInstance(configHelper);
       binder.bind(ConfigHelper.class).toInstance(configHelper);
     }
     }
   }
   }
+
+
+
 }
 }

+ 214 - 0
ambari-server/src/test/resources/stacks/HDP/2.2.0/upgrades/upgrade_test.xml

@@ -0,0 +1,214 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<upgrade xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <target>2.2.*</target>
+  
+  <order>
+    <group xsi:type="cluster" name="PRE_CLUSTER" title="Pre {{direction.text.proper}}">
+      <execute-stage title="Confirm 1">
+        <task xsi:type="manual">
+          <message>Foo</message>
+        </task>
+      </execute-stage>
+      <execute-stage service="HDFS" component="NAMENODE" title="Pre Upgrade HIVE">
+        <task xsi:type="manual">
+          <message>Back stuff up.</message>
+        </task>
+      </execute-stage>
+      <execute-stage service="HDFS" component="NAMENODE" title="Finalize HDFS">
+        <task xsi:type="execute">
+          <command>ls</command>
+        </task>
+      </execute-stage>
+      <execute-stage title="Confirm 2">
+        <task xsi:type="manual">
+          <message>Foo</message>
+        </task>
+      </execute-stage>
+    </group>
+  
+    <group name="ZOOKEEPER" title="Zookeeper">
+      <skippable>true</skippable>
+      <allow-retry>false</allow-retry>
+      <service name="ZOOKEEPER">
+        <component>ZOOKEEPER_SERVER</component>
+        <component>ZOOKEEPER_CLIENT</component>
+      </service>
+    </group>
+    
+    <group name="CORE_MASTER" title="Core Masters">
+      <service name="HDFS">
+        <component>JOURNALNODE</component>
+        <component>NAMENODE</component>
+      </service>
+      <service name="YARN">
+        <component>RESOURCEMANAGER</component>
+      </service>
+    </group>
+    
+    <group name="CORE_SLAVES" title="Core Slaves" xsi:type="colocated">
+      <skippable>true</skippable>      <!-- set skippable for test -->
+      <allow-retry>false</allow-retry> <!-- set no retry for test -->
+      <service name="HDFS">
+        <component>DATANODE</component>
+      </service>
+      <service name="HBASE">
+        <component>REGIONSERVER</component>
+      </service>
+      <service name="YARN">
+        <component>NODEMANAGER</component>
+      </service>
+      
+      <batch>
+        <percent>20</percent>
+        <message>Please run additional tests on {{components}}</message>
+      </batch>
+    </group>
+    
+    <group name="HIVE" title="Hive">
+      <skippable>true</skippable>
+      <service name="HIVE">
+        <component>HIVE_METASTORE</component>
+        <component>HIVE_SERVER</component>
+        <component>WEBHCAT_SERVER</component>
+      </service>
+    </group>    
+    
+    <group xsi:type="cluster" name="POST_CLUSTER" title="Finalize {{direction.text.proper}}">
+      <execute-stage title="Check Unhealthy Hosts" id="unhealthy-hosts">
+        <task xsi:type="manual">
+          <message>The following hosts were unhealthy and should be resolved before finalizing can be completed:
+              {{host-detail-list}}</message>
+        </task>
+      </execute-stage>
+      <execute-stage title="Confirm Finalize">
+        <task xsi:type="manual">
+          <message>Please confirm you are ready to finalize</message>
+        </task>
+      </execute-stage>
+      <execute-stage service="HDFS" component="NAMENODE" title="Execute HDFS Finalize">
+        <task xsi:type="execute">
+          <command>ls</command>
+        </task>
+      </execute-stage>
+      <execute-stage title="Save Cluster State" service="" component="">
+        <task xsi:type="server_action" class="org.apache.ambari.server.serveraction.upgrades.FinalizeUpgradeAction">
+        </task>
+      </execute-stage>
+    </group>
+        
+  </order>
+  
+
+  <processing>
+    <service name="ZOOKEEPER">
+      <component name="ZOOKEEPER_SERVER">
+        <pre-upgrade>
+          <task xsi:type="manual">
+            <summary>SUMMARY OF PREPARE</summary>
+            <message>This is a manual task with a placeholder of {{foo/bar}}</message>
+          </task>
+        </pre-upgrade>
+        <upgrade>
+          <task xsi:type="restart" />
+        </upgrade>
+        <post-upgrade>
+          <task xsi:type="configure" />
+        </post-upgrade>
+      </component>
+    </service>
+    
+    <service name="HDFS">
+      <component name="NAMENODE">
+        <pre-upgrade>
+          <task xsi:type="execute" hosts="master">
+            <command>su - {hdfs-user} -c 'dosomething'</command>
+          </task>
+          <task xsi:type="configure">
+            <type>hdfs-site</type>
+            <key>myproperty</key>
+            <value>mynewvalue</value>
+          </task>
+          <task xsi:type="manual">
+            <message>{{direction.verb.proper}} your database</message>
+          </task>
+        </pre-upgrade>
+        <upgrade>
+          <task xsi:type="restart" />
+        </upgrade>
+        <post-upgrade>
+          <task xsi:type="execute">
+            <command>ls</command>
+          </task>
+        </post-upgrade>
+      </component>
+      <component name="DATANODE">
+        <pre-downgrade />
+        <upgrade>
+          <task xsi:type="restart" />
+        </upgrade>
+        <post-downgrade>
+          <task xsi:type="manual">
+            <message>Manual Downgrade</message>
+          </task>
+        </post-downgrade>
+      </component>
+    </service>
+    
+    <service name="YARN">
+      <component name="RESOURCEMANAGER">
+        <pre-upgrade>
+          <task xsi:type="execute">
+            <command>ls</command>
+          </task>
+        </pre-upgrade>
+      </component>
+      <component name="NODEMANAGER">
+        <pre-upgrade>
+          <task xsi:type="execute">
+            <command>ls</command>
+          </task>
+        </pre-upgrade>
+      </component>
+    </service>
+    
+    <service name="HIVE">
+      <component name="HIVE_SERVER">
+        <pre-upgrade>
+          <task xsi:type="manual">
+            <summary>HiveServer Port Availability</summary>
+            <message>The HiveServer port will now change to 10010 if hive is using a binary transfer mode or 10011 if hive is using an http transport mode. You can use "netstat -anp | grep 1001[01]" to determine if the port is available on each of following HiveServer host(s): {{hosts.all}}. If the port is not available, the process using it must be terminated.</message>
+          </task>
+
+          <task xsi:type="configure">
+            <condition type="hive-site" key="hive.server2.transport.mode" value="binary">
+              <type>hive-site</type>
+              <key>hive.server2.thrift.port</key>
+              <value>10010</value>
+            </condition>
+            <condition type="hive-site" key="hive.server2.transport.mode" value="http">
+              <type>hive-site</type>
+              <key>hive.server2.http.port</key>
+              <value>10011</value>
+            </condition>
+          </task>
+        </pre-upgrade>
+       </component>
+     </service>    
+  </processing>
+</upgrade>