Bläddra i källkod

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

Nate Cole 11 år sedan
förälder
incheckning
db65324cf7
22 ändrade filer med 429 tillägg och 142 borttagningar
  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;
 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.File;
 import java.io.IOException;
 import java.io.IOException;
 import java.net.InetAddress;
 import java.net.InetAddress;
@@ -38,6 +56,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.TreeMap;
+
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.ClusterNotFoundException;
 import org.apache.ambari.server.ClusterNotFoundException;
 import org.apache.ambari.server.DuplicateResourceException;
 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.Stage;
 import org.apache.ambari.server.actionmanager.StageFactory;
 import org.apache.ambari.server.actionmanager.StageFactory;
 import org.apache.ambari.server.agent.ExecutionCommand;
 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.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.configuration.Configuration;
 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.RequestOperationLevel;
+import org.apache.ambari.server.controller.internal.RequestResourceFilter;
 import org.apache.ambari.server.controller.internal.RequestStageContainer;
 import org.apache.ambari.server.controller.internal.RequestStageContainer;
 import org.apache.ambari.server.controller.internal.URLStreamProvider;
 import org.apache.ambari.server.controller.internal.URLStreamProvider;
 import org.apache.ambari.server.customactions.ActionDefinition;
 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.Logger;
 import org.slf4j.LoggerFactory;
 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
 @Singleton
 public class AmbariManagementControllerImpl implements AmbariManagementController {
 public class AmbariManagementControllerImpl implements AmbariManagementController {
 
 
@@ -150,7 +153,6 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
 
 
   private final ActionManager actionManager;
   private final ActionManager actionManager;
 
 
-  @SuppressWarnings("unused")
   private final Injector injector;
   private final Injector injector;
 
 
   private final Gson gson;
   private final Gson gson;
@@ -1036,7 +1038,46 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
       clusters.mapHostsToCluster(
       clusters.mapHostsToCluster(
           request.getHostNames(), request.getClusterName());
           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;
     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 stackVersion; // for CREATE/UPDATE
 
 
+  private String provisioningState; // for GET/CREATE/UPDATE
+  
   Set<String> hostNames; // CREATE/UPDATE
   Set<String> hostNames; // CREATE/UPDATE
   
   
   private ConfigurationRequest config = null;
   private ConfigurationRequest config = null;
 
 
-  public ClusterRequest(Long clusterId, String clusterName,
+  public ClusterRequest(Long clusterId, String clusterName, 
       String stackVersion, Set<String> hostNames) {
       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();
     super();
     this.clusterId = clusterId;
     this.clusterId = clusterId;
     this.clusterName = clusterName;
     this.clusterName = clusterName;
+    this.provisioningState = provisioningState;
     this.stackVersion = stackVersion;
     this.stackVersion = stackVersion;
-    this.hostNames = hostNames;
+    this.hostNames = hostNames;    
   }
   }
   
   
   /**
   /**
@@ -57,6 +65,29 @@ public class ClusterRequest {
   public String getClusterName() {
   public String getClusterName() {
     return clusterName;
     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
    * @return the stackVersion
@@ -116,6 +147,7 @@ public class ClusterRequest {
     sb.append("{"
     sb.append("{"
         + " clusterName=" + clusterName
         + " clusterName=" + clusterName
         + ", clusterId=" + clusterId
         + ", clusterId=" + clusterId
+        + ", provisioningState=" + provisioningState
         + ", stackVersion=" + stackVersion
         + ", stackVersion=" + stackVersion
         + ", hosts=[");
         + ", hosts=[");
     if (hostNames != null) {
     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 java.util.Set;
 
 
 import org.apache.ambari.server.state.DesiredConfig;
 import org.apache.ambari.server.state.DesiredConfig;
+import org.apache.ambari.server.state.State;
 
 
 public class ClusterResponse {
 public class ClusterResponse {
 
 
@@ -35,13 +36,18 @@ public class ClusterResponse {
 
 
   private Map<String, DesiredConfig> desiredConfigs;
   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) {
       Set<String> hostNames, String desiredStackVersion) {
     super();
     super();
     this.clusterId = clusterId;
     this.clusterId = clusterId;
     this.clusterName = clusterName;
     this.clusterName = clusterName;
     this.hostNames = hostNames;
     this.hostNames = hostNames;
     this.desiredStackVersion = desiredStackVersion;
     this.desiredStackVersion = desiredStackVersion;
+    
+    if (null != provisioningState)
+      this.provisioningState = provisioningState.name();
   }
   }
 
 
   /**
   /**
@@ -64,6 +70,16 @@ public class ClusterResponse {
   public Set<String> getHostNames() {
   public Set<String> getHostNames() {
     return hostNames;
     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
   @Override
   public String toString() {
   public String toString() {
@@ -71,8 +87,10 @@ public class ClusterResponse {
     sb.append("{"
     sb.append("{"
         + " clusterName=" + clusterName
         + " clusterName=" + clusterName
         + ", clusterId=" + clusterId
         + ", clusterId=" + clusterId
+        + ", provisioningState=" + provisioningState
         + ", desiredStackVersion=" + desiredStackVersion
         + ", desiredStackVersion=" + desiredStackVersion
         + ", hosts=[");
         + ", hosts=[");
+    
     if (hostNames != null) {
     if (hostNames != null) {
       int i = 0;
       int i = 0;
       for (String hostName : hostNames) {
       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;
 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.AmbariException;
 import org.apache.ambari.server.StackAccessException;
 import org.apache.ambari.server.StackAccessException;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 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.ConfigImpl;
 import org.apache.ambari.server.state.PropertyInfo;
 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.
  * Resource provider for cluster resources.
@@ -74,11 +75,11 @@ public class ClusterResourceProvider extends AbstractControllerResourceProvider
   // Clusters
   // Clusters
   protected static final String CLUSTER_ID_PROPERTY_ID      = PropertyHelper.getPropertyId("Clusters", "cluster_id");
   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_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 CLUSTER_DESIRED_CONFIGS_PROPERTY_ID = PropertyHelper.getPropertyId("Clusters", "desired_configs");
   protected static final String BLUEPRINT_PROPERTY_ID = PropertyHelper.getPropertyId(null, "blueprint");
   protected static final String BLUEPRINT_PROPERTY_ID = PropertyHelper.getPropertyId(null, "blueprint");
 
 
-
   private static Set<String> pkPropertyIds =
   private static Set<String> pkPropertyIds =
       new HashSet<String>(Arrays.asList(new String[]{CLUSTER_ID_PROPERTY_ID}));
       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"
       LOG.debug("Found clusters matching getClusters request"
           + ", clusterResponseCount=" + responses.size());
           + ", clusterResponseCount=" + responses.size());
     }
     }
+    
     for (ClusterResponse response : responses) {
     for (ClusterResponse response : responses) {
       Resource resource = new ResourceImpl(Resource.Type.Cluster);
       Resource resource = new ResourceImpl(Resource.Type.Cluster);
       setResourceProperty(resource, CLUSTER_ID_PROPERTY_ID, response.getClusterId(), requestedIds);
       setResourceProperty(resource, CLUSTER_ID_PROPERTY_ID, response.getClusterId(), requestedIds);
       setResourceProperty(resource, CLUSTER_NAME_PROPERTY_ID, response.getClusterName(), 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,
       resource.setProperty(CLUSTER_VERSION_PROPERTY_ID,
           response.getDesiredStackVersion());
           response.getDesiredStackVersion());
 
 
@@ -276,10 +279,10 @@ public class ClusterResourceProvider extends AbstractControllerResourceProvider
     ClusterRequest cr = new ClusterRequest(
     ClusterRequest cr = new ClusterRequest(
         (Long) properties.get(CLUSTER_ID_PROPERTY_ID),
         (Long) properties.get(CLUSTER_ID_PROPERTY_ID),
         (String) properties.get(CLUSTER_NAME_PROPERTY_ID),
         (String) properties.get(CLUSTER_NAME_PROPERTY_ID),
+        (String) properties.get(CLUSTER_PROVISIONING_STATE_PROPERTY_ID),
         (String) properties.get(CLUSTER_VERSION_PROPERTY_ID),
         (String) properties.get(CLUSTER_VERSION_PROPERTY_ID),
         null);
         null);
 
 
-
     ConfigurationRequest configRequest = getConfigurationRequest("Clusters", properties);
     ConfigurationRequest configRequest = getConfigurationRequest("Clusters", properties);
 
 
     if (null != configRequest)
     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;
 package org.apache.ambari.server.orm.entities;
 
 
 import javax.persistence.*;
 import javax.persistence.*;
+
+import org.apache.ambari.server.state.State;
+
 import java.util.Collection;
 import java.util.Collection;
 
 
 import static org.apache.commons.lang.StringUtils.defaultString;
 import static org.apache.commons.lang.StringUtils.defaultString;
@@ -52,6 +55,11 @@ public class ClusterEntity {
       updatable = true, unique = true, length = 100)
       updatable = true, unique = true, length = 100)
   private String clusterName;
   private String clusterName;
 
 
+  @Basic
+  @Enumerated(value = EnumType.STRING)
+  @Column(name = "provisioning_state", insertable = true, updatable = true)
+  private State provisioningState = State.INIT;   
+  
   @Basic
   @Basic
   @Column(name = "desired_cluster_state", insertable = true, updatable = true)
   @Column(name = "desired_cluster_state", insertable = true, updatable = true)
   private String desiredClusterState = "";
   private String desiredClusterState = "";
@@ -130,6 +138,28 @@ public class ClusterEntity {
   public void setDesiredStackVersion(String desiredStackVersion) {
   public void setDesiredStackVersion(String desiredStackVersion) {
     this.desiredStackVersion = 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
   @Override
   public boolean equals(Object o) {
   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;
 package org.apache.ambari.server.orm.entities;
 
 
-import javax.persistence.*;
-
 import static org.apache.commons.lang.StringUtils.defaultString;
 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
 @Entity
+@Table(name = "clusterstate")
 public class ClusterStateEntity {
 public class ClusterStateEntity {
 
 
   @Id
   @Id
@@ -31,8 +41,9 @@ public class ClusterStateEntity {
   private Long clusterId;
   private Long clusterId;
 
 
   @Basic
   @Basic
+  @Enumerated(value = EnumType.STRING)
   @Column(name = "current_cluster_state", insertable = true, updatable = true)
   @Column(name = "current_cluster_state", insertable = true, updatable = true)
-  private String currentClusterState = "";
+  private State currentClusterState = State.INIT; 
 
 
   @Basic
   @Basic
   @Column(name = "current_stack_version", insertable = true, updatable = true)
   @Column(name = "current_stack_version", insertable = true, updatable = true)
@@ -50,11 +61,11 @@ public class ClusterStateEntity {
     this.clusterId = clusterId;
     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;
     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
    * @param stackVersion
    */
    */
   public void setCurrentStackVersion(StackId stackVersion) throws AmbariException;
   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
    * 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;
 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.AmbariException;
 import org.apache.ambari.server.ServiceComponentHostNotFoundException;
 import org.apache.ambari.server.ServiceComponentHostNotFoundException;
 import org.apache.ambari.server.ServiceNotFoundException;
 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.ClusterServiceEntity;
 import org.apache.ambari.server.orm.entities.ClusterStateEntity;
 import org.apache.ambari.server.orm.entities.ClusterStateEntity;
 import org.apache.ambari.server.orm.entities.ConfigGroupEntity;
 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.orm.entities.RequestScheduleEntity;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.Clusters;
@@ -51,6 +63,7 @@ import org.apache.ambari.server.state.ServiceComponent;
 import org.apache.ambari.server.state.ServiceComponentHost;
 import org.apache.ambari.server.state.ServiceComponentHost;
 import org.apache.ambari.server.state.ServiceFactory;
 import org.apache.ambari.server.state.ServiceFactory;
 import org.apache.ambari.server.state.StackId;
 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.ConfigGroup;
 import org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
 import org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
 import org.apache.ambari.server.state.scheduler.RequestExecution;
 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.Logger;
 import org.slf4j.LoggerFactory;
 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 {
 public class ClusterImpl implements Cluster {
 
 
@@ -913,8 +915,43 @@ public class ClusterImpl implements Cluster {
     } finally {
     } finally {
       clusterGlobalLock.readLock().unlock();
       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
   @Override
@@ -1047,7 +1084,8 @@ public class ClusterImpl implements Cluster {
     try {
     try {
       readWriteLock.readLock().lock();
       readWriteLock.readLock().lock();
       try {
       try {
-        ClusterResponse r = new ClusterResponse(getClusterId(), getClusterName(),
+        ClusterResponse r = new ClusterResponse(getClusterId(), 
+          getClusterName(), getProvisioningState(), 
           clusters.getHostsForCluster(getClusterName()).keySet(),
           clusters.getHostsForCluster(getClusterName()).keySet(),
           getDesiredStackVersion().getStackId());
           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 {
   public void executeDMLUpdates(List<UpgradeCatalog> upgradeCatalogs) throws AmbariException {
-    LOG.info("Execution DML changes.");
+    LOG.info("Executing DML changes.");
 
 
     if (upgradeCatalogs != null && !upgradeCatalogs.isEmpty()) {
     if (upgradeCatalogs != null && !upgradeCatalogs.isEmpty()) {
       for (UpgradeCatalog upgradeCatalog : upgradeCatalogs) {
       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;
 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.sql.SQLException;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.List;
 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.
  * Upgrade catalog for version 1.6.1.
  */
  */
 public class UpgradeCatalog161 extends AbstractUpgradeCatalog {
 public class UpgradeCatalog161 extends AbstractUpgradeCatalog {
 
 
+  /**
+   * Logger.
+   */
+  private static final Logger LOG = LoggerFactory.getLogger
+      (UpgradeCatalog161.class);
+  
   // ----- Constructors ------------------------------------------------------
   // ----- Constructors ------------------------------------------------------
 
 
   @Inject
   @Inject
@@ -64,6 +77,9 @@ public class UpgradeCatalog161 extends AbstractUpgradeCatalog {
     // Add constraints
     // Add constraints
     dbAccessor.addFKConstraint("requestoperationlevel", "FK_req_op_level_req_id",
     dbAccessor.addFKConstraint("requestoperationlevel", "FK_req_op_level_req_id",
             "request_id", "request", "request_id", true);
             "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)) {
     if (Configuration.ORACLE_DB_NAME.equals(dbType) || Configuration.MYSQL_DB_NAME.equals(dbType)) {
       valueColumnName = "value";
       valueColumnName = "value";
     }
     }
+    
     //add new sequences for operation level
     //add new sequences for operation level
     dbAccessor.executeQuery("INSERT INTO ambari_sequences(sequence_name, " + valueColumnName + ") " +
     dbAccessor.executeQuery("INSERT INTO ambari_sequences(sequence_name, " + valueColumnName + ") " +
             "VALUES('operation_level_id_seq', 1)", true);
             "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
   @Override

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

@@ -26,7 +26,7 @@ delimiter ;
 
 
 # USE @schema;
 # 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 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 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));
 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.
 -- 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 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 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));
 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 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));
 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';
 ALTER ROLE :username SET search_path TO 'ambari';
 
 
 ------create tables ang grant privileges to db user---------
 ------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;
 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));
 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":[
     "Cluster":[
         "Clusters/cluster_id",
         "Clusters/cluster_id",
         "Clusters/cluster_name",
         "Clusters/cluster_name",
+        "Clusters/provisioning_state",
         "Clusters/version",
         "Clusters/version",
         "Clusters/state",
         "Clusters/state",
         "Clusters/desired_configs",
         "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 {
   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);
     controller.createCluster(r);
   }
   }
 
 
@@ -509,6 +509,15 @@ public class AmbariManagementControllerTest {
     } catch (Exception e) {
     } catch (Exception e) {
       // Expected
       // 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
   @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 java.util.Set;
 
 
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.state.State;
 import org.junit.Assert;
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.Test;
 
 
@@ -31,16 +32,18 @@ public class ClusterRequestTest {
   public void testBasicGetAndSet() {
   public void testBasicGetAndSet() {
     Long clusterId = new Long(10);
     Long clusterId = new Long(10);
     String clusterName = "foo";
     String clusterName = "foo";
+    String provisioningState = State.INIT.name();
     StackId stackVersion = new StackId("HDP-1.0.1");
     StackId stackVersion = new StackId("HDP-1.0.1");
     Set<String> hostNames = new HashSet<String>();
     Set<String> hostNames = new HashSet<String>();
     hostNames.add("h1");
     hostNames.add("h1");
 
 
     ClusterRequest r1 =
     ClusterRequest r1 =
-        new ClusterRequest(clusterId, clusterName,
+        new ClusterRequest(clusterId, clusterName, provisioningState,
             stackVersion.getStackId(), hostNames);
             stackVersion.getStackId(), hostNames);
 
 
     Assert.assertEquals(clusterId, r1.getClusterId());
     Assert.assertEquals(clusterId, r1.getClusterId());
     Assert.assertEquals(clusterName, r1.getClusterName());
     Assert.assertEquals(clusterName, r1.getClusterName());
+    Assert.assertEquals(provisioningState, r1.getProvisioningState());
     Assert.assertEquals(stackVersion.getStackId(),
     Assert.assertEquals(stackVersion.getStackId(),
         r1.getStackVersion());
         r1.getStackVersion());
     Assert.assertArrayEquals(hostNames.toArray(), r1.getHostNames().toArray());
     Assert.assertArrayEquals(hostNames.toArray(), r1.getHostNames().toArray());
@@ -49,19 +52,20 @@ public class ClusterRequestTest {
     r1.setHostNames(hostNames);
     r1.setHostNames(hostNames);
     r1.setClusterName("foo1");
     r1.setClusterName("foo1");
     r1.setStackVersion("HDP-1.0.2");
     r1.setStackVersion("HDP-1.0.2");
+    r1.setProvisioningState(State.INSTALLED.name());
 
 
     hostNames.add("h2");
     hostNames.add("h2");
 
 
     Assert.assertEquals(clusterId, r1.getClusterId());
     Assert.assertEquals(clusterId, r1.getClusterId());
     Assert.assertEquals("foo1", r1.getClusterName());
     Assert.assertEquals("foo1", r1.getClusterName());
+    Assert.assertEquals(State.INSTALLED.name(), r1.getProvisioningState());
     Assert.assertEquals("HDP-1.0.2", r1.getStackVersion());
     Assert.assertEquals("HDP-1.0.2", r1.getStackVersion());
     Assert.assertArrayEquals(hostNames.toArray(), r1.getHostNames().toArray());
     Assert.assertArrayEquals(hostNames.toArray(), r1.getHostNames().toArray());
-
   }
   }
 
 
   @Test
   @Test
   public void testToString() {
   public void testToString() {
-    ClusterRequest r1 = new ClusterRequest(null, null, null, null);
+    ClusterRequest r1 = new ClusterRequest(null, null, null, null, null);
     r1.toString();
     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.HashSet;
 import java.util.Set;
 import java.util.Set;
 
 
+import org.apache.ambari.server.state.State;
 import org.junit.Assert;
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.Test;
 
 
@@ -30,21 +31,23 @@ public class ClusterResponseTest {
   public void testBasicGetAndSet() {
   public void testBasicGetAndSet() {
     Long clusterId = new Long(10);
     Long clusterId = new Long(10);
     String clusterName = "foo";
     String clusterName = "foo";
+    State provisioningState = State.INSTALLED;
     Set<String> hostNames = new HashSet<String>();
     Set<String> hostNames = new HashSet<String>();
     hostNames.add("h1");
     hostNames.add("h1");
 
 
     ClusterResponse r1 =
     ClusterResponse r1 =
-        new ClusterResponse(clusterId, clusterName, hostNames, "bar");
+        new ClusterResponse(clusterId, clusterName, provisioningState, hostNames, "bar");
     
     
     Assert.assertEquals(clusterId, r1.getClusterId());
     Assert.assertEquals(clusterId, r1.getClusterId());
     Assert.assertEquals(clusterName, r1.getClusterName());
     Assert.assertEquals(clusterName, r1.getClusterName());
+    Assert.assertEquals(provisioningState.name(), r1.getProvisioningState());
     Assert.assertArrayEquals(hostNames.toArray(), r1.getHostNames().toArray());
     Assert.assertArrayEquals(hostNames.toArray(), r1.getHostNames().toArray());
     Assert.assertEquals("bar", r1.getDesiredStackVersion());
     Assert.assertEquals("bar", r1.getDesiredStackVersion());
   }
   }
 
 
   @Test
   @Test
   public void testToString() {
   public void testToString() {
-    ClusterResponse r = new ClusterResponse(null, null, null, null);
+    ClusterResponse r = new ClusterResponse(null, null, null, null, null);
     r.toString();
     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.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 import org.apache.ambari.server.controller.utilities.PredicateBuilder;
 import org.apache.ambari.server.controller.utilities.PredicateBuilder;
+import org.apache.ambari.server.state.State;
 import org.easymock.EasyMock;
 import org.easymock.EasyMock;
 import org.easymock.IArgumentMatcher;
 import org.easymock.IArgumentMatcher;
 import org.junit.Assert;
 import org.junit.Assert;
@@ -256,9 +257,9 @@ public class AbstractResourceProviderTest {
     }
     }
 
 
     public static Set<ClusterRequest> getClusterRequestSet(
     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;
       return null;
     }
     }
 
 
@@ -334,8 +335,8 @@ public class AbstractResourceProviderTest {
    */
    */
   public static class ClusterRequestSetMatcher extends ClusterRequest implements IArgumentMatcher {
   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
     @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;
 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.AmbariMetaInfo;
 import org.apache.ambari.server.api.services.PersistKeyValueImpl;
 import org.apache.ambari.server.api.services.PersistKeyValueImpl;
 import org.apache.ambari.server.api.services.PersistKeyValueService;
 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.StackServiceComponentResponse;
 import org.apache.ambari.server.controller.StackServiceRequest;
 import org.apache.ambari.server.controller.StackServiceRequest;
 import org.apache.ambari.server.controller.StackServiceResponse;
 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.Predicate;
 import org.apache.ambari.server.controller.spi.Request;
 import org.apache.ambari.server.controller.spi.Request;
 import org.apache.ambari.server.controller.spi.RequestStatus;
 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.HostGroupComponentEntity;
 import org.apache.ambari.server.orm.entities.HostGroupConfigEntity;
 import org.apache.ambari.server.orm.entities.HostGroupConfigEntity;
 import org.apache.ambari.server.orm.entities.HostGroupEntity;
 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.PropertyInfo;
+import org.apache.ambari.server.state.State;
+import org.apache.commons.collections.CollectionUtils;
 import org.easymock.Capture;
 import org.easymock.Capture;
 import org.easymock.EasyMock;
 import org.easymock.EasyMock;
 import org.junit.Assert;
 import org.junit.Assert;
 import org.junit.Test;
 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.
  * ClusterResourceProvider tests.
@@ -1880,17 +1884,17 @@ public class ClusterResourceProviderTest {
     AmbariManagementController managementController = createMock(AmbariManagementController.class);
     AmbariManagementController managementController = createMock(AmbariManagementController.class);
 
 
     Set<ClusterResponse> allResponse = new HashSet<ClusterResponse>();
     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>();
     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>();
     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
     // set expectations
     expect(managementController.getClusters(EasyMock.<Set<ClusterRequest>>anyObject())).andReturn(allResponse).once();
     expect(managementController.getClusters(EasyMock.<Set<ClusterRequest>>anyObject())).andReturn(allResponse).once();
@@ -1959,7 +1963,7 @@ public class ClusterResourceProviderTest {
     RequestStatusResponse response = createNiceMock(RequestStatusResponse.class);
     RequestStatusResponse response = createNiceMock(RequestStatusResponse.class);
 
 
     Set<ClusterResponse> nameResponse = new HashSet<ClusterResponse>();
     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>();
     Map<String, String> mapRequestProps = new HashMap<String, String>();
     mapRequestProps.put("context", "Called from a test");
     mapRequestProps.put("context", "Called from a test");
@@ -1967,10 +1971,11 @@ public class ClusterResourceProviderTest {
     // set expectations
     // set expectations
     expect(managementController.getClusters(EasyMock.<Set<ClusterRequest>>anyObject())).andReturn(nameResponse).once();
     expect(managementController.getClusters(EasyMock.<Set<ClusterRequest>>anyObject())).andReturn(nameResponse).once();
     expect(managementController.updateClusters(
     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();
         andReturn(response).once();
+    
     expect(managementController.updateClusters(
     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();
         andReturn(response).once();
 
 
     // replay
     // replay
@@ -2020,7 +2025,7 @@ public class ClusterResourceProviderTest {
     RequestStatusResponse response = createNiceMock(RequestStatusResponse.class);
     RequestStatusResponse response = createNiceMock(RequestStatusResponse.class);
 
 
     Set<ClusterResponse> nameResponse = new HashSet<ClusterResponse>();
     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>();
     Map<String, String> mapRequestProps = new HashMap<String, String>();
     mapRequestProps.put("context", "Called from a test");
     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"));
     assertTrue(configs.containsKey("h1"));
     assertEquals(1, configs.get("h1").size());
     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.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Injector;
 import com.google.inject.Module;
 import com.google.inject.Module;
+
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.orm.DBAccessor;
 import org.apache.ambari.server.orm.DBAccessor;
+import org.apache.ambari.server.state.State;
 import org.easymock.Capture;
 import org.easymock.Capture;
 import org.junit.Assert;
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.Test;
@@ -31,6 +33,7 @@ import org.junit.Test;
 import java.lang.reflect.Field;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.Method;
 import java.sql.SQLException;
 import java.sql.SQLException;
+import java.util.Collections;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 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.createNiceMock;
 import static org.easymock.EasyMock.eq;
 import static org.easymock.EasyMock.eq;
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.verify;
 import static org.easymock.EasyMock.verify;
 
 
@@ -56,10 +60,12 @@ public class UpgradeCatalog161Test {
 
 
     final DBAccessor dbAccessor = createNiceMock(DBAccessor.class);
     final DBAccessor dbAccessor = createNiceMock(DBAccessor.class);
     Configuration configuration = createNiceMock(Configuration.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();
     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);
     setOperationLevelEntityConfigExpectations(dbAccessor, operationLevelEntitycolumnCapture);
 
 
     replay(dbAccessor, configuration);
     replay(dbAccessor, configuration);
@@ -72,6 +78,7 @@ public class UpgradeCatalog161Test {
     upgradeCatalog.executeDDLUpdates();
     upgradeCatalog.executeDDLUpdates();
     verify(dbAccessor, configuration);
     verify(dbAccessor, configuration);
 
 
+    assertClusterColumns(provisioningStateColumnCapture);
     assertOperationLevelEntityColumns(operationLevelEntitycolumnCapture);
     assertOperationLevelEntityColumns(operationLevelEntitycolumnCapture);
   }
   }
 
 
@@ -84,11 +91,15 @@ public class UpgradeCatalog161Test {
     Method m = AbstractUpgradeCatalog.class.getDeclaredMethod
     Method m = AbstractUpgradeCatalog.class.getDeclaredMethod
       ("updateConfigurationProperties", String.class, Map.class, boolean.class);
       ("updateConfigurationProperties", String.class, Map.class, boolean.class);
 
 
-    UpgradeCatalog161 upgradeCatalog = createMockBuilder(UpgradeCatalog161.class)
+    UpgradeCatalog160 upgradeCatalog = createMockBuilder(UpgradeCatalog160.class)
       .addMockedMethod(m).createMock();
       .addMockedMethod(m).createMock();
 
 
     expect(configuration.getDatabaseUrl()).andReturn(Configuration.JDBC_IN_MEMORY_URL).anyTimes();
     expect(configuration.getDatabaseUrl()).andReturn(Configuration.JDBC_IN_MEMORY_URL).anyTimes();
 
 
+    upgradeCatalog.updateConfigurationProperties("global",
+      Collections.singletonMap("jobhistory_heapsize", "900"), false);
+    expectLastCall();
+
     replay(upgradeCatalog, dbAccessor, configuration);
     replay(upgradeCatalog, dbAccessor, configuration);
 
 
     Class<?> c = AbstractUpgradeCatalog.class;
     Class<?> c = AbstractUpgradeCatalog.class;
@@ -190,7 +201,22 @@ public class UpgradeCatalog161Test {
     assertEquals(String.class, column.getType());
     assertEquals(String.class, column.getType());
     assertNull(column.getDefaultValue());
     assertNull(column.getDefaultValue());
     assertTrue(column.isNullable());
     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());
+    }  
 }
 }