Explorar el Código

AMBARI-1642. Add ability for maintainence mode in Host Role Component in Ambari.

git-svn-id: https://svn.apache.org/repos/asf/incubator/ambari/trunk@1456687 13f79535-47bb-0310-9956-ffa450edef68
Mahadev Konar hace 12 años
padre
commit
ad21db4022

+ 3 - 0
CHANGES.txt

@@ -488,6 +488,9 @@ Trunk (unreleased changes):
  AMBARI-1489. Add hadoop-lzo to be one of the rpms to check for before
  installation. (mahadev)
 
+ AMBARI-1642. Add ability for maintainence mode in Host Role Component in
+ Ambari. (mahadev)
+
  BUG FIXES
 
  AMBARI-1640. Erroneos property is not highlighted while landing on step7

+ 1 - 0
ambari-agent/src/main/puppet/modules/hdp-hue/manifests/params.pp

@@ -115,6 +115,7 @@ class hdp-hue::params() inherits hdp::params {
     $hue_hadoop_jt_host = hdp_default("jtnode_host")
     $webhcat_server_host = hdp_default("webhcat_server_host")
     $hue_templeton_url = "http://${webhcat_server_host}:50111/templeton/v1"
+    $hue_hive_home_dir = "/usr/lib/hive"
     $hue_hadoop_yarn_host = ""
     $hue_hadoop_yarn_port = ""
 

+ 232 - 121
ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java

@@ -30,19 +30,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;
-import org.apache.ambari.server.HostNotFoundException;
-import org.apache.ambari.server.ObjectNotFoundException;
-import org.apache.ambari.server.ParentObjectNotFoundException;
-import org.apache.ambari.server.Role;
-import org.apache.ambari.server.RoleCommand;
-import org.apache.ambari.server.ServiceComponentHostNotFoundException;
-import org.apache.ambari.server.ServiceComponentNotFoundException;
-import org.apache.ambari.server.ServiceNotFoundException;
-import org.apache.ambari.server.StackAccessException;
+import org.apache.ambari.server.*;
 import org.apache.ambari.server.actionmanager.ActionManager;
 import org.apache.ambari.server.actionmanager.HostRoleCommand;
 import org.apache.ambari.server.actionmanager.RequestStatus;
@@ -57,32 +45,9 @@ import org.apache.ambari.server.security.authorization.User;
 import org.apache.ambari.server.security.authorization.Users;
 import org.apache.ambari.server.serveraction.ServerAction;
 import org.apache.ambari.server.stageplanner.RoleGraph;
-import org.apache.ambari.server.state.Cluster;
-import org.apache.ambari.server.state.Clusters;
-import org.apache.ambari.server.state.ComponentInfo;
-import org.apache.ambari.server.state.Config;
-import org.apache.ambari.server.state.ConfigFactory;
-import org.apache.ambari.server.state.DesiredConfig;
-import org.apache.ambari.server.state.Host;
-import org.apache.ambari.server.state.OperatingSystemInfo;
-import org.apache.ambari.server.state.PropertyInfo;
-import org.apache.ambari.server.state.RepositoryInfo;
-import org.apache.ambari.server.state.Service;
-import org.apache.ambari.server.state.ServiceComponent;
-import org.apache.ambari.server.state.ServiceComponentFactory;
-import org.apache.ambari.server.state.ServiceComponentHost;
-import org.apache.ambari.server.state.ServiceComponentHostEvent;
-import org.apache.ambari.server.state.ServiceComponentHostFactory;
-import org.apache.ambari.server.state.ServiceFactory;
-import org.apache.ambari.server.state.ServiceInfo;
-import org.apache.ambari.server.state.StackId;
-import org.apache.ambari.server.state.StackInfo;
-import org.apache.ambari.server.state.State;
-import org.apache.ambari.server.state.svccomphost.ServiceComponentHostInstallEvent;
-import org.apache.ambari.server.state.svccomphost.ServiceComponentHostOpInProgressEvent;
-import org.apache.ambari.server.state.svccomphost.ServiceComponentHostStartEvent;
-import org.apache.ambari.server.state.svccomphost.ServiceComponentHostStopEvent;
-import org.apache.ambari.server.state.svccomphost.ServiceComponentHostUpgradeEvent;
+import org.apache.ambari.server.state.*;
+import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
+import org.apache.ambari.server.state.svccomphost.*;
 import org.apache.ambari.server.utils.StageUtils;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
@@ -648,16 +613,7 @@ public class AmbariManagementControllerImpl implements
         new HashMap<String, Map<String, Map<String, Set<String>>>>();
     Set<String> duplicates = new HashSet<String>();
     for (ServiceComponentHostRequest request : requests) {
-      if (request.getClusterName() == null
-          || request.getClusterName().isEmpty()
-          || request.getComponentName() == null
-          || request.getComponentName().isEmpty()
-          || request.getHostname() == null
-          || request.getHostname().isEmpty()) {
-        throw new IllegalArgumentException("Invalid arguments,"
-            + " clustername, componentname and hostname should not be null"
-            + " when trying to create a hostcomponent");
-      }
+      validateServiceComponentHostRequest(request);
 
       Cluster cluster;
       try {
@@ -667,25 +623,8 @@ public class AmbariManagementControllerImpl implements
             "Attempted to add a host_component to a cluster which doesn't exist: ", e);
       }
 
-      if (request.getServiceName() == null
-          || request.getServiceName().isEmpty()) {
-        StackId stackId = cluster.getDesiredStackVersion();
-        String serviceName =
-            ambariMetaInfo.getComponentToService(stackId.getStackName(),
-                stackId.getStackVersion(), request.getComponentName());
-        if (LOG.isDebugEnabled()) {
-          LOG.debug("Looking up service name for component"
-              + ", componentName=" + request.getComponentName()
-              + ", serviceName=" + serviceName);
-        }
-        if (serviceName == null
-            || serviceName.isEmpty()) {
-          throw new AmbariException("Could not find service for component"
-              + ", componentName=" + request.getComponentName()
-              + ", clusterName=" + cluster.getClusterName()
-              + ", stackInfo=" + stackId.getStackId());
-        }
-        request.setServiceName(serviceName);
+      if (StringUtils.isEmpty(request.getServiceName())) {
+        request.setServiceName(findServiceName(cluster, request.getComponentName()));
       }
 
       if (LOG.isDebugEnabled()) {
@@ -1439,7 +1378,6 @@ public class AmbariManagementControllerImpl implements
     // Set the current version value if its not already set
     if (currentVersion == null) {
       cluster.setCurrentStackVersion(desiredVersion);
-      cluster.refresh();
       currentVersion = cluster.getCurrentStackVersion();
     }
 
@@ -2115,7 +2053,8 @@ public class AmbariManagementControllerImpl implements
             || oldState == State.STOP_FAILED
             || oldState == State.UPGRADE_FAILED
             || oldState == State.UPGRADING
-            || oldState == State.STOPPING) {
+            || oldState == State.STOPPING
+            || oldState == State.MAINTENANCE) {
           return true;
         }
         break;
@@ -2139,6 +2078,10 @@ public class AmbariManagementControllerImpl implements
             || oldState == State.WIPEOUT_FAILED) {
           return true;
         }
+      case MAINTENANCE:
+        if (oldState == State.INSTALLED) {
+          return true;
+        }
     }
     return false;
   }
@@ -2366,6 +2309,19 @@ public class AmbariManagementControllerImpl implements
         }
         for (ServiceComponentHost sch : sc.getServiceComponentHosts().values()){
           State oldSchState = sch.getState();
+          if (oldSchState == State.MAINTENANCE) {
+            //Ignore host components updates in this state
+            if (LOG.isDebugEnabled()) {
+              LOG.debug("Ignoring ServiceComponentHost"
+                  + ", clusterName=" + request.getClusterName()
+                  + ", serviceName=" + s.getName()
+                  + ", componentName=" + sc.getName()
+                  + ", hostname=" + sch.getHostName()
+                  + ", currentState=" + oldSchState
+                  + ", newDesiredState=" + newState);
+            }
+            continue;
+          }
           if (newState == oldSchState) {
             sch.setDesiredState(newState);
             if (LOG.isDebugEnabled()) {
@@ -2652,6 +2608,18 @@ public class AmbariManagementControllerImpl implements
 
       for (ServiceComponentHost sch : sc.getServiceComponentHosts().values()) {
         State oldSchState = sch.getState();
+        if (oldSchState == State.MAINTENANCE) {
+          if (LOG.isDebugEnabled()) {
+            LOG.debug("Ignoring ServiceComponentHost"
+                + ", clusterName=" + request.getClusterName()
+                + ", serviceName=" + s.getName()
+                + ", componentName=" + sc.getName()
+                + ", hostname=" + sch.getHostName()
+                + ", currentState=" + oldSchState
+                + ", newDesiredState=" + newState);
+          }
+          continue;
+        }
         if (newState == oldSchState) {
           sch.setDesiredState(newState);
           if (LOG.isDebugEnabled()) {
@@ -2835,41 +2803,18 @@ public class AmbariManagementControllerImpl implements
     Map<String, Map<String, Map<String, Set<String>>>> hostComponentNames =
         new HashMap<String, Map<String, Map<String, Set<String>>>>();
     Set<State> seenNewStates = new HashSet<State>();
-
+    boolean processingUpgradeRequest = false;
+    int numberOfRequestsProcessed = 0;
+    StackId fromStackVersion = new StackId();
+    Map<ServiceComponentHost, State> directTransitionScHosts = new HashMap<ServiceComponentHost, State>();
     for (ServiceComponentHostRequest request : requests) {
-      if (request.getClusterName() == null
-          || request.getClusterName().isEmpty()
-          || request.getComponentName() == null
-          || request.getComponentName().isEmpty()
-          || request.getHostname() == null
-          || request.getHostname().isEmpty()) {
-        throw new IllegalArgumentException("Invalid arguments"
-            + ", cluster name, component name and host name should be"
-            + " provided to update host components");
-      }
+      numberOfRequestsProcessed++;
+      validateServiceComponentHostRequest(request);
 
       Cluster cluster = clusters.getCluster(request.getClusterName());
 
-      if (request.getServiceName() == null
-          || request.getServiceName().isEmpty()) {
-        StackId stackId = cluster.getDesiredStackVersion();
-        String serviceName =
-            ambariMetaInfo.getComponentToService(stackId.getStackName(),
-                stackId.getStackVersion(), request.getComponentName());
-        if (LOG.isDebugEnabled()) {
-          LOG.debug("Looking up service name for component"
-              + ", componentName=" + request.getComponentName()
-              + ", serviceName=" + serviceName);
-        }
-
-        if (serviceName == null
-            || serviceName.isEmpty()) {
-          throw new AmbariException("Could not find service for component"
-              + ", componentName=" + request.getComponentName()
-              + ", clusterName=" + cluster.getClusterName()
-              + ", stackInfo=" + stackId.getStackId());
-        }
-        request.setServiceName(serviceName);
+      if (StringUtils.isEmpty(request.getServiceName())) {
+        request.setServiceName(findServiceName(cluster, request.getComponentName()));
       }
 
       if (LOG.isDebugEnabled()) {
@@ -3017,24 +2962,52 @@ public class AmbariManagementControllerImpl implements
             + ", currentState=" + oldSchState
             + ", newDesiredState=" + newState);
       }
-      if (!changedScHosts.containsKey(sc.getName())) {
-        changedScHosts.put(sc.getName(),
-            new HashMap<State, List<ServiceComponentHost>>());
-      }
-      if (!changedScHosts.get(sc.getName()).containsKey(newState)) {
-        changedScHosts.get(sc.getName()).put(newState,
-            new ArrayList<ServiceComponentHost>());
-      }
-      if (LOG.isDebugEnabled()) {
-        LOG.debug("Handling update to ServiceComponentHost"
-            + ", clusterName=" + request.getClusterName()
-            + ", serviceName=" + s.getName()
-            + ", componentName=" + sc.getName()
-            + ", hostname=" + sch.getHostName()
-            + ", currentState=" + oldSchState
-            + ", newDesiredState=" + newState);
+
+      if (isDirectTransition(oldSchState, newState)) {
+
+//        if (newState == State.DELETED) {
+//          if (!sch.canBeRemoved()) {
+//            throw new AmbariException("Servicecomponenthost cannot be removed"
+//                + ", clusterName=" + cluster.getClusterName()
+//                + ", clusterId=" + cluster.getClusterId()
+//                + ", serviceName=" + sch.getServiceName()
+//                + ", componentName=" + sch.getServiceComponentName()
+//                + ", hostname=" + sch.getHostName()
+//                + ", currentState=" + oldSchState
+//                + ", newDesiredState=" + newState);
+//          }
+//        }
+
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("Handling direct transition update to ServiceComponentHost"
+              + ", clusterName=" + request.getClusterName()
+              + ", serviceName=" + s.getName()
+              + ", componentName=" + sc.getName()
+              + ", hostname=" + sch.getHostName()
+              + ", currentState=" + oldSchState
+              + ", newDesiredState=" + newState);
+        }
+        directTransitionScHosts.put(sch, newState);
+      } else {
+        if (!changedScHosts.containsKey(sc.getName())) {
+          changedScHosts.put(sc.getName(),
+              new HashMap<State, List<ServiceComponentHost>>());
+        }
+        if (!changedScHosts.get(sc.getName()).containsKey(newState)) {
+          changedScHosts.get(sc.getName()).put(newState,
+              new ArrayList<ServiceComponentHost>());
+        }
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("Handling update to ServiceComponentHost"
+              + ", clusterName=" + request.getClusterName()
+              + ", serviceName=" + s.getName()
+              + ", componentName=" + sc.getName()
+              + ", hostname=" + sch.getHostName()
+              + ", currentState=" + oldSchState
+              + ", newDesiredState=" + newState);
+        }
+        changedScHosts.get(sc.getName()).get(newState).add(sch);
       }
-      changedScHosts.get(sc.getName()).get(newState).add(sch);
     }
 
     if (seenNewStates.size() > 1) {
@@ -3061,12 +3034,42 @@ public class AmbariManagementControllerImpl implements
 
           if (!updated.isEmpty()) {
             sch.updateDesiredConfigs(updated);
-            sch.persist();
           }
         }
       }
     }
 
+    // Perform direct transitions (without task generation)
+    for (Entry<ServiceComponentHost, State> entry : directTransitionScHosts.entrySet()) {
+      ServiceComponentHost componentHost = entry.getKey();
+      State newState = entry.getValue();
+      long timestamp = System.currentTimeMillis();
+      ServiceComponentHostEvent event;
+      componentHost.setDesiredState(newState);
+      switch (newState) {
+        case MAINTENANCE:
+          event = new ServiceComponentHostMaintenanceEvent(
+              componentHost.getServiceComponentName(),
+              componentHost.getHostName(),
+              timestamp);
+          break;
+        case INSTALLED:
+          event = new ServiceComponentHostRestoreEvent(
+              componentHost.getServiceComponentName(),
+              componentHost.getHostName(),
+              timestamp);
+          break;
+        default:
+          throw new AmbariException("Direct transition from " + componentHost.getState() + " to " + newState + " not supported");
+      }
+      try {
+        componentHost.handleEvent(event);
+      } catch (InvalidStateTransitionException e) {
+        //Should not occur, must be covered by previous checks
+        throw new AmbariException("Internal error - not supported transition", e);
+      }
+    }
+
     Cluster cluster = clusters.getCluster(clusterNames.iterator().next());
 
     Map<String, String> requestParameters = null;
@@ -3085,6 +3088,56 @@ public class AmbariManagementControllerImpl implements
     return getRequestStatusResponse(stages.get(0).getRequestId());
   }
 
+  private void validateServiceComponentHostRequest(ServiceComponentHostRequest request) {
+    if (request.getClusterName() == null
+        || request.getClusterName().isEmpty()
+        || request.getComponentName() == null
+        || request.getComponentName().isEmpty()
+        || request.getHostname() == null
+        || request.getHostname().isEmpty()) {
+      throw new IllegalArgumentException("Invalid arguments"
+          + ", cluster name, component name and host name should be"
+          + " provided");
+    }
+  }
+
+  private String findServiceName(Cluster cluster, String componentName) throws AmbariException {
+    StackId stackId = cluster.getDesiredStackVersion();
+    String serviceName =
+        ambariMetaInfo.getComponentToService(stackId.getStackName(),
+            stackId.getStackVersion(), componentName);
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("Looking up service name for component"
+          + ", componentName=" + componentName
+          + ", serviceName=" + serviceName);
+    }
+
+    if (serviceName == null
+        || serviceName.isEmpty()) {
+      throw new AmbariException("Could not find service for component"
+          + ", componentName=" + componentName
+          + ", clusterName=" + cluster.getClusterName()
+          + ", stackInfo=" + stackId.getStackId());
+    }
+    return serviceName;
+  }
+
+  private boolean isDirectTransition(State oldState, State newState) {
+    switch (newState) {
+      case INSTALLED:
+        if (oldState == State.MAINTENANCE) {
+          return true;
+        }
+        break;
+      case MAINTENANCE:
+        if (oldState == State.INSTALLED) {
+          return true;
+        }
+        break;
+    }
+    return false;
+  }
+
   private boolean checkIfUpgradeRequestAndValidate(ServiceComponentHostRequest request, Cluster cluster, Service s,
                                                    ServiceComponent sc, ServiceComponentHost sch)
       throws AmbariException {
@@ -3231,8 +3284,66 @@ public class AmbariManagementControllerImpl implements
 
   @Override
   public RequestStatusResponse deleteHostComponents(
-      Set<ServiceComponentHostRequest> request) throws AmbariException {
-    throw new AmbariException("Delete host components not supported");
+      Set<ServiceComponentHostRequest> requests) throws AmbariException {
+
+    Map<ServiceComponent, Set<ServiceComponentHost>> safeToRemoveSCHs = new HashMap<ServiceComponent, Set<ServiceComponentHost>>();
+
+    for (ServiceComponentHostRequest request : requests) {
+
+      validateServiceComponentHostRequest(request);
+
+      Cluster cluster = clusters.getCluster(request.getClusterName());
+
+      if (StringUtils.isEmpty(request.getServiceName())) {
+        request.setServiceName(findServiceName(cluster, request.getComponentName()));
+      }
+
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Received a createHostComponent DELETE request request"
+            + ", clusterName=" + request.getClusterName()
+            + ", serviceName=" + request.getServiceName()
+            + ", componentName=" + request.getComponentName()
+            + ", hostname=" + request.getHostname()
+            + ", request=" + request);
+      }
+
+      Service service = cluster.getService(request.getServiceName());
+
+      ServiceComponent component = service.getServiceComponent(request.getComponentName());
+
+      ServiceComponentHost componentHost = component.getServiceComponentHost(request.getHostname());
+
+      if (!componentHost.canBeRemoved()) {
+        throw new AmbariException("Host Component cannot be removed"
+            + ", clusterName=" + request.getClusterName()
+            + ", serviceName=" + request.getServiceName()
+            + ", componentName=" + request.getComponentName()
+            + ", hostname=" + request.getHostname()
+            + ", request=" + request);
+      }
+
+
+      //Only allow removing master components in MAINTENANCE state without stages generation
+      if (component.isClientComponent() ||
+          componentHost.getState() != State.MAINTENANCE) {
+        throw new AmbariException("Only master component in MAINTENANCE state can be removed");
+      }
+
+      if (!safeToRemoveSCHs.containsKey(component)) {
+        safeToRemoveSCHs.put(component, new HashSet<ServiceComponentHost>());
+      }
+
+      safeToRemoveSCHs.get(component).add(componentHost);
+
+    }
+
+    for (Entry<ServiceComponent, Set<ServiceComponentHost>> entry : safeToRemoveSCHs.entrySet()) {
+      for (ServiceComponentHost componentHost : entry.getValue()) {
+        entry.getKey().deleteServiceComponentHosts(componentHost.getHostName());
+      }
+    }
+
+    return null;
   }
 
   @Override

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

@@ -1,4 +1,4 @@
-/**
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information

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

@@ -135,6 +135,10 @@ public abstract class ServiceComponentHostEvent
         return new ServiceComponentHostWipeoutEvent(serviceComponentName, hostName, opTimestamp);
       case HOST_SVCCOMP_UPGRADE:
         return new ServiceComponentHostUpgradeEvent(serviceComponentName, hostName, opTimestamp, stackId);
+      case HOST_SVCCOMP_MAINTENANCE:
+        return new ServiceComponentHostMaintenanceEvent(serviceComponentName, hostName, opTimestamp);
+      case HOST_SVCCOMP_RESTORE:
+        return new ServiceComponentHostRestoreEvent(serviceComponentName, hostName, opTimestamp);
     }
     return null;
   }

+ 10 - 1
ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHostEventType.java

@@ -58,5 +58,14 @@ public enum ServiceComponentHostEventType {
   /**
    * Triggering a host component upgrade.
    */
-  HOST_SVCCOMP_UPGRADE
+  HOST_SVCCOMP_UPGRADE,
+  /**
+   * Putting host component into maintenance state
+   */
+  HOST_SVCCOMP_MAINTENANCE,
+  /**
+   * Recovering host component from maintenance state
+   */
+  HOST_SVCCOMP_RESTORE
+
 }

+ 7 - 1
ambari-server/src/main/java/org/apache/ambari/server/state/State.java

@@ -82,7 +82,11 @@ public enum State {
   /**
    * Upgrade has failed.
    */
-  UPGRADE_FAILED(15);
+  UPGRADE_FAILED(15),
+  /**
+   * Disabled master's backup state
+   */
+  MAINTENANCE(16);
 
   private final int state;
 
@@ -101,6 +105,7 @@ public enum State {
       case INSTALLED:
       case STARTED:
       case UNINSTALLED:
+      case MAINTENANCE:
         return true;
       default:
         return false;
@@ -157,6 +162,7 @@ public enum State {
       case INSTALL_FAILED:
       case UPGRADE_FAILED:
       case UNINSTALLED:
+      case MAINTENANCE:
         return true;
       default:
         return false;

+ 14 - 1
ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java

@@ -314,6 +314,19 @@ public class ServiceComponentHostImpl implements ServiceComponentHost {
          ServiceComponentHostEventType.HOST_SVCCOMP_WIPEOUT,
          new ServiceComponentHostOpStartedTransition())
 
+      .addTransition(State.INSTALLED,
+          State.MAINTENANCE,
+          ServiceComponentHostEventType.HOST_SVCCOMP_MAINTENANCE,
+          new ServiceComponentHostOpCompletedTransition())
+      .addTransition(State.MAINTENANCE,
+          State.MAINTENANCE,
+          ServiceComponentHostEventType.HOST_SVCCOMP_MAINTENANCE,
+          new ServiceComponentHostOpCompletedTransition())
+      .addTransition(State.MAINTENANCE,
+          State.INSTALLED,
+          ServiceComponentHostEventType.HOST_SVCCOMP_RESTORE,
+          new ServiceComponentHostOpCompletedTransition())
+
      .installTopology();
 
   private static final StateMachineFactory
@@ -1265,7 +1278,7 @@ public class ServiceComponentHostImpl implements ServiceComponentHost {
   }
 
   @Override
-  public void delete() throws AmbariException {
+  public void delete() {
     try {
       writeLock.lock();
       if (persisted) {

+ 29 - 0
ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostMaintenanceEvent.java

@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.state.svccomphost;
+
+import org.apache.ambari.server.state.ServiceComponentHostEvent;
+import org.apache.ambari.server.state.ServiceComponentHostEventType;
+
+public class ServiceComponentHostMaintenanceEvent extends ServiceComponentHostEvent {
+  public ServiceComponentHostMaintenanceEvent(String serviceComponentName, String hostName, long opTimestamp) {
+    super(ServiceComponentHostEventType.HOST_SVCCOMP_MAINTENANCE,
+        serviceComponentName, hostName, opTimestamp);
+  }
+}

+ 29 - 0
ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostRestoreEvent.java

@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.state.svccomphost;
+
+import org.apache.ambari.server.state.ServiceComponentHostEvent;
+import org.apache.ambari.server.state.ServiceComponentHostEventType;
+
+public class ServiceComponentHostRestoreEvent extends ServiceComponentHostEvent {
+  public ServiceComponentHostRestoreEvent(String serviceComponentName, String hostName, long opTimestamp) {
+    super(ServiceComponentHostEventType.HOST_SVCCOMP_RESTORE,
+        serviceComponentName, hostName, opTimestamp);
+  }
+}

+ 270 - 0
ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java

@@ -19,14 +19,27 @@
 package org.apache.ambari.server.controller;
 
 import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
 import com.google.inject.Injector;
 import org.apache.ambari.server.*;
+import org.apache.ambari.server.actionmanager.*;
+import org.apache.ambari.server.agent.CommandReport;
+import org.apache.ambari.server.agent.ExecutionCommand;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.orm.GuiceJpaInitializer;
+import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
 import org.apache.ambari.server.state.*;
+import org.apache.ambari.server.state.svccomphost.ServiceComponentHostInstallEvent;
+import org.apache.ambari.server.state.svccomphost.ServiceComponentHostOpSucceededEvent;
+import org.apache.ambari.server.utils.StageUtils;
 import org.easymock.Capture;
 import org.junit.Test;
 
 import java.lang.reflect.Field;
+import java.lang.reflect.Type;
 import java.util.*;
 
 import static org.junit.Assert.*;
@@ -1459,5 +1472,262 @@ public class AmbariManagementControllerImplTest {
         component1, component2, componentHost1, componentHost2, componentHost3);
   }
 
+  @Test
+  public void testMaintenanceAndDeleteStates() throws Exception {
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        Properties properties = new Properties();
+        properties.setProperty(Configuration.PERSISTENCE_IN_MEMORY_KEY, "true");
+        properties.setProperty(Configuration.METADETA_DIR_PATH,
+            "src/main/resources/stacks");
+        properties.setProperty(Configuration.OS_VERSION_KEY,
+            "centos5");
+        try {
+          install(new ControllerModule(properties));
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      }
+    });
+    injector.getInstance(GuiceJpaInitializer.class);
+    AmbariManagementController amc = injector.getInstance(AmbariManagementController.class);
+    Clusters clusters = injector.getInstance(Clusters.class);
+    Gson gson = new Gson();
+
+    clusters.addHost("host1");
+    clusters.addHost("host2");
+    clusters.addHost("host3");
+    Host host = clusters.getHost("host1");
+    host.setOsType("centos5");
+    host.persist();
+    host = clusters.getHost("host2");
+    host.setOsType("centos5");
+    host.persist();
+    host = clusters.getHost("host3");
+    host.setOsType("centos5");
+    host.persist();
+
+    ClusterRequest clusterRequest = new ClusterRequest(null, "c1", "HDP-1.2.0", null);
+    amc.createCluster(clusterRequest);
+
+    Set<ServiceRequest> serviceRequests = new HashSet<ServiceRequest>();
+    serviceRequests.add(new ServiceRequest("c1", "HDFS", null, null));
+//    serviceRequests.add(new ServiceRequest("c1", "MAPREDUCE", null, null));
+//    serviceRequests.add(new ServiceRequest("c1", "ZOOKEEPER", null, null));
+//    serviceRequests.add(new ServiceRequest("c1", "HBASE", null, null));
+//    serviceRequests.add(new ServiceRequest("c1", "GANGLIA", null, null));
+//    serviceRequests.add(new ServiceRequest("c1", "NAGIOS", null, null));
+
+    amc.createServices(serviceRequests);
+
+    Type confType = new TypeToken<Map<String, String>>() {
+    }.getType();
+
+    ConfigurationRequest configurationRequest = new ConfigurationRequest("c1", "core-site", "version1",
+        gson.<Map<String, String>>fromJson("{ \"fs.default.name\" : \"localhost:8020\"}", confType)
+    );
+    amc.createConfiguration(configurationRequest);
+
+    configurationRequest = new ConfigurationRequest("c1", "hdfs-site", "version1",
+        gson.<Map<String, String>>fromJson("{ \"dfs.datanode.data.dir.perm\" : \"750\"}", confType)
+    );
+    amc.createConfiguration(configurationRequest);
+
+    configurationRequest = new ConfigurationRequest("c1", "global", "version1",
+        gson.<Map<String, String>>fromJson("{ \"hbase_hdfs_root_dir\" : \"/apps/hbase/\"}", confType)
+    );
+    amc.createConfiguration(configurationRequest);
+
+//    configurationRequest = new ConfigurationRequest("c1", "mapred-site", "version1",
+//        gson.<Map<String, String>>fromJson("{ \"mapred.job.tracker\" : \"localhost:50300\", \"mapreduce.history.server.embedded\": \"false\", \"mapreduce.history.server.http.address\": \"localhost:51111\"}", confType)
+//    );
+//    amc.createConfiguration(configurationRequest);
+//
+//    configurationRequest = new ConfigurationRequest("c1", "hbase-site", "version1",
+//        gson.<Map<String, String>>fromJson("{ \"hbase.rootdir\" : \"hdfs://localhost:8020/apps/hbase/\", \"hbase.cluster.distributed\" : \"true\", \"hbase.zookeeper.quorum\": \"localhost\", \"zookeeper.session.timeout\": \"60000\" }", confType));
+//    amc.createConfiguration(configurationRequest);
+//
+//    configurationRequest = new ConfigurationRequest("c1", "hbase-env", "version1",
+//        gson.<Map<String, String>>fromJson("{ \"hbase_hdfs_root_dir\" : \"/apps/hbase/\"}", confType)
+//    );
+//    amc.createConfiguration(configurationRequest);
+//
+//    configurationRequest = new ConfigurationRequest("c1", "nagios-global", "version2",
+//        gson.<Map<String, String>>fromJson("{ \"nagios_web_login\" : \"nagiosadmin\", \"nagios_web_password\" : \"password\", \"nagios_contact\": \"a\\u0040b.c\" }", confType)
+//    );
+//    amc.createConfiguration(configurationRequest);
+//
+//    configurationRequest = new ConfigurationRequest("c1", "nagios-global", "version1",
+//        gson.<Map<String, String>>fromJson("{ \"nagios_web_login\" : \"nagiosadmin\", \"nagios_web_password\" : \"password\"  }", confType)
+//    );
+//    amc.createConfiguration(configurationRequest);
+
+
+    serviceRequests.clear();
+    serviceRequests.add(new ServiceRequest("c1", "HDFS",
+        gson.<Map<String, String>>fromJson("{\"core-site\": \"version1\", \"hdfs-site\": \"version1\", \"global\" : \"version1\" }", confType)
+        , null));
+//    serviceRequests.add(new ServiceRequest("c1", "MAPREDUCE",
+//        gson.<Map<String, String>>fromJson("{\"core-site\": \"version1\", \"mapred-site\": \"version1\"}", confType)
+//        , null));
+//    serviceRequests.add(new ServiceRequest("c1", "HBASE",
+//        gson.<Map<String, String>>fromJson("{\"hbase-site\": \"version1\", \"hbase-env\": \"version1\"}", confType)
+//        , null));
+//    serviceRequests.add(new ServiceRequest("c1", "NAGIOS",
+//        gson.<Map<String, String>>fromJson("{\"nagios-global\": \"version2\" }", confType)
+//        , null));
+
+    amc.updateServices(serviceRequests);
+
+
+    Set<ServiceComponentRequest> serviceComponentRequests = new HashSet<ServiceComponentRequest>();
+    serviceComponentRequests.add(new ServiceComponentRequest("c1", "HDFS", "NAMENODE", null, null));
+    serviceComponentRequests.add(new ServiceComponentRequest("c1", "HDFS", "SECONDARY_NAMENODE", null, null));
+    serviceComponentRequests.add(new ServiceComponentRequest("c1", "HDFS", "DATANODE", null, null));
+    serviceComponentRequests.add(new ServiceComponentRequest("c1", "HDFS", "HDFS_CLIENT", null, null));
+
+//    serviceComponentRequests.add(new ServiceComponentRequest("c1", "MAPREDUCE", "JOBTRACKER", null, null));
+//    serviceComponentRequests.add(new ServiceComponentRequest("c1", "MAPREDUCE", "TASKTRACKER", null, null));
+//
+//    serviceComponentRequests.add(new ServiceComponentRequest("c1", "ZOOKEEPER", "ZOOKEEPER_SERVER", null, null));
+//
+//    serviceComponentRequests.add(new ServiceComponentRequest("c1", "HBASE", "HBASE_MASTER", null, null));
+//    serviceComponentRequests.add(new ServiceComponentRequest("c1", "HBASE", "HBASE_REGIONSERVER", null, null));
+//    serviceComponentRequests.add(new ServiceComponentRequest("c1", "HBASE", "HBASE_CLIENT", null, null));
+//
+//    serviceComponentRequests.add(new ServiceComponentRequest("c1", "GANGLIA", "GANGLIA_SERVER", null, null));
+//    serviceComponentRequests.add(new ServiceComponentRequest("c1", "GANGLIA", "GANGLIA_MONITOR", null, null));
+//
+//    serviceComponentRequests.add(new ServiceComponentRequest("c1", "NAGIOS", "NAGIOS_SERVER", null, null));
+
+    amc.createComponents(serviceComponentRequests);
+
+    Set<HostRequest> hostRequests = new HashSet<HostRequest>();
+    hostRequests.add(new HostRequest("host1", "c1", null));
+    hostRequests.add(new HostRequest("host2", "c1", null));
+    hostRequests.add(new HostRequest("host3", "c1", null));
+
+    amc.createHosts(hostRequests);
+
+    Set<ServiceComponentHostRequest> componentHostRequests = new HashSet<ServiceComponentHostRequest>();
+    componentHostRequests.add(new ServiceComponentHostRequest("c1", null, "DATANODE", "host1", null, null));
+    componentHostRequests.add(new ServiceComponentHostRequest("c1", null, "NAMENODE", "host1", null, null));
+    componentHostRequests.add(new ServiceComponentHostRequest("c1", null, "SECONDARY_NAMENODE", "host1", null, null));
+    componentHostRequests.add(new ServiceComponentHostRequest("c1", null, "DATANODE", "host2", null, null));
+    componentHostRequests.add(new ServiceComponentHostRequest("c1", null, "DATANODE", "host3", null, null));
+
+
+//    componentHostRequests.add(new ServiceComponentHostRequest("c1", null, "JOBTRACKER", "host1", null, null));
+//    componentHostRequests.add(new ServiceComponentHostRequest("c1", null, "TASKTRACKER", "host1", null, null));
+//    componentHostRequests.add(new ServiceComponentHostRequest("c1", null, "TASKTRACKER", "host2", null, null));
+//    componentHostRequests.add(new ServiceComponentHostRequest("c1", null, "TASKTRACKER", "host3", null, null));
+//
+//    componentHostRequests.add(new ServiceComponentHostRequest("c1", null, "ZOOKEEPER_SERVER", "host1", null, null));
+//    componentHostRequests.add(new ServiceComponentHostRequest("c1", null, "GANGLIA_SERVER", "host1", null, null));
+//    componentHostRequests.add(new ServiceComponentHostRequest("c1", null, "GANGLIA_MONITOR", "host1", null, null));
+//
+//    componentHostRequests.add(new ServiceComponentHostRequest("c1", null, "HDFS_CLIENT", "host1", null, null));
+//    componentHostRequests.add(new ServiceComponentHostRequest("c1", null, "HBASE_MASTER", "host1", null, null));
+//    componentHostRequests.add(new ServiceComponentHostRequest("c1", null, "HBASE_REGIONSERVER", "host1", null, null));
+//    componentHostRequests.add(new ServiceComponentHostRequest("c1", null, "HBASE_CLIENT", "host1", null, null));
+//
+//    componentHostRequests.add(new ServiceComponentHostRequest("c1", null, "NAGIOS_SERVER", "host1", null, null));
+
+
+    amc.createHostComponents(componentHostRequests);
+
+    serviceRequests.clear();
+    serviceRequests.add(new ServiceRequest("c1", "HDFS", null, "INSTALLED"));
+//    serviceRequests.add(new ServiceRequest("c1", "MAPREDUCE", null, "INSTALLED"));
+//    serviceRequests.add(new ServiceRequest("c1", "ZOOKEEPER", null, "INSTALLED"));
+//    serviceRequests.add(new ServiceRequest("c1", "HBASE", null, "INSTALLED"));
+//    serviceRequests.add(new ServiceRequest("c1", "GANGLIA", null, "INSTALLED"));
+//    serviceRequests.add(new ServiceRequest("c1", "NAGIOS", null, "INSTALLED"));
+
+    amc.updateServices(serviceRequests);
+
+    Cluster cluster = clusters.getCluster("c1");
+    Map<String, ServiceComponentHost> namenodes = cluster.getService("HDFS").getServiceComponent("NAMENODE").getServiceComponentHosts();
+    assertEquals(1, namenodes.size());
+
+    ServiceComponentHost componentHost = namenodes.get("host1");
+
+    Map<String, ServiceComponentHost> hostComponents = cluster.getService("HDFS").getServiceComponent("DATANODE").getServiceComponentHosts();
+    for (Map.Entry<String, ServiceComponentHost> entry : hostComponents.entrySet()) {
+      ServiceComponentHost cHost = entry.getValue();
+      cHost.handleEvent(new ServiceComponentHostInstallEvent(cHost.getServiceComponentName(), cHost.getHostName(), System.currentTimeMillis(), "HDP-1.2.0"));
+      cHost.handleEvent(new ServiceComponentHostOpSucceededEvent(cHost.getServiceComponentName(), cHost.getHostName(), System.currentTimeMillis()));
+    }
+    hostComponents = cluster.getService("HDFS").getServiceComponent("NAMENODE").getServiceComponentHosts();
+    for (Map.Entry<String, ServiceComponentHost> entry : hostComponents.entrySet()) {
+      ServiceComponentHost cHost = entry.getValue();
+      cHost.handleEvent(new ServiceComponentHostInstallEvent(cHost.getServiceComponentName(), cHost.getHostName(), System.currentTimeMillis(), "HDP-1.2.0"));
+      cHost.handleEvent(new ServiceComponentHostOpSucceededEvent(cHost.getServiceComponentName(), cHost.getHostName(), System.currentTimeMillis()));
+    }
+    hostComponents = cluster.getService("HDFS").getServiceComponent("SECONDARY_NAMENODE").getServiceComponentHosts();
+    for (Map.Entry<String, ServiceComponentHost> entry : hostComponents.entrySet()) {
+      ServiceComponentHost cHost = entry.getValue();
+      cHost.handleEvent(new ServiceComponentHostInstallEvent(cHost.getServiceComponentName(), cHost.getHostName(), System.currentTimeMillis(), "HDP-1.2.0"));
+      cHost.handleEvent(new ServiceComponentHostOpSucceededEvent(cHost.getServiceComponentName(), cHost.getHostName(), System.currentTimeMillis()));
+    }
+
+    componentHostRequests.clear();
+    componentHostRequests.add(new ServiceComponentHostRequest("c1", null, "NAMENODE", "host1", null, "MAINTENANCE"));
+
+    amc.updateHostComponents(componentHostRequests);
+
+    assertEquals(State.MAINTENANCE, componentHost.getState());
+
+    componentHostRequests.clear();
+    componentHostRequests.add(new ServiceComponentHostRequest("c1", null, "NAMENODE", "host1", null, "INSTALLED"));
+
+    amc.updateHostComponents(componentHostRequests);
+
+    assertEquals(State.INSTALLED, componentHost.getState());
+
+    componentHostRequests.clear();
+    componentHostRequests.add(new ServiceComponentHostRequest("c1", null, "NAMENODE", "host1", null, "MAINTENANCE"));
+
+    amc.updateHostComponents(componentHostRequests);
+
+    assertEquals(State.MAINTENANCE, componentHost.getState());
+
+    componentHostRequests.clear();
+    componentHostRequests.add(new ServiceComponentHostRequest("c1", null, "NAMENODE", "host2", null, null));
+
+    amc.createHostComponents(componentHostRequests);
+
+    componentHostRequests.clear();
+    componentHostRequests.add(new ServiceComponentHostRequest("c1", null, "NAMENODE", "host2", null, "INSTALLED"));
+
+    amc.updateHostComponents(componentHostRequests);
+
+    namenodes = cluster.getService("HDFS").getServiceComponent("NAMENODE").getServiceComponentHosts();
+    assertEquals(2, namenodes.size());
+
+    componentHost = namenodes.get("host2");
+    componentHost.handleEvent(new ServiceComponentHostInstallEvent(componentHost.getServiceComponentName(), componentHost.getHostName(), System.currentTimeMillis(), "HDP-1.2.0"));
+    componentHost.handleEvent(new ServiceComponentHostOpSucceededEvent(componentHost.getServiceComponentName(), componentHost.getHostName(), System.currentTimeMillis()));
+
+    serviceRequests.clear();
+    serviceRequests.add(new ServiceRequest("c1", "HDFS", null, "STARTED"));
+
+    RequestStatusResponse response = amc.updateServices(serviceRequests);
+    for (ShortTaskStatus shortTaskStatus : response.getTasks()) {
+      assertFalse("host1".equals(shortTaskStatus.getHostName()) && "NAMENODE".equals(shortTaskStatus.getRole()));
+    }
+
+    componentHostRequests.clear();
+    componentHostRequests.add(new ServiceComponentHostRequest("c1", null, "NAMENODE", "host1", null, null));
+
+    amc.deleteHostComponents(componentHostRequests);
+
+    namenodes = cluster.getService("HDFS").getServiceComponent("NAMENODE").getServiceComponentHosts();
+
+    assertEquals(1, namenodes.size());
+
+  }
+
   //todo other resources
 }