瀏覽代碼

AMBARI-5749. Store cluster installed state as part of the Cluster resource (Jonathan Hurley via ncole)

Nate Cole 11 年之前
父節點
當前提交
db65324cf7
共有 22 個文件被更改,包括 429 次插入142 次删除
  1. 70 29
      ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
  2. 34 2
      ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterRequest.java
  3. 19 1
      ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterResponse.java
  4. 17 14
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java
  5. 30 0
      ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterEntity.java
  6. 18 7
      ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterStateEntity.java
  7. 17 0
      ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
  8. 62 24
      ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
  9. 1 1
      ambari-server/src/main/java/org/apache/ambari/server/upgrade/SchemaUpgradeHelper.java
  10. 43 6
      ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog161.java
  11. 1 1
      ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
  12. 1 1
      ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
  13. 1 1
      ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
  14. 1 1
      ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
  15. 1 0
      ambari-server/src/main/resources/properties.json
  16. 10 1
      ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
  17. 7 3
      ambari-server/src/test/java/org/apache/ambari/server/controller/ClusterRequestTest.java
  18. 5 2
      ambari-server/src/test/java/org/apache/ambari/server/controller/ClusterResponseTest.java
  19. 5 4
      ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AbstractResourceProviderTest.java
  20. 44 39
      ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterResourceProviderTest.java
  21. 12 1
      ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java
  22. 30 4
      ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog161Test.java

+ 70 - 29
ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java

@@ -18,11 +18,29 @@
 
 package org.apache.ambari.server.controller;
 
-import com.google.gson.Gson;
-import com.google.inject.Inject;
-import com.google.inject.Injector;
-import com.google.inject.Singleton;
-import com.google.inject.persist.Transactional;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.AMBARI_DB_RCA_DRIVER;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.AMBARI_DB_RCA_PASSWORD;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.AMBARI_DB_RCA_URL;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.AMBARI_DB_RCA_USERNAME;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.COMMAND_TIMEOUT;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.DB_DRIVER_FILENAME;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.DB_NAME;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.HOOKS_FOLDER;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JAVA_HOME;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JCE_NAME;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JDK_LOCATION;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JDK_NAME;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.MYSQL_JDBC_URL;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.ORACLE_JDBC_URL;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.PACKAGE_LIST;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.REPO_INFO;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SCRIPT;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SCRIPT_TYPE;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SERVICE_PACKAGE_FOLDER;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SERVICE_REPO_INFO;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_NAME;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_VERSION;
+
 import java.io.File;
 import java.io.IOException;
 import java.net.InetAddress;
@@ -38,6 +56,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.TreeMap;
+
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.ClusterNotFoundException;
 import org.apache.ambari.server.DuplicateResourceException;
@@ -56,32 +75,10 @@ import org.apache.ambari.server.actionmanager.RequestFactory;
 import org.apache.ambari.server.actionmanager.Stage;
 import org.apache.ambari.server.actionmanager.StageFactory;
 import org.apache.ambari.server.agent.ExecutionCommand;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.AMBARI_DB_RCA_DRIVER;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.AMBARI_DB_RCA_PASSWORD;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.AMBARI_DB_RCA_URL;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.AMBARI_DB_RCA_USERNAME;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.COMMAND_TIMEOUT;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.DB_DRIVER_FILENAME;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.DB_NAME;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.HOOKS_FOLDER;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JAVA_HOME;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JCE_NAME;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JDK_LOCATION;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JDK_NAME;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.MYSQL_JDBC_URL;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.ORACLE_JDBC_URL;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.PACKAGE_LIST;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.REPO_INFO;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SCRIPT;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SCRIPT_TYPE;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SERVICE_PACKAGE_FOLDER;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SERVICE_REPO_INFO;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_NAME;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_VERSION;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.configuration.Configuration;
-import org.apache.ambari.server.controller.internal.RequestResourceFilter;
 import org.apache.ambari.server.controller.internal.RequestOperationLevel;
+import org.apache.ambari.server.controller.internal.RequestResourceFilter;
 import org.apache.ambari.server.controller.internal.RequestStageContainer;
 import org.apache.ambari.server.controller.internal.URLStreamProvider;
 import org.apache.ambari.server.customactions.ActionDefinition;
@@ -133,6 +130,12 @@ import org.apache.http.client.utils.URIBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.gson.Gson;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.Singleton;
+import com.google.inject.persist.Transactional;
+
 @Singleton
 public class AmbariManagementControllerImpl implements AmbariManagementController {
 
@@ -150,7 +153,6 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
 
   private final ActionManager actionManager;
 
-  @SuppressWarnings("unused")
   private final Injector injector;
 
   private final Gson gson;
@@ -1036,7 +1038,46 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
       clusters.mapHostsToCluster(
           request.getHostNames(), request.getClusterName());
     }
+    
+    // set the provisioning state of the cluster
+    if (null != request.getProvisioningState()) {
+      State provisioningState;
+      State oldProvisioningState = cluster.getProvisioningState();
+
+      provisioningState = State.valueOf(request.getProvisioningState());
+      if (provisioningState != State.INIT
+          && provisioningState != State.INSTALLED) {
+        LOG.warn(
+            "Invalid cluster provisioning state {} cannot be set on the cluster {}",
+            provisioningState, request.getClusterName());
 
+        throw new IllegalArgumentException(
+            "Invalid cluster provisioning state "
+            + provisioningState + " cannot be set on cluster "
+            + request.getClusterName());
+      }
+
+      if (provisioningState != oldProvisioningState) {
+        boolean isStateTransitionValid = State.isValidDesiredStateTransition(
+            oldProvisioningState, provisioningState);
+        
+        if (!isStateTransitionValid) {
+          LOG.warn(
+              "Invalid cluster provisioning state {} cannot be set on the cluster {} because the current state is {}",
+              provisioningState, request.getClusterName(), oldProvisioningState);
+          
+          throw new AmbariException("Invalid transition for"
+              + " cluster provisioning state" + ", clusterName="
+              + cluster.getClusterName() + ", clusterId="
+              + cluster.getClusterId() + ", currentProvisioningState="
+              + oldProvisioningState + ", newProvisioningState="
+              + provisioningState);
+        }
+      }
+      
+      cluster.setProvisioningState(provisioningState);
+    }
+    
     return null;
   }
 

+ 34 - 2
ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterRequest.java

@@ -31,17 +31,25 @@ public class ClusterRequest {
 
   private String stackVersion; // for CREATE/UPDATE
 
+  private String provisioningState; // for GET/CREATE/UPDATE
+  
   Set<String> hostNames; // CREATE/UPDATE
   
   private ConfigurationRequest config = null;
 
-  public ClusterRequest(Long clusterId, String clusterName,
+  public ClusterRequest(Long clusterId, String clusterName, 
       String stackVersion, Set<String> hostNames) {
+    this(clusterId, clusterName, null, stackVersion, hostNames);
+  }  
+  
+  public ClusterRequest(Long clusterId, String clusterName, 
+      String provisioningState, String stackVersion, Set<String> hostNames) {
     super();
     this.clusterId = clusterId;
     this.clusterName = clusterName;
+    this.provisioningState = provisioningState;
     this.stackVersion = stackVersion;
-    this.hostNames = hostNames;
+    this.hostNames = hostNames;    
   }
   
   /**
@@ -57,6 +65,29 @@ public class ClusterRequest {
   public String getClusterName() {
     return clusterName;
   }
+  
+  /**
+   * Gets whether the cluster is still initializing or has finished with its
+   * deployment requests.
+   * 
+   * @return either {@code INIT} or {@code INSTALLED} or {@code null} if not set
+   *         on the request.
+   */
+  public String getProvisioningState(){
+    return provisioningState;
+  }
+  
+  /**
+   * Sets whether the cluster is still initializing or has finished with its
+   * deployment requests.
+   * 
+   * @param provisioningState
+   *          either {@code INIT} or {@code INSTALLED}, or {@code null} if not
+   *          set on the request.
+   */
+  public void setProvisioningState(String provisioningState) {
+    this.provisioningState = provisioningState;
+  }
 
   /**
    * @return the stackVersion
@@ -116,6 +147,7 @@ public class ClusterRequest {
     sb.append("{"
         + " clusterName=" + clusterName
         + ", clusterId=" + clusterId
+        + ", provisioningState=" + provisioningState
         + ", stackVersion=" + stackVersion
         + ", hosts=[");
     if (hostNames != null) {

+ 19 - 1
ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterResponse.java

@@ -22,6 +22,7 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.ambari.server.state.DesiredConfig;
+import org.apache.ambari.server.state.State;
 
 public class ClusterResponse {
 
@@ -35,13 +36,18 @@ public class ClusterResponse {
 
   private Map<String, DesiredConfig> desiredConfigs;
   
-  public ClusterResponse(Long clusterId, String clusterName,
+  private String provisioningState;
+  
+  public ClusterResponse(Long clusterId, String clusterName, State provisioningState,
       Set<String> hostNames, String desiredStackVersion) {
     super();
     this.clusterId = clusterId;
     this.clusterName = clusterName;
     this.hostNames = hostNames;
     this.desiredStackVersion = desiredStackVersion;
+    
+    if (null != provisioningState)
+      this.provisioningState = provisioningState.name();
   }
 
   /**
@@ -64,6 +70,16 @@ public class ClusterResponse {
   public Set<String> getHostNames() {
     return hostNames;
   }
+  
+  /**
+   * Gets whether the cluster is still initializing or has finished with its
+   * deployment requests.
+   * 
+   * @return either {@code INIT} or {@code INSTALLED}, never {@code null}.
+   */
+  public String getProvisioningState(){
+    return provisioningState;
+  }
 
   @Override
   public String toString() {
@@ -71,8 +87,10 @@ public class ClusterResponse {
     sb.append("{"
         + " clusterName=" + clusterName
         + ", clusterId=" + clusterId
+        + ", provisioningState=" + provisioningState
         + ", desiredStackVersion=" + desiredStackVersion
         + ", hosts=[");
+    
     if (hostNames != null) {
       int i = 0;
       for (String hostName : hostNames) {

+ 17 - 14
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java

@@ -17,7 +17,15 @@
  */
 package org.apache.ambari.server.controller.internal;
 
-import com.google.gson.Gson;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.StackAccessException;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
@@ -55,14 +63,7 @@ import org.apache.ambari.server.state.Config;
 import org.apache.ambari.server.state.ConfigImpl;
 import org.apache.ambari.server.state.PropertyInfo;
 
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
+import com.google.gson.Gson;
 
 /**
  * Resource provider for cluster resources.
@@ -74,11 +75,11 @@ public class ClusterResourceProvider extends AbstractControllerResourceProvider
   // Clusters
   protected static final String CLUSTER_ID_PROPERTY_ID      = PropertyHelper.getPropertyId("Clusters", "cluster_id");
   protected static final String CLUSTER_NAME_PROPERTY_ID    = PropertyHelper.getPropertyId("Clusters", "cluster_name");
-  protected static final String CLUSTER_VERSION_PROPERTY_ID = PropertyHelper.getPropertyId("Clusters", "version");
+  protected static final String CLUSTER_VERSION_PROPERTY_ID = PropertyHelper.getPropertyId("Clusters", "version");  
+  protected static final String CLUSTER_PROVISIONING_STATE_PROPERTY_ID = PropertyHelper.getPropertyId("Clusters", "provisioning_state");
   protected static final String CLUSTER_DESIRED_CONFIGS_PROPERTY_ID = PropertyHelper.getPropertyId("Clusters", "desired_configs");
   protected static final String BLUEPRINT_PROPERTY_ID = PropertyHelper.getPropertyId(null, "blueprint");
 
-
   private static Set<String> pkPropertyIds =
       new HashSet<String>(Arrays.asList(new String[]{CLUSTER_ID_PROPERTY_ID}));
 
@@ -182,12 +183,14 @@ public class ClusterResourceProvider extends AbstractControllerResourceProvider
       LOG.debug("Found clusters matching getClusters request"
           + ", clusterResponseCount=" + responses.size());
     }
+    
     for (ClusterResponse response : responses) {
       Resource resource = new ResourceImpl(Resource.Type.Cluster);
       setResourceProperty(resource, CLUSTER_ID_PROPERTY_ID, response.getClusterId(), requestedIds);
       setResourceProperty(resource, CLUSTER_NAME_PROPERTY_ID, response.getClusterName(), requestedIds);
-      setResourceProperty(resource, CLUSTER_DESIRED_CONFIGS_PROPERTY_ID, response.getDesiredConfigs(), requestedIds);
-
+      setResourceProperty(resource, CLUSTER_PROVISIONING_STATE_PROPERTY_ID, response.getProvisioningState(), requestedIds);
+      setResourceProperty(resource, CLUSTER_DESIRED_CONFIGS_PROPERTY_ID, response.getDesiredConfigs(), requestedIds);      
+      
       resource.setProperty(CLUSTER_VERSION_PROPERTY_ID,
           response.getDesiredStackVersion());
 
@@ -276,10 +279,10 @@ public class ClusterResourceProvider extends AbstractControllerResourceProvider
     ClusterRequest cr = new ClusterRequest(
         (Long) properties.get(CLUSTER_ID_PROPERTY_ID),
         (String) properties.get(CLUSTER_NAME_PROPERTY_ID),
+        (String) properties.get(CLUSTER_PROVISIONING_STATE_PROPERTY_ID),
         (String) properties.get(CLUSTER_VERSION_PROPERTY_ID),
         null);
 
-
     ConfigurationRequest configRequest = getConfigurationRequest("Clusters", properties);
 
     if (null != configRequest)

+ 30 - 0
ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterEntity.java

@@ -19,6 +19,9 @@
 package org.apache.ambari.server.orm.entities;
 
 import javax.persistence.*;
+
+import org.apache.ambari.server.state.State;
+
 import java.util.Collection;
 
 import static org.apache.commons.lang.StringUtils.defaultString;
@@ -52,6 +55,11 @@ public class ClusterEntity {
       updatable = true, unique = true, length = 100)
   private String clusterName;
 
+  @Basic
+  @Enumerated(value = EnumType.STRING)
+  @Column(name = "provisioning_state", insertable = true, updatable = true)
+  private State provisioningState = State.INIT;   
+  
   @Basic
   @Column(name = "desired_cluster_state", insertable = true, updatable = true)
   private String desiredClusterState = "";
@@ -130,6 +138,28 @@ public class ClusterEntity {
   public void setDesiredStackVersion(String desiredStackVersion) {
     this.desiredStackVersion = desiredStackVersion;
   }
+  
+  /**
+   * Gets whether the cluster is still initializing or has finished with its 
+   * deployment requests.
+   * 
+   * @return either {@link State#INIT} or {@link State#INSTALLED}, 
+   * never {@code null}.
+   */
+  public State getProvisioningState(){
+    return this.provisioningState;
+  }
+  
+  /**
+   * Sets whether the cluster is still initializing or has finished with its 
+   * deployment requests.
+   * 
+   * @param provisioningState either {@link State#INIT} or 
+   * {@link State#INSTALLED}, never {@code null}. 
+   */
+  public void setProvisioningState(State provisioningState){
+    this.provisioningState = provisioningState;
+  }
 
   @Override
   public boolean equals(Object o) {

+ 18 - 7
ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterStateEntity.java

@@ -18,12 +18,22 @@
 
 package org.apache.ambari.server.orm.entities;
 
-import javax.persistence.*;
-
 import static org.apache.commons.lang.StringUtils.defaultString;
 
-@javax.persistence.Table(name = "clusterstate")
+import javax.persistence.Basic;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+
+import org.apache.ambari.server.state.State;
+
 @Entity
+@Table(name = "clusterstate")
 public class ClusterStateEntity {
 
   @Id
@@ -31,8 +41,9 @@ public class ClusterStateEntity {
   private Long clusterId;
 
   @Basic
+  @Enumerated(value = EnumType.STRING)
   @Column(name = "current_cluster_state", insertable = true, updatable = true)
-  private String currentClusterState = "";
+  private State currentClusterState = State.INIT; 
 
   @Basic
   @Column(name = "current_stack_version", insertable = true, updatable = true)
@@ -50,11 +61,11 @@ public class ClusterStateEntity {
     this.clusterId = clusterId;
   }
 
-  public String getCurrentClusterState() {
-    return defaultString(currentClusterState);
+  public State getCurrentClusterState() {
+    return currentClusterState;
   }
 
-  public void setCurrentClusterState(String currentClusterState) {
+  public void setCurrentClusterState(State currentClusterState) {
     this.currentClusterState = currentClusterState;
   }
 

+ 17 - 0
ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java

@@ -101,6 +101,23 @@ public interface Cluster {
    * @param stackVersion
    */
   public void setCurrentStackVersion(StackId stackVersion) throws AmbariException;
+  
+  /**
+   * Gets whether the cluster is still initializing or has finished with its
+   * deployment requests.
+   * 
+   * @return either {@link State#INIT} or {@link State#INSTALLED}, never
+   *         {@code null}.
+   */
+  public State getProvisioningState();
+  
+  /**
+   * Sets the provisioning state of the cluster.
+   * 
+   * @param provisioningState
+   *          the provisioning state, not {@code null}.
+   */
+  public void setProvisioningState(State provisioningState);
 
   /**
    * Gets all configs that match the specified type.  Result is not the

+ 62 - 24
ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java

@@ -18,11 +18,24 @@
 
 package org.apache.ambari.server.state.cluster;
 
-import com.google.gson.Gson;
-import com.google.inject.Inject;
-import com.google.inject.Injector;
-import com.google.inject.assistedinject.Assisted;
-import com.google.inject.persist.Transactional;
+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.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import javax.persistence.RollbackException;
+
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.ServiceComponentHostNotFoundException;
 import org.apache.ambari.server.ServiceNotFoundException;
@@ -39,7 +52,6 @@ import org.apache.ambari.server.orm.entities.ClusterEntity;
 import org.apache.ambari.server.orm.entities.ClusterServiceEntity;
 import org.apache.ambari.server.orm.entities.ClusterStateEntity;
 import org.apache.ambari.server.orm.entities.ConfigGroupEntity;
-import org.apache.ambari.server.orm.entities.ConfigGroupHostMappingEntity;
 import org.apache.ambari.server.orm.entities.RequestScheduleEntity;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
@@ -51,6 +63,7 @@ import org.apache.ambari.server.state.ServiceComponent;
 import org.apache.ambari.server.state.ServiceComponentHost;
 import org.apache.ambari.server.state.ServiceFactory;
 import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.state.State;
 import org.apache.ambari.server.state.configgroup.ConfigGroup;
 import org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
 import org.apache.ambari.server.state.scheduler.RequestExecution;
@@ -58,22 +71,11 @@ import org.apache.ambari.server.state.scheduler.RequestExecutionFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.persistence.RollbackException;
-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.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
+import com.google.gson.Gson;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.assistedinject.Assisted;
+import com.google.inject.persist.Transactional;
 
 public class ClusterImpl implements Cluster {
 
@@ -913,8 +915,43 @@ public class ClusterImpl implements Cluster {
     } finally {
       clusterGlobalLock.readLock().unlock();
     }
+  }
+  
+  @Override
+  public State getProvisioningState() {    
+    clusterGlobalLock.readLock().lock();
+    try {
+      readLock.lock();
+      State provisioningState = null;
+      try {
+        provisioningState = clusterEntity.getProvisioningState();
+        
+        if( null == provisioningState )
+          provisioningState = State.INIT;
+        
+        return provisioningState;
+      } finally {
+        readLock.unlock();
+      }
+    } finally {
+      clusterGlobalLock.readLock().unlock();
+    }
+  }  
 
-
+  @Override
+  public void setProvisioningState(State provisioningState) {
+    clusterGlobalLock.readLock().lock();
+    try {
+      writeLock.lock();
+      try {
+        clusterEntity.setProvisioningState(provisioningState);
+        clusterDAO.merge(clusterEntity);        
+      } finally {
+        writeLock.unlock();
+      }
+    } finally {
+      clusterGlobalLock.readLock().unlock();
+    }
   }
 
   @Override
@@ -1047,7 +1084,8 @@ public class ClusterImpl implements Cluster {
     try {
       readWriteLock.readLock().lock();
       try {
-        ClusterResponse r = new ClusterResponse(getClusterId(), getClusterName(),
+        ClusterResponse r = new ClusterResponse(getClusterId(), 
+          getClusterName(), getProvisioningState(), 
           clusters.getHostsForCluster(getClusterName()).keySet(),
           getDesiredStackVersion().getStackId());
 

+ 1 - 1
ambari-server/src/main/java/org/apache/ambari/server/upgrade/SchemaUpgradeHelper.java

@@ -184,7 +184,7 @@ public class SchemaUpgradeHelper {
   }
 
   public void executeDMLUpdates(List<UpgradeCatalog> upgradeCatalogs) throws AmbariException {
-    LOG.info("Execution DML changes.");
+    LOG.info("Executing DML changes.");
 
     if (upgradeCatalogs != null && !upgradeCatalogs.isEmpty()) {
       for (UpgradeCatalog upgradeCatalog : upgradeCatalogs) {

+ 43 - 6
ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog161.java

@@ -18,22 +18,35 @@
 
 package org.apache.ambari.server.upgrade;
 
-import com.google.inject.Inject;
-import com.google.inject.Injector;
-import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.configuration.Configuration;
-
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.List;
 
-import static org.apache.ambari.server.orm.DBAccessor.DBColumnInfo;
+import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.orm.DBAccessor.DBColumnInfo;
+import org.apache.ambari.server.orm.entities.ClusterEntity;
+import org.apache.ambari.server.state.State;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Inject;
+import com.google.inject.Injector;
 
 /**
  * Upgrade catalog for version 1.6.1.
  */
 public class UpgradeCatalog161 extends AbstractUpgradeCatalog {
 
+  /**
+   * Logger.
+   */
+  private static final Logger LOG = LoggerFactory.getLogger
+      (UpgradeCatalog161.class);
+  
   // ----- Constructors ------------------------------------------------------
 
   @Inject
@@ -64,6 +77,9 @@ public class UpgradeCatalog161 extends AbstractUpgradeCatalog {
     // Add constraints
     dbAccessor.addFKConstraint("requestoperationlevel", "FK_req_op_level_req_id",
             "request_id", "request", "request_id", true);
+    
+    // Clusters
+    dbAccessor.addColumn("clusters", new DBColumnInfo("provisioning_state", String.class, 255, State.INIT.name(), false));    
   }
 
 
@@ -77,9 +93,30 @@ public class UpgradeCatalog161 extends AbstractUpgradeCatalog {
     if (Configuration.ORACLE_DB_NAME.equals(dbType) || Configuration.MYSQL_DB_NAME.equals(dbType)) {
       valueColumnName = "value";
     }
+    
     //add new sequences for operation level
     dbAccessor.executeQuery("INSERT INTO ambari_sequences(sequence_name, " + valueColumnName + ") " +
             "VALUES('operation_level_id_seq', 1)", true);
+    
+    // upgrade cluster provision state
+    executeInTransaction(new Runnable() { 
+      @Override
+      public void run() {
+        // it should be safe to bulk update the current cluster state since 
+        // this field is not currently used and since all clusters stored in
+        // the database must (at this point) be installed
+        final EntityManager em = getEntityManagerProvider().get();        
+        final TypedQuery<ClusterEntity> query = em.createQuery(
+            "UPDATE ClusterEntity SET provisioningState = :provisioningState", 
+            ClusterEntity.class);
+
+        query.setParameter("provisioningState", State.INSTALLED);
+        final int updatedClusterProvisionedStateCount = query.executeUpdate();
+        
+        LOG.info("Updated {} cluster provisioning states to {}",
+            updatedClusterProvisionedStateCount, State.INSTALLED);
+      }
+    });
   }
 
   @Override

+ 1 - 1
ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql

@@ -26,7 +26,7 @@ delimiter ;
 
 # USE @schema;
 
-CREATE TABLE clusters (cluster_id BIGINT NOT NULL, cluster_info VARCHAR(255) NOT NULL, cluster_name VARCHAR(100) NOT NULL UNIQUE, desired_cluster_state VARCHAR(255) NOT NULL, desired_stack_version VARCHAR(255) NOT NULL, PRIMARY KEY (cluster_id));
+CREATE TABLE clusters (cluster_id BIGINT NOT NULL, cluster_info VARCHAR(255) NOT NULL, cluster_name VARCHAR(100) NOT NULL UNIQUE, provisioning_state VARCHAR(255) NOT NULL DEFAULT 'INIT', desired_cluster_state VARCHAR(255) NOT NULL, desired_stack_version VARCHAR(255) NOT NULL, PRIMARY KEY (cluster_id));
 CREATE TABLE clusterconfig (version_tag VARCHAR(255) NOT NULL, type_name VARCHAR(255) NOT NULL, cluster_id BIGINT NOT NULL, config_data LONGTEXT NOT NULL, create_timestamp BIGINT NOT NULL, PRIMARY KEY (version_tag, type_name, cluster_id));
 CREATE TABLE clusterservices (service_name VARCHAR(255) NOT NULL, cluster_id BIGINT NOT NULL, service_enabled INTEGER NOT NULL, PRIMARY KEY (service_name, cluster_id));
 CREATE TABLE clusterstate (cluster_id BIGINT NOT NULL, current_cluster_state VARCHAR(255) NOT NULL, current_stack_version VARCHAR(255) NOT NULL, PRIMARY KEY (cluster_id));

+ 1 - 1
ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql

@@ -16,7 +16,7 @@
 -- limitations under the License.
 --
 
-CREATE TABLE clusters (cluster_id NUMBER(19) NOT NULL, cluster_info VARCHAR2(255) NULL, cluster_name VARCHAR2(100) NOT NULL UNIQUE, desired_cluster_state VARCHAR2(255) NULL, desired_stack_version VARCHAR2(255) NULL, PRIMARY KEY (cluster_id));
+CREATE TABLE clusters (cluster_id NUMBER(19) NOT NULL, cluster_info VARCHAR2(255) NULL, cluster_name VARCHAR2(100) NOT NULL UNIQUE, provisioning_state VARCHAR2(255) NOT NULL DEFAULT 'INIT', desired_cluster_state VARCHAR2(255) NULL, desired_stack_version VARCHAR2(255) NULL, PRIMARY KEY (cluster_id));
 CREATE TABLE clusterconfig (version_tag VARCHAR2(255) NOT NULL, type_name VARCHAR2(255) NOT NULL, cluster_id NUMBER(19) NOT NULL, config_data CLOB NOT NULL, create_timestamp NUMBER(19) NOT NULL, PRIMARY KEY (version_tag, type_name, cluster_id));
 CREATE TABLE clusterservices (service_name VARCHAR2(255) NOT NULL, cluster_id NUMBER(19) NOT NULL, service_enabled NUMBER(10) NOT NULL, PRIMARY KEY (service_name, cluster_id));
 CREATE TABLE clusterstate (cluster_id NUMBER(19) NOT NULL, current_cluster_state VARCHAR2(255) NULL, current_stack_version VARCHAR2(255) NULL, PRIMARY KEY (cluster_id));

+ 1 - 1
ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql

@@ -17,7 +17,7 @@
 --
 
 ------create tables ang grant privileges to db user---------
-CREATE TABLE clusters (cluster_id BIGINT NOT NULL, cluster_info VARCHAR(255) NOT NULL, cluster_name VARCHAR(100) NOT NULL UNIQUE, desired_cluster_state VARCHAR(255) NOT NULL, desired_stack_version VARCHAR(255) NOT NULL, PRIMARY KEY (cluster_id));
+CREATE TABLE clusters (cluster_id BIGINT NOT NULL, cluster_info VARCHAR(255) NOT NULL, cluster_name VARCHAR(100) NOT NULL UNIQUE, provisioning_state VARCHAR(255) NOT NULL DEFAULT 'INIT', desired_cluster_state VARCHAR(255) NOT NULL, desired_stack_version VARCHAR(255) NOT NULL, PRIMARY KEY (cluster_id));
 
 CREATE TABLE clusterconfig (version_tag VARCHAR(255) NOT NULL, type_name VARCHAR(255) NOT NULL, cluster_id BIGINT NOT NULL, config_data VARCHAR(32000) NOT NULL, create_timestamp BIGINT NOT NULL, PRIMARY KEY (cluster_id, type_name, version_tag));
 

+ 1 - 1
ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql

@@ -28,7 +28,7 @@ ALTER SCHEMA ambari OWNER TO :username;
 ALTER ROLE :username SET search_path TO 'ambari';
 
 ------create tables ang grant privileges to db user---------
-CREATE TABLE ambari.clusters (cluster_id BIGINT NOT NULL, cluster_info VARCHAR(255) NOT NULL, cluster_name VARCHAR(100) NOT NULL UNIQUE, desired_cluster_state VARCHAR(255) NOT NULL, desired_stack_version VARCHAR(255) NOT NULL, PRIMARY KEY (cluster_id));
+CREATE TABLE ambari.clusters (cluster_id BIGINT NOT NULL, cluster_info VARCHAR(255) NOT NULL, cluster_name VARCHAR(100) NOT NULL UNIQUE, provisioning_state VARCHAR(255) NOT NULL DEFAULT 'INIT', desired_cluster_state VARCHAR(255) NOT NULL, desired_stack_version VARCHAR(255) NOT NULL, PRIMARY KEY (cluster_id));
 GRANT ALL PRIVILEGES ON TABLE ambari.clusters TO :username;
 
 CREATE TABLE ambari.clusterconfig (version_tag VARCHAR(255) NOT NULL, type_name VARCHAR(255) NOT NULL, cluster_id BIGINT NOT NULL, config_data VARCHAR(32000) NOT NULL, create_timestamp BIGINT NOT NULL, PRIMARY KEY (cluster_id, type_name, version_tag));

+ 1 - 0
ambari-server/src/main/resources/properties.json

@@ -2,6 +2,7 @@
     "Cluster":[
         "Clusters/cluster_id",
         "Clusters/cluster_name",
+        "Clusters/provisioning_state",
         "Clusters/version",
         "Clusters/state",
         "Clusters/desired_configs",

+ 10 - 1
ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java

@@ -227,7 +227,7 @@ public class AmbariManagementControllerTest {
   }
 
   private void createCluster(String clusterName) throws AmbariException {
-    ClusterRequest r = new ClusterRequest(null, clusterName, "HDP-0.1", null);
+    ClusterRequest r = new ClusterRequest(null, clusterName, State.INSTALLED.name(), "HDP-0.1", null);
     controller.createCluster(r);
   }
 
@@ -509,6 +509,15 @@ public class AmbariManagementControllerTest {
     } catch (Exception e) {
       // Expected
     }
+    
+    r.setStackVersion("HDP-1.0.1");
+    r.setProvisioningState(State.INSTALLING.name());
+    try {
+      controller.createCluster(r);
+     fail("Expected create cluster for invalid request - invalid provisioning state");
+    } catch (Exception e) {
+      // Expected
+    }    
   }
 
   @Test

+ 7 - 3
ambari-server/src/test/java/org/apache/ambari/server/controller/ClusterRequestTest.java

@@ -22,6 +22,7 @@ import java.util.HashSet;
 import java.util.Set;
 
 import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.state.State;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -31,16 +32,18 @@ public class ClusterRequestTest {
   public void testBasicGetAndSet() {
     Long clusterId = new Long(10);
     String clusterName = "foo";
+    String provisioningState = State.INIT.name();
     StackId stackVersion = new StackId("HDP-1.0.1");
     Set<String> hostNames = new HashSet<String>();
     hostNames.add("h1");
 
     ClusterRequest r1 =
-        new ClusterRequest(clusterId, clusterName,
+        new ClusterRequest(clusterId, clusterName, provisioningState,
             stackVersion.getStackId(), hostNames);
 
     Assert.assertEquals(clusterId, r1.getClusterId());
     Assert.assertEquals(clusterName, r1.getClusterName());
+    Assert.assertEquals(provisioningState, r1.getProvisioningState());
     Assert.assertEquals(stackVersion.getStackId(),
         r1.getStackVersion());
     Assert.assertArrayEquals(hostNames.toArray(), r1.getHostNames().toArray());
@@ -49,19 +52,20 @@ public class ClusterRequestTest {
     r1.setHostNames(hostNames);
     r1.setClusterName("foo1");
     r1.setStackVersion("HDP-1.0.2");
+    r1.setProvisioningState(State.INSTALLED.name());
 
     hostNames.add("h2");
 
     Assert.assertEquals(clusterId, r1.getClusterId());
     Assert.assertEquals("foo1", r1.getClusterName());
+    Assert.assertEquals(State.INSTALLED.name(), r1.getProvisioningState());
     Assert.assertEquals("HDP-1.0.2", r1.getStackVersion());
     Assert.assertArrayEquals(hostNames.toArray(), r1.getHostNames().toArray());
-
   }
 
   @Test
   public void testToString() {
-    ClusterRequest r1 = new ClusterRequest(null, null, null, null);
+    ClusterRequest r1 = new ClusterRequest(null, null, null, null, null);
     r1.toString();
   }
 

+ 5 - 2
ambari-server/src/test/java/org/apache/ambari/server/controller/ClusterResponseTest.java

@@ -21,6 +21,7 @@ package org.apache.ambari.server.controller;
 import java.util.HashSet;
 import java.util.Set;
 
+import org.apache.ambari.server.state.State;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -30,21 +31,23 @@ public class ClusterResponseTest {
   public void testBasicGetAndSet() {
     Long clusterId = new Long(10);
     String clusterName = "foo";
+    State provisioningState = State.INSTALLED;
     Set<String> hostNames = new HashSet<String>();
     hostNames.add("h1");
 
     ClusterResponse r1 =
-        new ClusterResponse(clusterId, clusterName, hostNames, "bar");
+        new ClusterResponse(clusterId, clusterName, provisioningState, hostNames, "bar");
     
     Assert.assertEquals(clusterId, r1.getClusterId());
     Assert.assertEquals(clusterName, r1.getClusterName());
+    Assert.assertEquals(provisioningState.name(), r1.getProvisioningState());
     Assert.assertArrayEquals(hostNames.toArray(), r1.getHostNames().toArray());
     Assert.assertEquals("bar", r1.getDesiredStackVersion());
   }
 
   @Test
   public void testToString() {
-    ClusterResponse r = new ClusterResponse(null, null, null, null);
+    ClusterResponse r = new ClusterResponse(null, null, null, null, null);
     r.toString();
   }
 }

+ 5 - 4
ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AbstractResourceProviderTest.java

@@ -47,6 +47,7 @@ import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
 import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 import org.apache.ambari.server.controller.utilities.PredicateBuilder;
+import org.apache.ambari.server.state.State;
 import org.easymock.EasyMock;
 import org.easymock.IArgumentMatcher;
 import org.junit.Assert;
@@ -256,9 +257,9 @@ public class AbstractResourceProviderTest {
     }
 
     public static Set<ClusterRequest> getClusterRequestSet(
-        Long clusterId, String clusterName, String stackVersion, Set<String> hostNames)
+        Long clusterId, String clusterName, String provisioningState, String stackVersion, Set<String> hostNames)
     {
-      EasyMock.reportMatcher(new ClusterRequestSetMatcher(clusterId, clusterName, stackVersion, hostNames));
+      EasyMock.reportMatcher(new ClusterRequestSetMatcher(clusterId, clusterName, provisioningState, stackVersion, hostNames));
       return null;
     }
 
@@ -334,8 +335,8 @@ public class AbstractResourceProviderTest {
    */
   public static class ClusterRequestSetMatcher extends ClusterRequest implements IArgumentMatcher {
 
-    public ClusterRequestSetMatcher(Long clusterId, String clusterName, String stackVersion, Set<String> hostNames) {
-      super(clusterId, clusterName, stackVersion, hostNames);
+    public ClusterRequestSetMatcher(Long clusterId, String clusterName, String provisioningState, String stackVersion, Set<String> hostNames) {
+      super(clusterId, clusterName, provisioningState, stackVersion, hostNames);
     }
 
     @Override

+ 44 - 39
ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterResourceProviderTest.java

@@ -18,7 +18,32 @@
 
 package org.apache.ambari.server.controller.internal;
 
-import com.google.gson.Gson;
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.createMockBuilder;
+import static org.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.createStrictMock;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.api.services.PersistKeyValueImpl;
 import org.apache.ambari.server.api.services.PersistKeyValueService;
@@ -34,6 +59,8 @@ import org.apache.ambari.server.controller.StackServiceComponentRequest;
 import org.apache.ambari.server.controller.StackServiceComponentResponse;
 import org.apache.ambari.server.controller.StackServiceRequest;
 import org.apache.ambari.server.controller.StackServiceResponse;
+import org.apache.ambari.server.controller.internal.ClusterResourceProvider.HostGroup;
+import org.apache.ambari.server.controller.internal.ClusterResourceProvider.PropertyUpdater;
 import org.apache.ambari.server.controller.spi.Predicate;
 import org.apache.ambari.server.controller.spi.Request;
 import org.apache.ambari.server.controller.spi.RequestStatus;
@@ -47,38 +74,15 @@ import org.apache.ambari.server.orm.entities.BlueprintEntity;
 import org.apache.ambari.server.orm.entities.HostGroupComponentEntity;
 import org.apache.ambari.server.orm.entities.HostGroupConfigEntity;
 import org.apache.ambari.server.orm.entities.HostGroupEntity;
-import org.apache.commons.collections.CollectionUtils;
 import org.apache.ambari.server.state.PropertyInfo;
+import org.apache.ambari.server.state.State;
+import org.apache.commons.collections.CollectionUtils;
 import org.easymock.Capture;
 import org.easymock.EasyMock;
 import org.junit.Assert;
 import org.junit.Test;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
-import static org.easymock.EasyMock.capture;
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.createMockBuilder;
-import static org.easymock.EasyMock.createNiceMock;
-import static org.easymock.EasyMock.createStrictMock;
-import static org.easymock.EasyMock.eq;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.verify;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import org.apache.ambari.server.controller.internal.ClusterResourceProvider.HostGroup;
-import org.apache.ambari.server.controller.internal.ClusterResourceProvider.PropertyUpdater;
+
+import com.google.gson.Gson;
 
 /**
  * ClusterResourceProvider tests.
@@ -1880,17 +1884,17 @@ public class ClusterResourceProviderTest {
     AmbariManagementController managementController = createMock(AmbariManagementController.class);
 
     Set<ClusterResponse> allResponse = new HashSet<ClusterResponse>();
-    allResponse.add(new ClusterResponse(100L, "Cluster100", null, null));
-    allResponse.add(new ClusterResponse(101L, "Cluster101", null, null));
-    allResponse.add(new ClusterResponse(102L, "Cluster102", null, null));
-    allResponse.add(new ClusterResponse(103L, "Cluster103", null, null));
-    allResponse.add(new ClusterResponse(104L, "Cluster104", null, null));
+    allResponse.add(new ClusterResponse(100L, "Cluster100", State.INSTALLED, null, null));
+    allResponse.add(new ClusterResponse(101L, "Cluster101", State.INSTALLED, null, null));
+    allResponse.add(new ClusterResponse(102L, "Cluster102", State.INSTALLED, null, null));
+    allResponse.add(new ClusterResponse(103L, "Cluster103", State.INSTALLED, null, null));
+    allResponse.add(new ClusterResponse(104L, "Cluster104", State.INSTALLED, null, null));
 
     Set<ClusterResponse> nameResponse = new HashSet<ClusterResponse>();
-    nameResponse.add(new ClusterResponse(102L, "Cluster102", null, null));
+    nameResponse.add(new ClusterResponse(102L, "Cluster102", State.INSTALLED, null, null));
 
     Set<ClusterResponse> idResponse = new HashSet<ClusterResponse>();
-    idResponse.add(new ClusterResponse(103L, "Cluster103", null, null));
+    idResponse.add(new ClusterResponse(103L, "Cluster103", State.INSTALLED, null, null));
 
     // set expectations
     expect(managementController.getClusters(EasyMock.<Set<ClusterRequest>>anyObject())).andReturn(allResponse).once();
@@ -1959,7 +1963,7 @@ public class ClusterResourceProviderTest {
     RequestStatusResponse response = createNiceMock(RequestStatusResponse.class);
 
     Set<ClusterResponse> nameResponse = new HashSet<ClusterResponse>();
-    nameResponse.add(new ClusterResponse(102L, "Cluster102", null, null));
+    nameResponse.add(new ClusterResponse(102L, "Cluster102", State.INIT, null, null));
 
     Map<String, String> mapRequestProps = new HashMap<String, String>();
     mapRequestProps.put("context", "Called from a test");
@@ -1967,10 +1971,11 @@ public class ClusterResourceProviderTest {
     // set expectations
     expect(managementController.getClusters(EasyMock.<Set<ClusterRequest>>anyObject())).andReturn(nameResponse).once();
     expect(managementController.updateClusters(
-        AbstractResourceProviderTest.Matcher.getClusterRequestSet(102L, "Cluster102", "HDP-0.1", null), eq(mapRequestProps))).
+        AbstractResourceProviderTest.Matcher.getClusterRequestSet(102L, "Cluster102", State.INSTALLED.name(), "HDP-0.1", null), eq(mapRequestProps))).
         andReturn(response).once();
+    
     expect(managementController.updateClusters(
-        AbstractResourceProviderTest.Matcher.getClusterRequestSet(103L, null, "HDP-0.1", null), eq(mapRequestProps))).
+        AbstractResourceProviderTest.Matcher.getClusterRequestSet(103L, null, null, "HDP-0.1", null), eq(mapRequestProps))).
         andReturn(response).once();
 
     // replay
@@ -2020,7 +2025,7 @@ public class ClusterResourceProviderTest {
     RequestStatusResponse response = createNiceMock(RequestStatusResponse.class);
 
     Set<ClusterResponse> nameResponse = new HashSet<ClusterResponse>();
-    nameResponse.add(new ClusterResponse(100L, "Cluster100", null, null));
+    nameResponse.add(new ClusterResponse(100L, "Cluster100", State.INSTALLED, null, null));
 
     Map<String, String> mapRequestProps = new HashMap<String, String>();
     mapRequestProps.put("context", "Called from a test");

+ 12 - 1
ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java

@@ -510,6 +510,17 @@ public class ClusterTest {
 
     assertTrue(configs.containsKey("h1"));
     assertEquals(1, configs.get("h1").size());
-
   }
+  
+  @Test
+  public void testProvisioningState() throws AmbariException {
+    c1.setProvisioningState(State.INIT);
+    Assert.assertEquals(State.INIT,
+        c1.getProvisioningState());
+    
+    c1.setProvisioningState(State.INSTALLED);
+    Assert.assertEquals(State.INSTALLED,
+        c1.getProvisioningState());    
+  }
+
 }

+ 30 - 4
ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog161Test.java

@@ -22,8 +22,10 @@ import com.google.inject.Binder;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Module;
+
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.orm.DBAccessor;
+import org.apache.ambari.server.state.State;
 import org.easymock.Capture;
 import org.junit.Assert;
 import org.junit.Test;
@@ -31,6 +33,7 @@ import org.junit.Test;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.sql.SQLException;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
@@ -43,6 +46,7 @@ import static org.easymock.EasyMock.createMockBuilder;
 import static org.easymock.EasyMock.createNiceMock;
 import static org.easymock.EasyMock.eq;
 import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.verify;
 
@@ -56,10 +60,12 @@ public class UpgradeCatalog161Test {
 
     final DBAccessor dbAccessor = createNiceMock(DBAccessor.class);
     Configuration configuration = createNiceMock(Configuration.class);
-    Capture<List<DBAccessor.DBColumnInfo>> operationLevelEntitycolumnCapture = new Capture<List<DBAccessor.DBColumnInfo>>();
-
     expect(configuration.getDatabaseUrl()).andReturn(Configuration.JDBC_IN_MEMORY_URL).anyTimes();
 
+    Capture<DBAccessor.DBColumnInfo> provisioningStateColumnCapture = new Capture<DBAccessor.DBColumnInfo>();
+    Capture<List<DBAccessor.DBColumnInfo>> operationLevelEntitycolumnCapture = new Capture<List<DBAccessor.DBColumnInfo>>();
+    
+    setClustersConfigExpectations(dbAccessor, provisioningStateColumnCapture);    
     setOperationLevelEntityConfigExpectations(dbAccessor, operationLevelEntitycolumnCapture);
 
     replay(dbAccessor, configuration);
@@ -72,6 +78,7 @@ public class UpgradeCatalog161Test {
     upgradeCatalog.executeDDLUpdates();
     verify(dbAccessor, configuration);
 
+    assertClusterColumns(provisioningStateColumnCapture);
     assertOperationLevelEntityColumns(operationLevelEntitycolumnCapture);
   }
 
@@ -84,11 +91,15 @@ public class UpgradeCatalog161Test {
     Method m = AbstractUpgradeCatalog.class.getDeclaredMethod
       ("updateConfigurationProperties", String.class, Map.class, boolean.class);
 
-    UpgradeCatalog161 upgradeCatalog = createMockBuilder(UpgradeCatalog161.class)
+    UpgradeCatalog160 upgradeCatalog = createMockBuilder(UpgradeCatalog160.class)
       .addMockedMethod(m).createMock();
 
     expect(configuration.getDatabaseUrl()).andReturn(Configuration.JDBC_IN_MEMORY_URL).anyTimes();
 
+    upgradeCatalog.updateConfigurationProperties("global",
+      Collections.singletonMap("jobhistory_heapsize", "900"), false);
+    expectLastCall();
+
     replay(upgradeCatalog, dbAccessor, configuration);
 
     Class<?> c = AbstractUpgradeCatalog.class;
@@ -190,7 +201,22 @@ public class UpgradeCatalog161Test {
     assertEquals(String.class, column.getType());
     assertNull(column.getDefaultValue());
     assertTrue(column.isNullable());
-
   }
 
+  private void setClustersConfigExpectations(DBAccessor dbAccessor,
+      Capture<DBAccessor.DBColumnInfo> provisioningStateColumnCapture) throws SQLException {
+
+      dbAccessor.addColumn(eq("clusters"),
+        capture(provisioningStateColumnCapture));
+    }
+  
+  private void assertClusterColumns(
+      Capture<DBAccessor.DBColumnInfo> provisiontStateColumnCapture) {
+      DBAccessor.DBColumnInfo column = provisiontStateColumnCapture.getValue();
+      assertEquals("provisioning_state", column.getName());
+      assertEquals(255, (int) column.getLength());
+      assertEquals(String.class, column.getType());
+      assertEquals(State.INIT.name(), column.getDefaultValue());
+      assertFalse(column.isNullable());
+    }  
 }