You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by nc...@apache.org on 2017/07/13 19:14:45 UTC

[27/37] ambari git commit: AMBARI-21450. Initial cherry-picking for feature branch (ncole)

http://git-wip-us.apache.org/repos/asf/ambari/blob/48f7fb22/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java
index ab8026c..e178b92 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java
@@ -1,4 +1,4 @@
-/**
+/*
  * 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
@@ -17,14 +17,12 @@
  */
 package org.apache.ambari.server.state;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
@@ -86,6 +84,7 @@ public class ConfigHelper {
   public static final String CLUSTER_ENV = "cluster-env";
   public static final String CLUSTER_ENV_ALERT_REPEAT_TOLERANCE = "alerts_repeat_tolerance";
   public static final String CLUSTER_ENV_RETRY_ENABLED = "command_retry_enabled";
+  public static final String SERVICE_CHECK_TYPE = "service_check_type";
   public static final String CLUSTER_ENV_RETRY_COMMANDS = "commands_to_retry";
   public static final String CLUSTER_ENV_RETRY_MAX_TIME_IN_SEC = "command_retry_max_time_in_sec";
   public static final String COMMAND_RETRY_MAX_TIME_IN_SEC_DEFAULT = "600";
@@ -96,6 +95,7 @@ public class ConfigHelper {
 
   public static final String HTTP_ONLY = "HTTP_ONLY";
   public static final String HTTPS_ONLY = "HTTPS_ONLY";
+  public static final String SERVICE_CHECK_MINIMAL = "minimal";
 
   /**
    * The tag given to newly created versions.
@@ -602,8 +602,9 @@ public class ConfigHelper {
                 found = true;
               }
             }
+
             if(!found) {
-             //Log error if the user-group mapping is not found
+              //Log error if the user-group mapping is not found
               LOG.error("User group mapping property {" + userGroupInfo.getType() + "/" + userGroupInfo.getName() + "} is missing for user property {" + ConfigHelper.fileNameToConfigType(userPropertyInfo.getFilename()) + "/" + userPropertyInfo.getName() + "} (username = " + userPropertyInfo.getValue() +")");
             }
           }
@@ -736,8 +737,19 @@ public class ConfigHelper {
         if (serviceProperty.getPropertyTypes().contains(propertyType)) {
           String stackPropertyConfigType = fileNameToConfigType(serviceProperty.getFilename());
           try {
-            result.add(actualConfigs.get(stackPropertyConfigType).getProperties().get(serviceProperty.getName()));
-          } catch (Exception ex) {
+            String property = actualConfigs.get(stackPropertyConfigType).getProperties().get(serviceProperty.getName());
+            if (null == property){
+              LOG.error(String.format("Unable to obtain property values for %s with property attribute %s. "
+                  + "The property does not exist in version %s of %s configuration.",
+                  serviceProperty.getName(),
+                  propertyType,
+                  desiredConfigs.get(stackPropertyConfigType),
+                  stackPropertyConfigType
+                  ));
+            } else {
+              result.add(property);
+            }
+          } catch (Exception ignored) {
           }
         }
       }
@@ -763,23 +775,31 @@ public class ConfigHelper {
    * @throws AmbariException
    */
   public String getPropertyValueFromStackDefinitions(Cluster cluster, String configType, String propertyName) throws AmbariException {
-    StackId stackId = cluster.getCurrentStackVersion();
-    StackInfo stack = ambariMetaInfo.getStack(stackId.getStackName(),
-        stackId.getStackVersion());
 
-    for (ServiceInfo serviceInfo : stack.getServices()) {
-      Set<PropertyInfo> serviceProperties = ambariMetaInfo.getServiceProperties(stack.getName(), stack.getVersion(), serviceInfo.getName());
-      Set<PropertyInfo> stackProperties = ambariMetaInfo.getStackProperties(stack.getName(), stack.getVersion());
-      serviceProperties.addAll(stackProperties);
+    Set<StackId> stackIds = new HashSet<>();
 
-      for (PropertyInfo stackProperty : serviceProperties) {
-        String stackPropertyConfigType = fileNameToConfigType(stackProperty.getFilename());
+    for (Service service : cluster.getServices().values()) {
+      stackIds.add(service.getDesiredStackId());
+    }
+
+    for (StackId stackId : stackIds) {
 
-        if (stackProperty.getName().equals(propertyName) && stackPropertyConfigType.equals(configType)) {
-          return stackProperty.getValue();
+      StackInfo stack = ambariMetaInfo.getStack(stackId.getStackName(),
+          stackId.getStackVersion());
+
+      for (ServiceInfo serviceInfo : stack.getServices()) {
+        Set<PropertyInfo> serviceProperties = ambariMetaInfo.getServiceProperties(stack.getName(), stack.getVersion(), serviceInfo.getName());
+        Set<PropertyInfo> stackProperties = ambariMetaInfo.getStackProperties(stack.getName(), stack.getVersion());
+        serviceProperties.addAll(stackProperties);
+
+        for (PropertyInfo stackProperty : serviceProperties) {
+          String stackPropertyConfigType = fileNameToConfigType(stackProperty.getFilename());
+
+          if (stackProperty.getName().equals(propertyName) && stackPropertyConfigType.equals(configType)) {
+            return stackProperty.getValue();
+          }
         }
       }
-
     }
 
     return null;
@@ -838,20 +858,22 @@ public class ConfigHelper {
   }
 
   public ServiceInfo getPropertyOwnerService(Cluster cluster, String configType, String propertyName) throws AmbariException {
-    StackId stackId = cluster.getCurrentStackVersion();
-    StackInfo stack = ambariMetaInfo.getStack(stackId.getStackName(), stackId.getStackVersion());
 
-    for (ServiceInfo serviceInfo : stack.getServices()) {
-      Set<PropertyInfo> serviceProperties = ambariMetaInfo.getServiceProperties(stack.getName(), stack.getVersion(), serviceInfo.getName());
+    for (Service service : cluster.getServices().values()) {
+      StackId stackId = service.getDesiredStackId();
+      StackInfo stack = ambariMetaInfo.getStack(stackId.getStackName(), stackId.getStackVersion());
 
-      for (PropertyInfo stackProperty : serviceProperties) {
-        String stackPropertyConfigType = fileNameToConfigType(stackProperty.getFilename());
+      for (ServiceInfo serviceInfo : stack.getServices()) {
+        Set<PropertyInfo> serviceProperties = ambariMetaInfo.getServiceProperties(stack.getName(), stack.getVersion(), serviceInfo.getName());
+
+        for (PropertyInfo stackProperty : serviceProperties) {
+          String stackPropertyConfigType = fileNameToConfigType(stackProperty.getFilename());
 
-        if (stackProperty.getName().equals(propertyName) && stackPropertyConfigType.equals(configType)) {
-          return serviceInfo;
+          if (stackProperty.getName().equals(propertyName) && stackPropertyConfigType.equals(configType)) {
+            return serviceInfo;
+          }
         }
       }
-
     }
 
     return null;
@@ -861,7 +883,9 @@ public class ConfigHelper {
     // The original implementation of this method is to return all properties regardless of whether
     // they should be excluded or not.  By setting removeExcluded to false in the method invocation
     // below, no attempt will be made to remove properties that exist in excluded types.
-    return getServiceProperties(cluster.getCurrentStackVersion(), serviceName, false);
+    Service service = cluster.getService(serviceName);
+
+    return getServiceProperties(service.getDesiredStackId(), serviceName, false);
   }
 
   /**
@@ -940,11 +964,10 @@ public class ConfigHelper {
    * @param serviceVersionNote
    * @throws AmbariException
    */
-  public void updateConfigType(Cluster cluster,
-                               AmbariManagementController controller, String configType,
-                               Map<String, String> updates, Collection<String> removals,
-                               String authenticatedUserName,
-                               String serviceVersionNote) throws AmbariException {
+  public void updateConfigType(Cluster cluster, StackId stackId,
+      AmbariManagementController controller, String configType, Map<String, String> updates,
+      Collection<String> removals, String authenticatedUserName, String serviceVersionNote)
+      throws AmbariException {
 
     // Nothing to update or remove
     if (configType == null ||
@@ -987,21 +1010,27 @@ public class ConfigHelper {
 
     if ((oldConfigProperties == null)
       || !Maps.difference(oldConfigProperties, properties).areEqual()) {
-      createConfigType(cluster, controller, configType, properties,
+      createConfigType(cluster, stackId, controller, configType, properties,
         propertiesAttributes, authenticatedUserName, serviceVersionNote);
     }
   }
 
-  private void createConfigType(Cluster cluster,
-                               AmbariManagementController controller,
-                               String configType, Map<String, String> properties,
-                               Map<String, Map<String, String>> propertyAttributes,
-                               String authenticatedUserName,
-                               String serviceVersionNote) throws AmbariException {
+  public void createConfigType(Cluster cluster, StackId stackId,
+      AmbariManagementController controller, String configType, Map<String, String> properties,
+      String authenticatedUserName, String serviceVersionNote) throws AmbariException {
+
+    createConfigType(cluster, stackId, controller, configType, properties,
+        new HashMap<String, Map<String, String>>(), authenticatedUserName, serviceVersionNote);
+  }
+
+  public void createConfigType(Cluster cluster, StackId stackId,
+      AmbariManagementController controller, String configType, Map<String, String> properties,
+      Map<String, Map<String, String>> propertyAttributes, String authenticatedUserName,
+      String serviceVersionNote) throws AmbariException {
 
     // create the configuration history entry
-    Config baseConfig = createConfig(cluster, controller, configType, FIRST_VERSION_TAG, properties,
-        propertyAttributes);
+    Config baseConfig = createConfig(cluster, stackId, controller, configType, FIRST_VERSION_TAG,
+        properties, propertyAttributes);
 
     if (baseConfig != null) {
       cluster.addDesiredConfig(authenticatedUserName,
@@ -1010,46 +1039,18 @@ public class ConfigHelper {
   }
 
   /**
-   * A helper method to create a new {@link Config} for a given configuration
-   * type. This method will perform the following tasks:
-   * <ul>
-   * <li>Create a {@link Config} in the cluster for the specified type. This
-   * will have the proper versions and tags set automatically.</li>
-   * <li>Set the cluster's {@link DesiredConfig} to the new configuration</li>
-   * <li>Create an entry in the configuration history with a note and username.</li>
-   * <ul>
-   *
-   * @param cluster
-   * @param controller
-   * @param configType
-   * @param properties
-   * @param authenticatedUserName
-   * @param serviceVersionNote
-   * @throws AmbariException
-   */
-  public void createConfigType(Cluster cluster,
-                               AmbariManagementController controller,
-                               String configType, Map<String, String> properties,
-                               String authenticatedUserName,
-                               String serviceVersionNote) throws AmbariException {
-    createConfigType(cluster, controller, configType, properties,
-      new HashMap<String, Map<String, String>>(), authenticatedUserName,
-      serviceVersionNote);
-  }
-
-  /**
    * Create configurations and assign them for services.
    * @param cluster               the cluster
    * @param controller            the controller
+   * @param stackId               the stack to create the new properties for
    * @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 {
+  public void createConfigTypes(Cluster cluster, StackId stackId,
+      AmbariManagementController controller, Map<String, Map<String, String>> batchProperties,
+      String authenticatedUserName, String serviceVersionNote) throws AmbariException {
 
     Map<String, Set<Config>> serviceMapped = new HashMap<>();
 
@@ -1057,8 +1058,8 @@ public class ConfigHelper {
       String type = entry.getKey();
       Map<String, String> properties = entry.getValue();
 
-      Config baseConfig = createConfig(cluster, controller, type, FIRST_VERSION_TAG, properties,
-        Collections.<String, Map<String,String>>emptyMap());
+      Config baseConfig = createConfig(cluster, stackId, controller, type, FIRST_VERSION_TAG,
+          properties, Collections.<String, Map<String, String>> emptyMap());
 
       if (null != baseConfig) {
         try {
@@ -1090,9 +1091,13 @@ public class ConfigHelper {
    *
    * @param cluster
    *          the cluster (not {@code null}).
+   * @param stackId
+   *          the stack to create the new properties for
    * @param controller
    *          the controller which actually creates the configuration (not
    *          {@code null}).
+   * @param stackId
+   *          the stack to create the new properties for
    * @param type
    *          the new configuration type (not {@code null}).
    * @param tag
@@ -1105,8 +1110,8 @@ public class ConfigHelper {
    * @return
    * @throws AmbariException
    */
-  Config createConfig(Cluster cluster, AmbariManagementController controller, String type,
-      String tag, Map<String, String> properties,
+  Config createConfig(Cluster cluster, StackId stackId, AmbariManagementController controller,
+      String type, String tag, Map<String, String> properties,
       Map<String, Map<String, String>> propertyAttributes) throws AmbariException {
 
     // if the configuration is not new, then create a timestamp tag
@@ -1177,7 +1182,7 @@ public class ConfigHelper {
    *         default configurations.
    * @throws AmbariException
    */
-  public Map<String, Map<String, String>> getDefaultProperties(StackId stack, Cluster cluster)
+  public Map<String, Map<String, String>> getDefaultProperties(StackId stack, String serviceName)
       throws AmbariException {
     Map<String, Map<String, String>> defaultPropertiesByType = new HashMap<>();
 
@@ -1191,54 +1196,24 @@ public class ConfigHelper {
       if (!defaultPropertiesByType.containsKey(type)) {
         defaultPropertiesByType.put(type, new HashMap<String, String>());
       }
-
-      defaultPropertiesByType.get(type).put(stackDefaultProperty.getName(),
-          stackDefaultProperty.getValue());
     }
 
     // for every installed service, populate the default service properties
-    for (String serviceName : cluster.getServices().keySet()) {
-      Set<org.apache.ambari.server.state.PropertyInfo> serviceConfigurationProperties = ambariMetaInfo.getServiceProperties(
-          stack.getStackName(), stack.getStackVersion(), serviceName);
-
-      // !!! use new stack as the basis
-      for (PropertyInfo serviceDefaultProperty : serviceConfigurationProperties) {
-        String type = ConfigHelper.fileNameToConfigType(serviceDefaultProperty.getFilename());
+    Set<org.apache.ambari.server.state.PropertyInfo> serviceConfigurationProperties = ambariMetaInfo.getServiceProperties(
+        stack.getStackName(), stack.getStackVersion(), serviceName);
 
-        if (!defaultPropertiesByType.containsKey(type)) {
-          defaultPropertiesByType.put(type, new HashMap<String, String>());
-        }
+    // !!! use new stack as the basis
+    for (PropertyInfo serviceDefaultProperty : serviceConfigurationProperties) {
+      String type = ConfigHelper.fileNameToConfigType(serviceDefaultProperty.getFilename());
 
-        defaultPropertiesByType.get(type).put(serviceDefaultProperty.getName(),
-            serviceDefaultProperty.getValue());
+      if (!defaultPropertiesByType.containsKey(type)) {
+        defaultPropertiesByType.put(type, new HashMap<String, String>());
       }
     }
 
     return defaultPropertiesByType;
   }
 
-  /**
-   * Gets whether configurations are stale for a given service host component.
-   *
-   * @param sch
-   *          the SCH to calcualte config staleness for (not {@code null}).
-   * @param desiredConfigs
-   *          the desired configurations for the cluster. Obtaining these can be
-   *          expensive and since this method operates on SCH's, it could be
-   *          called 10,000's of times when generating cluster/host responses.
-   *          Therefore, the caller should build these once and pass them in. If
-   *          {@code null}, then this method will retrieve them at runtime,
-   *          incurring a performance penality.
-   * @return
-   * @throws AmbariException
-   */
-  private boolean calculateIsStaleConfigs(ServiceComponentHost sch,
-      Map<String, DesiredConfig> desiredConfigs) throws AmbariException {
-
-    HostComponentDesiredStateEntity hostComponentDesiredStateEntity = sch.getDesiredStateEntity();
-    return calculateIsStaleConfigs(sch, desiredConfigs, hostComponentDesiredStateEntity);
-  }
-
   private boolean calculateIsStaleConfigs(ServiceComponentHost sch, Map<String, DesiredConfig> desiredConfigs,
                                           HostComponentDesiredStateEntity hostComponentDesiredStateEntity) throws AmbariException {
 
@@ -1272,7 +1247,7 @@ public class ConfigHelper {
 
     stale = false;
 
-    StackId stackId = cluster.getDesiredStackVersion();
+    StackId stackId = sch.getServiceComponent().getDesiredStackId();
 
     ServiceInfo serviceInfo = ambariMetaInfo.getService(stackId.getStackName(),
             stackId.getStackVersion(), sch.getServiceName());
@@ -1346,64 +1321,6 @@ public class ConfigHelper {
   }
 
   /**
-   * @return <code>true</code> if any service on the stack defines a property
-   * for the type.
-   */
-  private boolean hasPropertyFor(StackId stack, String type,
-                                 Collection<String> keys) throws AmbariException {
-
-    for (ServiceInfo svc : ambariMetaInfo.getServices(stack.getStackName(),
-        stack.getStackVersion()).values()) {
-
-      if (svc.hasDependencyAndPropertyFor(type, keys)) {
-        return true;
-      }
-
-    }
-
-    return false;
-  }
-
-  /**
-   * @return the keys that have changed values
-   */
-  private Collection<String> findChangedKeys(Cluster cluster, String type,
-                                             Collection<String> desiredTags, Collection<String> actualTags) {
-
-    Map<String, String> desiredValues = new HashMap<>();
-    Map<String, String> actualValues = new HashMap<>();
-
-    for (String tag : desiredTags) {
-      Config config = cluster.getConfig(type, tag);
-      if (null != config) {
-        desiredValues.putAll(config.getProperties());
-      }
-    }
-
-    for (String tag : actualTags) {
-      Config config = cluster.getConfig(type, tag);
-      if (null != config) {
-        actualValues.putAll(config.getProperties());
-      }
-    }
-
-    List<String> keys = new ArrayList<>();
-
-    for (Entry<String, String> entry : desiredValues.entrySet()) {
-      String key = entry.getKey();
-      String value = entry.getValue();
-
-      if (!actualValues.containsKey(key)) {
-        keys.add(key);
-      } else if (!actualValues.get(key).equals(value)) {
-        keys.add(key);
-      }
-    }
-
-    return keys;
-  }
-
-  /**
    * @return the map of tags for a desired config
    */
   private Map<String, String> buildTags(HostConfig hc) {
@@ -1439,23 +1356,6 @@ public class ConfigHelper {
     return !desiredSet.equals(actualSet);
   }
 
-  /**
-   * @return the list of combined config property names
-   */
-  private Collection<String> mergeKeyNames(Cluster cluster, String type, Collection<String> tags) {
-    Set<String> names = new HashSet<>();
-
-    for (String tag : tags) {
-      Config config = cluster.getConfig(type, tag);
-      if (null != config) {
-        names.addAll(config.getProperties().keySet());
-      }
-    }
-
-    return names;
-  }
-
-
   public static String fileNameToConfigType(String filename) {
     int extIndex = filename.indexOf(AmbariMetaInfo.SERVICE_CONFIG_FILE_NAME_POSTFIX);
     return filename.substring(0, extIndex);

http://git-wip-us.apache.org/repos/asf/ambari/blob/48f7fb22/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryVersionState.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryVersionState.java b/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryVersionState.java
index e02e422..720f307 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryVersionState.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryVersionState.java
@@ -1,4 +1,4 @@
-/**
+/*
  * 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
@@ -18,11 +18,16 @@
 
 package org.apache.ambari.server.state;
 
+import java.util.List;
+
 /**
- * There must be exactly one repository version that is in a CURRENT state for a particular cluster or host.
- * There may be 0 or more repository versions in an INSTALLED or INSTALLING state.
- * The operation to transition a repository version state from INSTALLED into CURRENT must be atomic and change the existing
- * relation between repository version and cluster or host from CURRENT to INSTALLED.
+ * The {@link RepositoryVersionState} represents the state of a repository on a
+ * particular host. Because hosts can contain a mixture of components from
+ * different repositories, there can be any combination of
+ * {@link RepositoryVersionState#CURRENT}} entries for a single host. A host may
+ * not have multiple entries for the same repository.
+ * <p/>
+ *
  *
  * <pre>
  * Step 1: Initial Configuration
@@ -41,20 +46,23 @@ package org.apache.ambari.server.state;
  * Version 1: CURRENT
  * Version 2: INSTALL_FAILED (a retry can set this back to INSTALLING)
  *
- * Step 4: Perform an upgrade from Version 1 to Version 2
+ * Step 4: Perform an upgrade of every component on the host from version 1 to version 2
  * Version 1: INSTALLED
  * Version 2: CURRENT
  *
- * Step 4: May revert to the original version via a downgrade, which is technically still an upgrade to a version
+ * Step 4a: Perform an upgrade of a single component, leaving other components on the prior version
+ * Version 1: CURRENT
+ * Version 2: CURRENT
+ *
+ * Step 4b: May revert to the original version via a downgrade, which is technically still an upgrade to a version
  * and eventually becomes
  *
  * Version 1: CURRENT
  * Version 2: INSTALLED
  *
  * *********************************************
- * Start states: CURRENT, INSTALLING
+ * Start states: NOT_REQUIRED, INSTALLING, CURRENT
  * Allowed Transitions:
- * INIT -> CURRENT
  * INSTALLED -> CURRENT
  * INSTALLING -> INSTALLED | INSTALL_FAILED | OUT_OF_SYNC
  * INSTALLED -> INSTALLED | INSTALLING | OUT_OF_SYNC
@@ -65,35 +73,68 @@ package org.apache.ambari.server.state;
  */
 public enum RepositoryVersionState {
   /**
-   * Repository version is initialized, and will transition to current.  This is used
-   * when creating a cluster using a specific version.  Transition occurs naturally as
-   * hosts report CURRENT.
-   */
-  INIT,
-
-  /**
    * Repository version is not required
    */
-  NOT_REQUIRED,
+  NOT_REQUIRED(0),
+
   /**
    * Repository version that is in the process of being installed.
    */
-  INSTALLING,
+  INSTALLING(3),
+
   /**
    * Repository version that is installed and supported but not the active version.
    */
-  INSTALLED,
+  INSTALLED(2),
+
   /**
    * Repository version that during the install process failed to install some components.
    */
-  INSTALL_FAILED,
+  INSTALL_FAILED(5),
+
   /**
    * Repository version that is installed for some components but not for all.
    */
-  OUT_OF_SYNC,
+  OUT_OF_SYNC(4),
+
   /**
    * Repository version that is installed and supported and is the active version.
    */
-  CURRENT,
+  CURRENT(1);
+
+  private final int weight;
+
+  /**
+   * Constructor.
+   *
+   * @param weight
+   *          the weight of the state.
+   */
+  private RepositoryVersionState(int weight) {
+    this.weight = weight;
+  }
+
+  /**
+   * Gets a single representation of the repository state based on the supplied
+   * states.
+   *
+   * @param states
+   *          the states to calculate the aggregate for.
+   * @return the "heaviest" state.
+   */
+  public static RepositoryVersionState getAggregateState(List<RepositoryVersionState> states) {
+    if (null == states || states.isEmpty()) {
+      return NOT_REQUIRED;
+    }
+
+    RepositoryVersionState heaviestState = states.get(0);
+    for (RepositoryVersionState state : states) {
+      if (state.weight > heaviestState.weight) {
+        heaviestState = state;
+      }
+    }
+
+    return heaviestState;
+  }
 
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/48f7fb22/ambari-server/src/main/java/org/apache/ambari/server/state/Service.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/Service.java b/ambari-server/src/main/java/org/apache/ambari/server/state/Service.java
index 5964e33..b151278 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/Service.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/Service.java
@@ -1,4 +1,4 @@
-/**
+/*
  * 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
@@ -22,6 +22,7 @@ import java.util.Map;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.controller.ServiceResponse;
+import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 
 public interface Service {
 
@@ -64,9 +65,7 @@ public interface Service {
    */
   void setSecurityState(SecurityState securityState) throws AmbariException;
 
-  StackId getDesiredStackVersion();
-
-  void setDesiredStackVersion(StackId stackVersion);
+  StackId getDesiredStackId();
 
   ServiceResponse convertToResponse();
 
@@ -139,6 +138,22 @@ public interface Service {
    */
   void setCredentialStoreEnabled(boolean credentialStoreEnabled);
 
+  /**
+   * @return
+   */
+  RepositoryVersionEntity getDesiredRepositoryVersion();
+
+  /**
+   * @param desiredRepositoryVersion
+   */
+  void setDesiredRepositoryVersion(RepositoryVersionEntity desiredRepositoryVersion);
+
+  /**
+   * Gets the repository for the desired version of this service by consulting
+   * the repository states of all known components.
+   */
+  RepositoryVersionState getRepositoryState();
+
   enum Type {
     HDFS,
     GLUSTERFS,

http://git-wip-us.apache.org/repos/asf/ambari/blob/48f7fb22/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponent.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponent.java
index e93ab9a..9fb2aba 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponent.java
@@ -1,4 +1,4 @@
-/**
+/*
  * 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
@@ -22,6 +22,7 @@ import java.util.Map;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.controller.ServiceComponentResponse;
+import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 
 public interface ServiceComponent {
 
@@ -51,13 +52,18 @@ public interface ServiceComponent {
 
   void setDesiredState(State state);
 
-  StackId getDesiredStackVersion();
+  /**
+   * Gets the desired repository for this service component.
+   *
+   * @return
+   */
+  RepositoryVersionEntity getDesiredRepositoryVersion();
 
-  void setDesiredStackVersion(StackId stackVersion);
+  StackId getDesiredStackId();
 
   String getDesiredVersion();
 
-  void setDesiredVersion(String version);
+  void setDesiredRepositoryVersion(RepositoryVersionEntity repositoryVersionEntity);
 
   /**
    * Refresh Component info due to current stack
@@ -97,4 +103,19 @@ public interface ServiceComponent {
       String hostName) throws AmbariException;
 
   void delete() throws AmbariException;
+
+  /**
+   * This method computes the state of the repository that's associated with the desired
+   * version.  It is used, for example, when a host component reports its version and the
+   * state can be in flux.
+   *
+   * @param reportedVersion
+   * @throws AmbariException
+   */
+  void updateRepositoryState(String reportedVersion) throws AmbariException;
+
+  /**
+   * @return the repository state for the desired version
+   */
+  RepositoryVersionState getRepositoryState();
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/48f7fb22/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHost.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHost.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHost.java
index 104e456..3c314d8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHost.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHost.java
@@ -1,4 +1,4 @@
-/**
+/*
  * 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
@@ -24,7 +24,7 @@ import java.util.Map;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.controller.ServiceComponentHostResponse;
 import org.apache.ambari.server.orm.entities.HostComponentDesiredStateEntity;
-import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
+import org.apache.ambari.server.orm.entities.HostVersionEntity;
 import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
 
 
@@ -91,10 +91,6 @@ public interface ServiceComponentHost {
 
   void setDesiredState(State state);
 
-  StackId getDesiredStackVersion();
-
-  void setDesiredStackVersion(StackId stackVersion);
-
   State getState();
 
   void setState(State state);
@@ -167,10 +163,6 @@ public interface ServiceComponentHost {
    */
   UpgradeState getUpgradeState();
 
-  StackId getStackVersion();
-
-  void setStackVersion(StackId stackVersion);
-
   HostComponentAdminState getComponentAdminState();
 
   void setComponentAdminState(HostComponentAdminState attribute);
@@ -242,13 +234,31 @@ public interface ServiceComponentHost {
    */
   void setRestartRequired(boolean restartRequired);
 
+
+  HostComponentDesiredStateEntity getDesiredStateEntity();
+
+  /**
+   * Gets the service component.
+   *
+   * @return the service component (never {@code null}).
+   */
+  ServiceComponent getServiceComponent();
+
   /**
-   * Changes host version state according to state of the components installed on the host.
-   * @return The Repository Version Entity with that component in the host
-   * @throws AmbariException if host is detached from the cluster
+   * Updates an existing {@link HostVersionEntity} for the desired repository of
+   * this component, or create one if it doesn't exist.
+   *
+   * @return Returns either the newly created or the updated Host Version
+   *         Entity.
+   * @throws AmbariException
    */
-  RepositoryVersionEntity recalculateHostVersionState() throws AmbariException;
+  HostVersionEntity recalculateHostVersionState() throws AmbariException;
 
-  HostComponentDesiredStateEntity getDesiredStateEntity();
+  /**
+   * Convenience method to get the desired stack id from the service component
+   *
+   * @return the desired stack id
+   */
+  StackId getDesiredStackId();
 
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/48f7fb22/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java
index cbf0ff9..5f85e38 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java
@@ -1,4 +1,4 @@
-/**
+/*
  * 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
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.state;
 
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentHashMap;
@@ -32,21 +33,30 @@ import org.apache.ambari.server.ServiceComponentHostNotFoundException;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.controller.ServiceComponentResponse;
 import org.apache.ambari.server.events.ServiceComponentRecoveryChangedEvent;
+import org.apache.ambari.server.events.listeners.upgrade.StackVersionListener;
 import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.orm.dao.ClusterServiceDAO;
 import org.apache.ambari.server.orm.dao.HostComponentDesiredStateDAO;
+import org.apache.ambari.server.orm.dao.HostComponentStateDAO;
+import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
 import org.apache.ambari.server.orm.dao.ServiceComponentDesiredStateDAO;
-import org.apache.ambari.server.orm.dao.StackDAO;
 import org.apache.ambari.server.orm.entities.ClusterServiceEntity;
 import org.apache.ambari.server.orm.entities.ClusterServiceEntityPK;
 import org.apache.ambari.server.orm.entities.HostComponentDesiredStateEntity;
 import org.apache.ambari.server.orm.entities.HostComponentStateEntity;
+import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.ServiceComponentDesiredStateEntity;
+import org.apache.ambari.server.orm.entities.ServiceComponentVersionEntity;
 import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.state.cluster.ClusterImpl;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.MapUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Function;
+import com.google.common.collect.Maps;
+import com.google.inject.Inject;
 import com.google.inject.ProvisionException;
 import com.google.inject.assistedinject.Assisted;
 import com.google.inject.assistedinject.AssistedInject;
@@ -74,24 +84,25 @@ public class ServiceComponentImpl implements ServiceComponent {
 
   private AmbariMetaInfo ambariMetaInfo;
 
-  private final ConcurrentMap<String, ServiceComponentHost> hostComponents = new ConcurrentHashMap<String, ServiceComponentHost>();
+  private final ConcurrentMap<String, ServiceComponentHost> hostComponents = new ConcurrentHashMap<>();
 
   /**
    * The ID of the persisted {@link ServiceComponentDesiredStateEntity}.
    */
   private final long desiredStateEntityId;
 
-  /**
-   * Data access object used for lookup up stacks.
-   */
-  private final StackDAO stackDAO;
+  @Inject
+  private RepositoryVersionDAO repoVersionDAO;
+
+  @Inject
+  private HostComponentStateDAO hostComponentDAO;
 
   @AssistedInject
   public ServiceComponentImpl(@Assisted Service service, @Assisted String componentName,
       AmbariMetaInfo ambariMetaInfo,
       ServiceComponentDesiredStateDAO serviceComponentDesiredStateDAO,
       ClusterServiceDAO clusterServiceDAO, ServiceComponentHostFactory serviceComponentHostFactory,
-      StackDAO stackDAO, AmbariEventPublisher eventPublisher)
+      AmbariEventPublisher eventPublisher)
       throws AmbariException {
 
     this.ambariMetaInfo = ambariMetaInfo;
@@ -100,20 +111,15 @@ public class ServiceComponentImpl implements ServiceComponent {
     this.serviceComponentDesiredStateDAO = serviceComponentDesiredStateDAO;
     this.clusterServiceDAO = clusterServiceDAO;
     this.serviceComponentHostFactory = serviceComponentHostFactory;
-    this.stackDAO = stackDAO;
     this.eventPublisher = eventPublisher;
 
-    StackId stackId = service.getDesiredStackVersion();
-    StackEntity stackEntity = stackDAO.find(stackId.getStackName(), stackId.getStackVersion());
-
     ServiceComponentDesiredStateEntity desiredStateEntity = new ServiceComponentDesiredStateEntity();
     desiredStateEntity.setComponentName(componentName);
     desiredStateEntity.setDesiredState(State.INIT);
-    desiredStateEntity.setDesiredVersion(State.UNKNOWN.toString());
     desiredStateEntity.setServiceName(service.getName());
     desiredStateEntity.setClusterId(service.getClusterId());
     desiredStateEntity.setRecoveryEnabled(false);
-    desiredStateEntity.setDesiredStack(stackEntity);
+    desiredStateEntity.setDesiredRepositoryVersion(service.getDesiredRepositoryVersion());
 
     updateComponentInfo();
 
@@ -121,8 +127,9 @@ public class ServiceComponentImpl implements ServiceComponent {
     desiredStateEntityId = desiredStateEntity.getId();
   }
 
+  @Override
   public void updateComponentInfo() throws AmbariException {
-    StackId stackId = service.getDesiredStackVersion();
+    StackId stackId = service.getDesiredStackId();
     try {
       ComponentInfo compInfo = ambariMetaInfo.getComponent(stackId.getStackName(),
           stackId.getStackVersion(), service.getName(), componentName);
@@ -147,14 +154,13 @@ public class ServiceComponentImpl implements ServiceComponent {
       ServiceComponentDesiredStateDAO serviceComponentDesiredStateDAO,
       ClusterServiceDAO clusterServiceDAO,
       HostComponentDesiredStateDAO hostComponentDesiredStateDAO,
-      ServiceComponentHostFactory serviceComponentHostFactory, StackDAO stackDAO,
+      ServiceComponentHostFactory serviceComponentHostFactory,
       AmbariEventPublisher eventPublisher)
       throws AmbariException {
     this.service = service;
     this.serviceComponentDesiredStateDAO = serviceComponentDesiredStateDAO;
     this.clusterServiceDAO = clusterServiceDAO;
     this.serviceComponentHostFactory = serviceComponentHostFactory;
-    this.stackDAO = stackDAO;
     this.eventPublisher = eventPublisher;
     this.ambariMetaInfo = ambariMetaInfo;
 
@@ -177,7 +183,7 @@ public class ServiceComponentImpl implements ServiceComponent {
           serviceComponentHostFactory.createExisting(this,
             hostComponentStateEntity, hostComponentDesiredStateEntity));
       } catch(ProvisionException ex) {
-        StackId currentStackId = service.getCluster().getCurrentStackVersion();
+        StackId currentStackId = getDesiredStackId();
         LOG.error(String.format("Can not get host component info: stackName=%s, stackVersion=%s, serviceName=%s, componentName=%s, hostname=%s",
           currentStackId.getStackName(), currentStackId.getStackVersion(),
           service.getName(),serviceComponentDesiredStateEntity.getComponentName(), hostComponentStateEntity.getHostName()));
@@ -219,11 +225,8 @@ public class ServiceComponentImpl implements ServiceComponent {
   @Override
   public void setRecoveryEnabled(boolean recoveryEnabled) {
     if (LOG.isDebugEnabled()) {
-      LOG.debug("Setting RecoveryEnabled of Component" + ", clusterName="
-          + service.getCluster().getClusterName() + ", clusterId="
-          + service.getCluster().getClusterId() + ", serviceName=" + service.getName()
-          + ", componentName=" + getName() + ", oldRecoveryEnabled=" + isRecoveryEnabled()
-          + ", newRecoveryEnabled=" + recoveryEnabled);
+      LOG.debug("Setting RecoveryEnabled of Component, clusterName={}, clusterId={}, serviceName={}, componentName={}, oldRecoveryEnabled={}, newRecoveryEnabled={}",
+        service.getCluster().getClusterName(), service.getCluster().getClusterId(), service.getName(), getName(), isRecoveryEnabled(), recoveryEnabled);
     }
 
     ServiceComponentDesiredStateEntity desiredStateEntity = serviceComponentDesiredStateDAO.findById(
@@ -256,7 +259,7 @@ public class ServiceComponentImpl implements ServiceComponent {
 
   @Override
   public Map<String, ServiceComponentHost> getServiceComponentHosts() {
-    return new HashMap<String, ServiceComponentHost>(hostComponents);
+    return new HashMap<>(hostComponents);
   }
 
   @Override
@@ -283,11 +286,8 @@ public class ServiceComponentImpl implements ServiceComponent {
       // TODO validation
       // TODO ensure host belongs to cluster
       if (LOG.isDebugEnabled()) {
-        LOG.debug("Adding a ServiceComponentHost to ServiceComponent" + ", clusterName="
-            + service.getCluster().getClusterName() + ", clusterId="
-            + service.getCluster().getClusterId() + ", serviceName=" + service.getName()
-            + ", serviceComponentName=" + getName() + ", hostname=" + hostComponent.getHostName()
-            + ", recoveryEnabled=" + isRecoveryEnabled());
+        LOG.debug("Adding a ServiceComponentHost to ServiceComponent, clusterName={}, clusterId={}, serviceName={}, serviceComponentName={}, hostname={}, recoveryEnabled={}",
+          service.getCluster().getClusterName(), service.getCluster().getClusterId(), service.getName(), getName(), hostComponent.getHostName(), isRecoveryEnabled());
       }
 
       if (hostComponents.containsKey(hostComponent.getHostName())) {
@@ -344,11 +344,8 @@ public class ServiceComponentImpl implements ServiceComponent {
   @Override
   public void setDesiredState(State state) {
     if (LOG.isDebugEnabled()) {
-      LOG.debug("Setting DesiredState of Service" + ", clusterName="
-          + service.getCluster().getClusterName() + ", clusterId="
-          + service.getCluster().getClusterId() + ", serviceName=" + service.getName()
-          + ", serviceComponentName=" + getName() + ", oldDesiredState=" + getDesiredState()
-          + ", newDesiredState=" + state);
+      LOG.debug("Setting DesiredState of Service, clusterName={}, clusterId={}, serviceName={}, serviceComponentName={}, oldDesiredState={}, newDesiredState={}",
+        service.getCluster().getClusterName(), service.getCluster().getClusterId(), service.getName(), getName(), getDesiredState(), state);
     }
 
     ServiceComponentDesiredStateEntity desiredStateEntity = serviceComponentDesiredStateDAO.findById(
@@ -364,7 +361,7 @@ public class ServiceComponentImpl implements ServiceComponent {
   }
 
   @Override
-  public StackId getDesiredStackVersion() {
+  public StackId getDesiredStackId() {
     ServiceComponentDesiredStateEntity desiredStateEntity = serviceComponentDesiredStateDAO.findById(
         desiredStateEntityId);
 
@@ -376,22 +373,16 @@ public class ServiceComponentImpl implements ServiceComponent {
     }
   }
 
+  /**
+   * {@inheritDoc}
+   */
   @Override
-  public void setDesiredStackVersion(StackId stack) {
-    if (LOG.isDebugEnabled()) {
-      LOG.debug("Setting DesiredStackVersion of Service" + ", clusterName="
-          + service.getCluster().getClusterName() + ", clusterId="
-          + service.getCluster().getClusterId() + ", serviceName=" + service.getName()
-          + ", serviceComponentName=" + getName() + ", oldDesiredStackVersion="
-          + getDesiredStackVersion() + ", newDesiredStackVersion=" + stack);
-    }
-
+  public void setDesiredRepositoryVersion(RepositoryVersionEntity repositoryVersionEntity) {
     ServiceComponentDesiredStateEntity desiredStateEntity = serviceComponentDesiredStateDAO.findById(
         desiredStateEntityId);
 
     if (desiredStateEntity != null) {
-      StackEntity stackEntity = stackDAO.find(stack.getStackName(), stack.getStackVersion());
-      desiredStateEntity.setDesiredStack(stackEntity);
+      desiredStateEntity.setDesiredRepositoryVersion(repositoryVersionEntity);
       desiredStateEntity = serviceComponentDesiredStateDAO.merge(desiredStateEntity);
     } else {
       LOG.warn("Setting a member on an entity object that may have been "
@@ -399,35 +390,37 @@ public class ServiceComponentImpl implements ServiceComponent {
     }
   }
 
+  /**
+   * {@inheritDoc}
+   */
   @Override
-  public String getDesiredVersion() {
+  public RepositoryVersionEntity getDesiredRepositoryVersion() {
     ServiceComponentDesiredStateEntity desiredStateEntity = serviceComponentDesiredStateDAO.findById(
         desiredStateEntityId);
 
-    return desiredStateEntity.getDesiredVersion();
+    return desiredStateEntity.getDesiredRepositoryVersion();
   }
 
   @Override
-  public void setDesiredVersion(String version) {
+  public String getDesiredVersion() {
     ServiceComponentDesiredStateEntity desiredStateEntity = serviceComponentDesiredStateDAO.findById(
         desiredStateEntityId);
 
-      if (desiredStateEntity != null) {
-        desiredStateEntity.setDesiredVersion(version);
-      desiredStateEntity = serviceComponentDesiredStateDAO.merge(desiredStateEntity);
-      } else {
-        LOG.warn("Setting a member on an entity object that may have been " +
-          "previously deleted, serviceName = " + (service != null ? service.getName() : ""));
-      }
+    return desiredStateEntity.getDesiredVersion();
   }
 
   @Override
   public ServiceComponentResponse convertToResponse() {
     Cluster cluster = service.getCluster();
+    RepositoryVersionEntity repositoryVersionEntity = getDesiredRepositoryVersion();
+    StackId desiredStackId = repositoryVersionEntity.getStackId();
+
     ServiceComponentResponse r = new ServiceComponentResponse(getClusterId(),
         cluster.getClusterName(), service.getName(), getName(),
-        getDesiredStackVersion().getStackId(), getDesiredState().toString(),
-        getServiceComponentStateCount(), isRecoveryEnabled(), displayName);
+        desiredStackId, getDesiredState().toString(),
+        getServiceComponentStateCount(), isRecoveryEnabled(), displayName,
+        repositoryVersionEntity.getVersion(), getRepositoryState());
+
     return r;
   }
 
@@ -439,11 +432,14 @@ public class ServiceComponentImpl implements ServiceComponent {
 
   @Override
   public void debugDump(StringBuilder sb) {
-    sb.append("ServiceComponent={ serviceComponentName=" + getName() + ", recoveryEnabled="
-        + isRecoveryEnabled() + ", clusterName=" + service.getCluster().getClusterName()
-        + ", clusterId=" + service.getCluster().getClusterId() + ", serviceName="
-        + service.getName() + ", desiredStackVersion=" + getDesiredStackVersion()
-        + ", desiredState=" + getDesiredState().toString() + ", hostcomponents=[ ");
+    sb.append("ServiceComponent={ serviceComponentName=").append(getName())
+      .append(", recoveryEnabled=").append(isRecoveryEnabled())
+      .append(", clusterName=").append(service.getCluster().getClusterName())
+      .append(", clusterId=").append(service.getCluster().getClusterId())
+      .append(", serviceName=").append(service.getName())
+      .append(", desiredStackVersion=").append(getDesiredStackId())
+      .append(", desiredState=").append(getDesiredState())
+      .append(", hostcomponents=[ ");
     boolean first = true;
     for (ServiceComponentHost sch : hostComponents.values()) {
       if (!first) {
@@ -572,6 +568,152 @@ public class ServiceComponentImpl implements ServiceComponent {
   }
 
 
+  /**
+   * Follows this version logic:
+   * <table border="1">
+   *   <tr>
+   *     <th>DB hostcomponent1</th>
+   *     <th>DB hostcomponentN</th>
+   *     <th>DB desired</th>
+   *     <th>New desired</th>
+   *     <th>Repo State</th>
+   *   </tr>
+   *   <tr>
+   *     <td>v1</td>
+   *     <td>v1</td>
+   *     <td>UNKNOWN</td>
+   *     <td>v1</td>
+   *     <td>CURRENT</td>
+   *   </tr>
+   *   <tr>
+   *     <td>v1</td>
+   *     <td>v2</td>
+   *     <td>UNKNOWN</td>
+   *     <td>UNKNOWN</td>
+   *     <td>OUT_OF_SYNC</td>
+   *   </tr>
+   *   <tr>
+   *     <td>v1</td>
+   *     <td>v2</td>
+   *     <td>v2</td>
+   *     <td>v2 (no change)</td>
+   *     <td>OUT_OF_SYNC</td>
+   *   </tr>
+   *   <tr>
+   *     <td>v2</td>
+   *     <td>v2</td>
+   *     <td>v1</td>
+   *     <td>v1 (no change)</td>
+   *     <td>OUT_OF_SYNC</td>
+   *   </tr>
+   *   <tr>
+   *     <td>v2</td>
+   *     <td>v2</td>
+   *     <td>v2</td>
+   *     <td>v2 (no change)</td>
+   *     <td>CURRENT</td>
+   *   </tr>
+   * </table>
+   */
+  @Override
+  @Transactional
+  public void updateRepositoryState(String reportedVersion) throws AmbariException {
+
+    ServiceComponentDesiredStateEntity component = serviceComponentDesiredStateDAO.findById(
+        desiredStateEntityId);
+
+    List<ServiceComponentVersionEntity> componentVersions = serviceComponentDesiredStateDAO.findVersions(
+        getClusterId(), getServiceName(), getName());
+
+    // per component, this list should be small, so iterating here isn't a big deal
+    Map<String, ServiceComponentVersionEntity> map = new HashMap<>(Maps.uniqueIndex(componentVersions,
+        new Function<ServiceComponentVersionEntity, String>() {
+          @Override
+          public String apply(ServiceComponentVersionEntity input) {
+            return input.getRepositoryVersion().getVersion();
+          }
+      }));
+
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("Existing versions for {}/{}/{}: {}",
+          getClusterName(), getServiceName(), getName(), map.keySet());
+    }
+
+    ServiceComponentVersionEntity componentVersion = map.get(reportedVersion);
+
+    if (null == componentVersion) {
+      RepositoryVersionEntity repoVersion = repoVersionDAO.findByStackAndVersion(
+          getDesiredStackId(), reportedVersion);
+
+      if (null != repoVersion) {
+        componentVersion = new ServiceComponentVersionEntity();
+        componentVersion.setRepositoryVersion(repoVersion);
+        componentVersion.setState(RepositoryVersionState.INSTALLED);
+        componentVersion.setUserName("auto-reported");
+
+        // since we've never seen this version before, mark the component as CURRENT
+        component.setRepositoryState(RepositoryVersionState.CURRENT);
+        component.addVersion(componentVersion);
+
+        component = serviceComponentDesiredStateDAO.merge(component);
+
+        map.put(reportedVersion, componentVersion);
+
+      } else {
+        LOG.warn("There is no repository available for stack {}, version {}",
+            getDesiredStackId(), reportedVersion);
+      }
+    }
+
+    if (MapUtils.isNotEmpty(map)) {
+      String desiredVersion = component.getDesiredVersion();
+      RepositoryVersionEntity desiredRepositoryVersion = service.getDesiredRepositoryVersion();
+
+      List<HostComponentStateEntity> hostComponents = hostComponentDAO.findByServiceAndComponentAndNotVersion(
+          component.getServiceName(), component.getComponentName(), reportedVersion);
+
+      LOG.debug("{}/{} reportedVersion={}, desiredVersion={}, non-matching desired count={}, repo_state={}",
+          component.getServiceName(), component.getComponentName(), reportedVersion,
+          desiredVersion, hostComponents.size(), component.getRepositoryState());
+
+      // !!! if we are unknown, that means it's never been set.  Try to determine it.
+      if (StackVersionListener.UNKNOWN_VERSION.equals(desiredVersion)) {
+        if (CollectionUtils.isEmpty(hostComponents)) {
+          // all host components are the same version as reported
+          component.setDesiredRepositoryVersion(desiredRepositoryVersion);
+          component.setRepositoryState(RepositoryVersionState.CURRENT);
+        } else {
+          // desired is UNKNOWN and there's a mix of versions in the host components
+          component.setRepositoryState(RepositoryVersionState.OUT_OF_SYNC);
+        }
+      } else {
+        if (!reportedVersion.equals(desiredVersion)) {
+          component.setRepositoryState(RepositoryVersionState.OUT_OF_SYNC);
+        } else if (CollectionUtils.isEmpty(hostComponents)) {
+          component.setRepositoryState(RepositoryVersionState.CURRENT);
+        }
+      }
+
+      component = serviceComponentDesiredStateDAO.merge(component);
+    }
+  }
+
+  @Override
+  public RepositoryVersionState getRepositoryState() {
+    ServiceComponentDesiredStateEntity component = serviceComponentDesiredStateDAO.findById(
+        desiredStateEntityId);
+
+    if (null != component) {
+      return component.getRepositoryState();
+    } else {
+      LOG.warn("Cannot retrieve repository state on component that may have been deleted: service {}, component {}",
+          service != null ? service.getName() : null, componentName);
+
+      return null;
+    }
+  }
+
+
   private int getSCHCountByState(State state) {
     int count = 0;
     for (ServiceComponentHost sch : hostComponents.values()) {
@@ -583,7 +725,7 @@ public class ServiceComponentImpl implements ServiceComponent {
   }
 
   private Map <String, Integer> getServiceComponentStateCount() {
-    Map <String, Integer> serviceComponentStateCountMap = new HashMap <String, Integer>();
+    Map <String, Integer> serviceComponentStateCountMap = new HashMap<>();
     serviceComponentStateCountMap.put("startedCount", getSCHCountByState(State.STARTED));
     serviceComponentStateCountMap.put("installedCount", getSCHCountByState(State.INSTALLED));
     serviceComponentStateCountMap.put("installFailedCount", getSCHCountByState(State.INSTALL_FAILED));

http://git-wip-us.apache.org/repos/asf/ambari/blob/48f7fb22/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceFactory.java
index a3a041b..a4c953f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceFactory.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceFactory.java
@@ -1,4 +1,4 @@
-/**
+/*
  * 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
@@ -19,10 +19,33 @@
 package org.apache.ambari.server.state;
 
 import org.apache.ambari.server.orm.entities.ClusterServiceEntity;
+import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 
 public interface ServiceFactory {
 
-  Service createNew(Cluster cluster, String serviceName);
+  /**
+   * Creates a new service in memory and then persists it to the database.
+   *
+   * @param cluster
+   *          the cluster the service is for (not {@code null).
+   * @param serviceName
+   *          the name of the service (not {@code null).
+   * @param desiredRepositoryVersion
+   *          the repository version of the service (not {@code null).
+   * @return
+   */
+  Service createNew(Cluster cluster, String serviceName,
+      RepositoryVersionEntity desiredRepositoryVersion);
 
+  /**
+   * Creates an in-memory representation of a service from an existing database
+   * object.
+   *
+   * @param cluster
+   *          the cluster the service is installed in (not {@code null).
+   * @param serviceEntity
+   *          the entity the existing database entry (not {@code null).
+   * @return
+   */
   Service createExisting(Cluster cluster, ClusterServiceEntity serviceEntity);
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/48f7fb22/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
index 26fe9c0..e2956ca 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
@@ -1,4 +1,4 @@
-/**
+/*
  * 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
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.state;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -40,12 +41,11 @@ import org.apache.ambari.server.orm.dao.ClusterDAO;
 import org.apache.ambari.server.orm.dao.ClusterServiceDAO;
 import org.apache.ambari.server.orm.dao.ServiceConfigDAO;
 import org.apache.ambari.server.orm.dao.ServiceDesiredStateDAO;
-import org.apache.ambari.server.orm.dao.StackDAO;
 import org.apache.ambari.server.orm.entities.ClusterConfigEntity;
-import org.apache.ambari.server.orm.entities.ClusterConfigMappingEntity;
 import org.apache.ambari.server.orm.entities.ClusterEntity;
 import org.apache.ambari.server.orm.entities.ClusterServiceEntity;
 import org.apache.ambari.server.orm.entities.ClusterServiceEntityPK;
+import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.ServiceComponentDesiredStateEntity;
 import org.apache.ambari.server.orm.entities.ServiceConfigEntity;
 import org.apache.ambari.server.orm.entities.ServiceDesiredStateEntity;
@@ -84,11 +84,6 @@ public class ServiceImpl implements Service {
   private final ServiceComponentFactory serviceComponentFactory;
 
   /**
-   * Data access object for retrieving stack instances.
-   */
-  private final StackDAO stackDAO;
-
-  /**
    * Used to publish events relating to service CRUD operations.
    */
   private final AmbariEventPublisher eventPublisher;
@@ -99,17 +94,16 @@ public class ServiceImpl implements Service {
   private final String serviceName;
 
   @AssistedInject
-  ServiceImpl(@Assisted Cluster cluster, @Assisted String serviceName, ClusterDAO clusterDAO,
+  ServiceImpl(@Assisted Cluster cluster, @Assisted String serviceName,
+      @Assisted RepositoryVersionEntity desiredRepositoryVersion, ClusterDAO clusterDAO,
       ClusterServiceDAO clusterServiceDAO, ServiceDesiredStateDAO serviceDesiredStateDAO,
-      ServiceComponentFactory serviceComponentFactory, StackDAO stackDAO,
-      AmbariMetaInfo ambariMetaInfo, AmbariEventPublisher eventPublisher)
-      throws AmbariException {
+      ServiceComponentFactory serviceComponentFactory, AmbariMetaInfo ambariMetaInfo,
+      AmbariEventPublisher eventPublisher) throws AmbariException {
     this.cluster = cluster;
     this.clusterDAO = clusterDAO;
     this.clusterServiceDAO = clusterServiceDAO;
     this.serviceDesiredStateDAO = serviceDesiredStateDAO;
     this.serviceComponentFactory = serviceComponentFactory;
-    this.stackDAO = stackDAO;
     this.eventPublisher = eventPublisher;
     this.serviceName = serviceName;
     this.ambariMetaInfo = ambariMetaInfo;
@@ -120,15 +114,14 @@ public class ServiceImpl implements Service {
     ServiceDesiredStateEntity serviceDesiredStateEntity = new ServiceDesiredStateEntity();
     serviceDesiredStateEntity.setServiceName(serviceName);
     serviceDesiredStateEntity.setClusterId(cluster.getClusterId());
+    serviceDesiredStateEntity.setDesiredRepositoryVersion(desiredRepositoryVersion);
     serviceDesiredStateEntityPK = getServiceDesiredStateEntityPK(serviceDesiredStateEntity);
     serviceEntityPK = getServiceEntityPK(serviceEntity);
 
     serviceDesiredStateEntity.setClusterServiceEntity(serviceEntity);
     serviceEntity.setServiceDesiredStateEntity(serviceDesiredStateEntity);
 
-    StackId stackId = cluster.getDesiredStackVersion();
-    StackEntity stackEntity = stackDAO.find(stackId.getStackName(), stackId.getStackVersion());
-    serviceDesiredStateEntity.setDesiredStack(stackEntity);
+    StackId stackId = desiredRepositoryVersion.getStackId();
 
     ServiceInfo sInfo = ambariMetaInfo.getService(stackId.getStackName(),
         stackId.getStackVersion(), serviceName);
@@ -145,15 +138,13 @@ public class ServiceImpl implements Service {
   ServiceImpl(@Assisted Cluster cluster, @Assisted ClusterServiceEntity serviceEntity,
       ClusterDAO clusterDAO, ClusterServiceDAO clusterServiceDAO,
       ServiceDesiredStateDAO serviceDesiredStateDAO,
-      ServiceComponentFactory serviceComponentFactory, StackDAO stackDAO,
-      AmbariMetaInfo ambariMetaInfo, AmbariEventPublisher eventPublisher)
-      throws AmbariException {
+      ServiceComponentFactory serviceComponentFactory, AmbariMetaInfo ambariMetaInfo,
+      AmbariEventPublisher eventPublisher) throws AmbariException {
     this.cluster = cluster;
     this.clusterDAO = clusterDAO;
     this.clusterServiceDAO = clusterServiceDAO;
     this.serviceDesiredStateDAO = serviceDesiredStateDAO;
     this.serviceComponentFactory = serviceComponentFactory;
-    this.stackDAO = stackDAO;
     this.eventPublisher = eventPublisher;
     serviceName = serviceEntity.getServiceName();
     this.ambariMetaInfo = ambariMetaInfo;
@@ -170,7 +161,7 @@ public class ServiceImpl implements Service {
                 serviceComponentFactory.createExisting(this,
                     serviceComponentDesiredStateEntity));
           } catch(ProvisionException ex) {
-            StackId stackId = cluster.getCurrentStackVersion();
+            StackId stackId = new StackId(serviceComponentDesiredStateEntity.getDesiredStack());
             LOG.error(String.format("Can not get component info: stackName=%s, stackVersion=%s, serviceName=%s, componentName=%s",
                 stackId.getStackName(), stackId.getStackVersion(),
                 serviceEntity.getServiceName(),serviceComponentDesiredStateEntity.getComponentName()));
@@ -179,7 +170,7 @@ public class ServiceImpl implements Service {
       }
     }
 
-    StackId stackId = getDesiredStackVersion();
+    StackId stackId = getDesiredStackId();
     ServiceInfo sInfo = ambariMetaInfo.getService(stackId.getStackName(),
         stackId.getStackVersion(), getName());
     isClientOnlyService = sInfo.isClientOnlyService();
@@ -195,8 +186,8 @@ public class ServiceImpl implements Service {
   @Override
   public void updateServiceInfo() throws AmbariException {
     try {
-      ServiceInfo serviceInfo = ambariMetaInfo.getService(cluster.getDesiredStackVersion().getStackName(),
-              cluster.getDesiredStackVersion().getStackVersion(), getName());
+      ServiceInfo serviceInfo = ambariMetaInfo.getService(this);
+
       isClientOnlyService = serviceInfo.isClientOnlyService();
       isCredentialStoreSupported = serviceInfo.isCredentialStoreSupported();
       isCredentialStoreRequired = serviceInfo.isCredentialStoreRequired();
@@ -206,7 +197,7 @@ public class ServiceImpl implements Service {
               + " not recognized in stack info"
               + ", clusterName=" + cluster.getClusterName()
               + ", serviceName=" + getName()
-              + ", stackInfo=" + cluster.getDesiredStackVersion().getStackName());
+              + ", stackInfo=" + getDesiredStackId().getStackName());
     }
   }
 
@@ -222,7 +213,7 @@ public class ServiceImpl implements Service {
 
   @Override
   public Map<String, ServiceComponent> getServiceComponents() {
-    return new HashMap<String, ServiceComponent>(components);
+    return new HashMap<>(components);
   }
 
   @Override
@@ -275,11 +266,8 @@ public class ServiceImpl implements Service {
   @Override
   public void setDesiredState(State state) {
     if (LOG.isDebugEnabled()) {
-      LOG.debug("Setting DesiredState of Service" + ", clusterName="
-          + cluster.getClusterName() + ", clusterId="
-          + cluster.getClusterId() + ", serviceName=" + getName()
-          + ", oldDesiredState=" + getDesiredState() + ", newDesiredState="
-          + state);
+      LOG.debug("Setting DesiredState of Service, clusterName={}, clusterId={}, serviceName={}, oldDesiredState={}, newDesiredState={}",
+        cluster.getClusterName(), cluster.getClusterId(), getName(), getDesiredState(), state);
     }
 
     ServiceDesiredStateEntity serviceDesiredStateEntity = getServiceDesiredStateEntity();
@@ -300,49 +288,81 @@ public class ServiceImpl implements Service {
     }
 
     if (LOG.isDebugEnabled()) {
-      LOG.debug("Setting DesiredSecurityState of Service" + ", clusterName="
-          + cluster.getClusterName() + ", clusterId="
-          + cluster.getClusterId() + ", serviceName=" + getName()
-          + ", oldDesiredSecurityState=" + getSecurityState()
-          + ", newDesiredSecurityState=" + securityState);
+      LOG.debug("Setting DesiredSecurityState of Service, clusterName={}, clusterId={}, serviceName={}, oldDesiredSecurityState={}, newDesiredSecurityState={}",
+        cluster.getClusterName(), cluster.getClusterId(), getName(), getSecurityState(), securityState);
     }
     ServiceDesiredStateEntity serviceDesiredStateEntity = getServiceDesiredStateEntity();
     serviceDesiredStateEntity.setSecurityState(securityState);
     serviceDesiredStateDAO.merge(serviceDesiredStateEntity);
   }
 
+  /**
+   * {@inheritDoc}
+   */
   @Override
-  public StackId getDesiredStackVersion() {
+  public StackId getDesiredStackId() {
     ServiceDesiredStateEntity serviceDesiredStateEntity = getServiceDesiredStateEntity();
-    StackEntity desiredStackEntity = serviceDesiredStateEntity.getDesiredStack();
-    if( null != desiredStackEntity ) {
-      return new StackId(desiredStackEntity);
-    } else {
+
+    if (null == serviceDesiredStateEntity) {
       return null;
+    } else {
+      StackEntity desiredStackEntity = serviceDesiredStateEntity.getDesiredStack();
+      return new StackId(desiredStackEntity);
     }
   }
 
+  /**
+   * {@inheritDoc}
+   */
   @Override
-  public void setDesiredStackVersion(StackId stack) {
-    if (LOG.isDebugEnabled()) {
-      LOG.debug("Setting DesiredStackVersion of Service" + ", clusterName="
-          + cluster.getClusterName() + ", clusterId="
-          + cluster.getClusterId() + ", serviceName=" + getName()
-          + ", oldDesiredStackVersion=" + getDesiredStackVersion()
-          + ", newDesiredStackVersion=" + stack);
-    }
+  public RepositoryVersionEntity getDesiredRepositoryVersion() {
+    ServiceDesiredStateEntity serviceDesiredStateEntity = getServiceDesiredStateEntity();
+    return serviceDesiredStateEntity.getDesiredRepositoryVersion();
+  }
 
-    StackEntity stackEntity = stackDAO.find(stack.getStackName(), stack.getStackVersion());
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @Transactional
+  public void setDesiredRepositoryVersion(RepositoryVersionEntity repositoryVersionEntity) {
     ServiceDesiredStateEntity serviceDesiredStateEntity = getServiceDesiredStateEntity();
-    serviceDesiredStateEntity.setDesiredStack(stackEntity);
+    serviceDesiredStateEntity.setDesiredRepositoryVersion(repositoryVersionEntity);
     serviceDesiredStateDAO.merge(serviceDesiredStateEntity);
+
+    Collection<ServiceComponent> components = getServiceComponents().values();
+    for (ServiceComponent component : components) {
+      component.setDesiredRepositoryVersion(repositoryVersionEntity);
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public RepositoryVersionState getRepositoryState() {
+    if (components.isEmpty()) {
+      return RepositoryVersionState.NOT_REQUIRED;
+    }
+
+    List<RepositoryVersionState> states = new ArrayList<>();
+    for( ServiceComponent component : components.values() ){
+      states.add(component.getRepositoryState());
+    }
+
+    return RepositoryVersionState.getAggregateState(states);
   }
 
   @Override
   public ServiceResponse convertToResponse() {
+    RepositoryVersionEntity desiredRespositoryVersion = getDesiredRepositoryVersion();
+    StackId desiredStackId = desiredRespositoryVersion.getStackId();
+
     ServiceResponse r = new ServiceResponse(cluster.getClusterId(), cluster.getClusterName(),
-        getName(), getDesiredStackVersion().getStackId(), getDesiredState().toString(),
-        isCredentialStoreSupported(), isCredentialStoreEnabled());
+        getName(), desiredStackId, desiredRespositoryVersion.getVersion(), getRepositoryState(),
+        getDesiredState().toString(), isCredentialStoreSupported(), isCredentialStoreEnabled());
+
+    r.setDesiredRepositoryVersionId(desiredRespositoryVersion.getId());
 
     r.setMaintenanceState(getMaintenanceState().name());
     return r;
@@ -405,11 +425,8 @@ public class ServiceImpl implements Service {
   @Override
   public void setCredentialStoreEnabled(boolean credentialStoreEnabled) {
     if (LOG.isDebugEnabled()) {
-      LOG.debug("Setting CredentialStoreEnabled of Service" + ", clusterName="
-              + cluster.getClusterName() + ", clusterId="
-              + cluster.getClusterId() + ", serviceName=" + getName()
-              + ", oldCredentialStoreEnabled=" + isCredentialStoreEnabled()
-              + ", newCredentialStoreEnabled=" + credentialStoreEnabled);
+      LOG.debug("Setting CredentialStoreEnabled of Service, clusterName={}, clusterId={}, serviceName={}, oldCredentialStoreEnabled={}, newCredentialStoreEnabled={}",
+        cluster.getClusterName(), cluster.getClusterId(), getName(), isCredentialStoreEnabled(), credentialStoreEnabled);
     }
 
     ServiceDesiredStateEntity desiredStateEntity = getServiceDesiredStateEntity();
@@ -425,10 +442,12 @@ public class ServiceImpl implements Service {
 
   @Override
   public void debugDump(StringBuilder sb) {
-    sb.append("Service={ serviceName=" + getName() + ", clusterName=" + cluster.getClusterName()
-        + ", clusterId=" + cluster.getClusterId() + ", desiredStackVersion="
-        + getDesiredStackVersion() + ", desiredState=" + getDesiredState().toString()
-        + ", components=[ ");
+    sb.append("Service={ serviceName=").append(getName())
+      .append(", clusterName=").append(cluster.getClusterName())
+      .append(", clusterId=").append(cluster.getClusterId())
+      .append(", desiredStackVersion=").append(getDesiredStackId())
+      .append(", desiredState=").append(getDesiredState())
+      .append(", components=[ ");
     boolean first = true;
     for (ServiceComponent sc : components.values()) {
       if (!first) {
@@ -449,7 +468,7 @@ public class ServiceImpl implements Service {
     persistEntities(serviceEntity);
 
     // publish the service installed event
-    StackId stackId = cluster.getDesiredStackVersion();
+    StackId stackId = getDesiredStackId();
     cluster.addService(this);
 
     ServiceInstalledEvent event = new ServiceInstalledEvent(getClusterId(), stackId.getStackName(),
@@ -490,34 +509,19 @@ public class ServiceImpl implements Service {
 
   @Transactional
   void deleteAllServiceConfigs() throws AmbariException {
-    ArrayList<String> serviceConfigTypes = new ArrayList<>();
-    ArrayList<ClusterConfigEntity> clusterConfigEntitiesForDeletedServices = new ArrayList<>();
-    ServiceConfigEntity lastServiceConfigEntity = serviceConfigDAO.findMaxVersion(getClusterId(), getName());
-    //ensure service config version exist
+    long clusterId = getClusterId();
+    ServiceConfigEntity lastServiceConfigEntity = serviceConfigDAO.findMaxVersion(clusterId, getName());
+    // de-select every configuration from the service
     if (lastServiceConfigEntity != null) {
-      for (ClusterConfigEntity configEntity : lastServiceConfigEntity.getClusterConfigEntities()) {
-        serviceConfigTypes.add(configEntity.getType());
-        configEntity.setServiceDeleted(true);
-        clusterConfigEntitiesForDeletedServices.add(configEntity);
+      for (ClusterConfigEntity serviceConfigEntity : lastServiceConfigEntity.getClusterConfigEntities()) {
+        LOG.info("Disabling configuration {}", serviceConfigEntity);
+        serviceConfigEntity.setSelected(false);
+        serviceConfigEntity.setServiceDeleted(true);
+        clusterDAO.merge(serviceConfigEntity);
       }
-
-      LOG.info("Deselecting config mapping for cluster, clusterId={}, configTypes={} ",
-          getClusterId(), serviceConfigTypes);
-
-      List<ClusterConfigMappingEntity> configMappingEntities =
-          clusterDAO.getSelectedConfigMappingByTypes(getClusterId(), serviceConfigTypes);
-
-      for (ClusterConfigMappingEntity configMappingEntity : configMappingEntities) {
-        configMappingEntity.setSelected(0);
-      }
-
-      clusterDAO.mergeConfigMappings(configMappingEntities);
-      clusterDAO.mergeConfigs(clusterConfigEntitiesForDeletedServices);
     }
 
-    LOG.info("Deleting all serviceconfigs for service"
-        + ", clusterName=" + cluster.getClusterName()
-        + ", serviceName=" + getName());
+    LOG.info("Deleting all configuration associations for {} on cluster {}", getName(), cluster.getClusterName());
 
     List<ServiceConfigEntity> serviceConfigEntities =
       serviceConfigDAO.findByService(cluster.getClusterId(), getName());
@@ -589,10 +593,14 @@ public class ServiceImpl implements Service {
     deleteAllComponents();
     deleteAllServiceConfigs();
 
+    StackId stackId = getDesiredStackId();
+
     removeEntities();
 
     // publish the service removed event
-    StackId stackId = cluster.getDesiredStackVersion();
+    if (null == stackId) {
+      return;
+    }
 
     ServiceRemovedEvent event = new ServiceRemovedEvent(getClusterId(), stackId.getStackName(),
         stackId.getStackVersion(), getName());
@@ -603,12 +611,7 @@ public class ServiceImpl implements Service {
   @Transactional
   protected void removeEntities() throws AmbariException {
     serviceDesiredStateDAO.removeByPK(serviceDesiredStateEntityPK);
-
-    ClusterServiceEntityPK pk = new ClusterServiceEntityPK();
-    pk.setClusterId(getClusterId());
-    pk.setServiceName(getName());
-
-    clusterServiceDAO.removeByPK(pk);
+    clusterServiceDAO.removeByPK(serviceEntityPK);
   }
 
   @Override
@@ -627,10 +630,6 @@ public class ServiceImpl implements Service {
     return getServiceDesiredStateEntity().getMaintenanceState();
   }
 
-  private ClusterServiceEntity getServiceEntity() {
-    return clusterServiceDAO.findByPK(serviceEntityPK);
-  }
-
   private ClusterServiceEntityPK getServiceEntityPK(ClusterServiceEntity serviceEntity) {
     ClusterServiceEntityPK pk = new ClusterServiceEntityPK();
     pk.setClusterId(serviceEntity.getClusterId());