ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From smoha...@apache.org
Subject [2/3] AMBARI 3608. Custom Action: Add support for Custom Action Definition
Date Mon, 04 Nov 2013 18:05:15 GMT
http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/8b0e64c5/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestResourceProvider.java
index 58d8311..f8c9065 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestResourceProvider.java
@@ -17,19 +17,24 @@
  */
 package org.apache.ambari.server.controller.internal;
 
+import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.actionmanager.ActionManager;
 import org.apache.ambari.server.actionmanager.HostRoleCommand;
 import org.apache.ambari.server.actionmanager.HostRoleStatus;
+import org.apache.ambari.server.controller.ExecuteActionRequest;
 import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.RequestStatusResponse;
 import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
 import org.apache.ambari.server.controller.spi.NoSuchResourceException;
 import org.apache.ambari.server.controller.spi.Predicate;
 import org.apache.ambari.server.controller.spi.Request;
 import org.apache.ambari.server.controller.spi.RequestStatus;
 import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
 import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -47,17 +52,22 @@ class RequestResourceProvider extends AbstractControllerResourceProvider {
   // ----- Property ID constants ---------------------------------------------
   // Requests
   protected static final String REQUEST_CLUSTER_NAME_PROPERTY_ID = "Requests/cluster_name";
-  protected static final String REQUEST_ID_PROPERTY_ID           = "Requests/id";
-  protected static final String REQUEST_STATUS_PROPERTY_ID       = "Requests/request_status";
-  protected static final String REQUEST_CONTEXT_ID               = "Requests/request_context";
-  protected static final String REQUEST_TASK_CNT_ID              = "Requests/task_count";
-  protected static final String REQUEST_FAILED_TASK_CNT_ID       = "Requests/failed_task_count";
-  protected static final String REQUEST_ABORTED_TASK_CNT_ID      = "Requests/aborted_task_count";
-  protected static final String REQUEST_TIMED_OUT_TASK_CNT_ID    = "Requests/timed_out_task_count";
-  protected static final String REQUEST_COMPLETED_TASK_CNT_ID    = "Requests/completed_task_count";
-  protected static final String REQUEST_QUEUED_TASK_CNT_ID       = "Requests/queued_task_count";
-  protected static final String REQUEST_PROGRESS_PERCENT_ID      = "Requests/progress_percent";
-
+  protected static final String REQUEST_ID_PROPERTY_ID = "Requests/id";
+  protected static final String REQUEST_STATUS_PROPERTY_ID = "Requests/request_status";
+  protected static final String REQUEST_CONTEXT_ID = "Requests/request_context";
+  protected static final String REQUEST_TASK_CNT_ID = "Requests/task_count";
+  protected static final String REQUEST_FAILED_TASK_CNT_ID = "Requests/failed_task_count";
+  protected static final String REQUEST_ABORTED_TASK_CNT_ID = "Requests/aborted_task_count";
+  protected static final String REQUEST_TIMED_OUT_TASK_CNT_ID = "Requests/timed_out_task_count";
+  protected static final String REQUEST_COMPLETED_TASK_CNT_ID = "Requests/completed_task_count";
+  protected static final String REQUEST_QUEUED_TASK_CNT_ID = "Requests/queued_task_count";
+  protected static final String REQUEST_PROGRESS_PERCENT_ID = "Requests/progress_percent";
+  protected static final String COMMAND_ID = "command";
+  protected static final String ACTION_ID = "action";
+  protected static final String HOSTS_ID = "hosts";
+  protected static final String SERVICE_NAME_ID = "service_name";
+  protected static final String COMPONENT_NAME_ID = "component_name";
+  protected static final String INPUTS_ID = "parameters";
   private static Set<String> pkPropertyIds =
       new HashSet<String>(Arrays.asList(new String[]{
           REQUEST_ID_PROPERTY_ID}));
@@ -80,16 +90,27 @@ class RequestResourceProvider extends AbstractControllerResourceProvider {
   // ----- ResourceProvider ------------------------------------------------
 
   @Override
-  public RequestStatus createResources(Request request) {
-    throw new UnsupportedOperationException("Not currently supported.");
+  public RequestStatus createResources(Request request)
+      throws SystemException, UnsupportedPropertyException, NoSuchParentResourceException, ResourceAlreadyExistsException {
+    if (request.getProperties().size() > 1) {
+      throw new UnsupportedOperationException("Multiple actions/commands cannot be executed at the same time.");
+    }
+    final ExecuteActionRequest actionRequest = getActionRequest(request);
+    final Map<String, String> requestInfoProperties = request.getRequestInfoProperties();
+    return getRequestStatus(createResources(new Command<RequestStatusResponse>() {
+      @Override
+      public RequestStatusResponse invoke() throws AmbariException {
+        return getManagementController().createAction(actionRequest, requestInfoProperties);
+      }
+    }));
   }
 
   @Override
   public Set<Resource> getResources(Request request, Predicate predicate)
       throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
 
-    Set<String>   requestedIds = getRequestPropertyIds(request, predicate);
-    Set<Resource> resources    = new HashSet<Resource>();
+    Set<String> requestedIds = getRequestPropertyIds(request, predicate);
+    Set<Resource> resources = new HashSet<Resource>();
 
     for (Map<String, Object> properties : getPropertyMaps(predicate)) {
       String clusterName = (String) properties.get(REQUEST_CLUSTER_NAME_PROPERTY_ID);
@@ -130,13 +151,65 @@ class RequestResourceProvider extends AbstractControllerResourceProvider {
 
   // ----- utility methods --------------------------------------------------
 
+  // Get request to execute an action/command
+  private ExecuteActionRequest getActionRequest(Request request) {
+    Map<String, String> requestInfoProperties = request.getRequestInfoProperties();
+    Map<String, Object> propertyMap = request.getProperties().iterator().next();
+
+    Boolean isCommand = requestInfoProperties.containsKey(COMMAND_ID);
+    String commandName = null;
+    String actionName = null;
+    if (isCommand) {
+      if (requestInfoProperties.containsKey(ACTION_ID)) {
+        throw new UnsupportedOperationException("Both command and action cannot be specified.");
+      }
+      commandName = requestInfoProperties.get(COMMAND_ID);
+    } else {
+      if (!requestInfoProperties.containsKey(ACTION_ID)) {
+        throw new UnsupportedOperationException("Either command or action must be specified.");
+      }
+      actionName = requestInfoProperties.get(ACTION_ID);
+    }
+
+    String hostList = requestInfoProperties.get(HOSTS_ID);
+    List<String> hosts = new ArrayList<String>();
+    if (hostList != null && !hostList.isEmpty()) {
+      for (String hostname : hostList.split(",")) {
+        String trimmedName = hostname.trim();
+        if (!trimmedName.isEmpty()) {
+          hosts.add(hostname.trim());
+        }
+      }
+    }
+
+    String serviceName = requestInfoProperties.get(SERVICE_NAME_ID);
+    String componentName = requestInfoProperties.get(COMPONENT_NAME_ID);
+
+    Map<String, String> params = new HashMap<String, String>();
+    String keyPrefix = "/" + INPUTS_ID + "/";
+    for (String key : requestInfoProperties.keySet()) {
+      if (key.startsWith(keyPrefix)) {
+        params.put(key.substring(keyPrefix.length()), requestInfoProperties.get(key));
+      }
+    }
+
+    return new ExecuteActionRequest(
+        (String) propertyMap.get(REQUEST_CLUSTER_NAME_PROPERTY_ID),
+        commandName,
+        actionName,
+        serviceName,
+        componentName,
+        hosts,
+        params);
+  }
+
   // Get all of the request resources for the given properties
   private Set<Resource> getRequestResources(String clusterName,
                                             Long requestId,
                                             String requestStatus,
                                             Set<String> requestedPropertyIds) throws NoSuchResourceException {
 
-    Set<Resource> response      = new HashSet<Resource>();
+    Set<Resource> response = new HashSet<Resource>();
     ActionManager actionManager = getManagementController().getActionManager();
 
     if (requestId == null) {
@@ -170,15 +243,15 @@ class RequestResourceProvider extends AbstractControllerResourceProvider {
                                                    Set<String> requestedPropertyIds) {
 
     List<HostRoleCommand> hostRoleCommands = actionManager.getAllTasksByRequestIds(requestIds);
-    Map<Long, String>     requestContexts  = actionManager.getRequestContext(requestIds);
-    Map<Long, Resource>   resourceMap      = new HashMap<Long, Resource>();
+    Map<Long, String> requestContexts = actionManager.getRequestContext(requestIds);
+    Map<Long, Resource> resourceMap = new HashMap<Long, Resource>();
 
     // group by request id
     Map<Long, Set<HostRoleCommand>> commandMap = new HashMap<Long, Set<HostRoleCommand>>();
 
     for (HostRoleCommand hostRoleCommand : hostRoleCommands) {
-      Long                 requestId = hostRoleCommand.getRequestId();
-      Set<HostRoleCommand> commands  = commandMap.get(requestId);
+      Long requestId = hostRoleCommand.getRequestId();
+      Set<HostRoleCommand> commands = commandMap.get(requestId);
 
       if (commands == null) {
         commands = new HashSet<HostRoleCommand>();
@@ -188,9 +261,9 @@ class RequestResourceProvider extends AbstractControllerResourceProvider {
     }
 
     for (Map.Entry<Long, Set<HostRoleCommand>> entry : commandMap.entrySet()) {
-      Long                 requestId = entry.getKey();
-      Set<HostRoleCommand> commands  = entry.getValue();
-      String               context   = requestContexts.get(requestId);
+      Long requestId = entry.getKey();
+      Set<HostRoleCommand> commands = entry.getValue();
+      String context = requestContexts.get(requestId);
 
       resourceMap.put(requestId,
           getRequestResource(clusterName, requestId, context, commands, requestedPropertyIds));
@@ -210,13 +283,13 @@ class RequestResourceProvider extends AbstractControllerResourceProvider {
     setResourceProperty(resource, REQUEST_ID_PROPERTY_ID, requestId, requestedPropertyIds);
     setResourceProperty(resource, REQUEST_CONTEXT_ID, context, requestedPropertyIds);
 
-    int taskCount          = commands.size();
+    int taskCount = commands.size();
     int completedTaskCount = 0;
-    int queuedTaskCount    = 0;
-    int pendingTaskCount   = 0;
-    int failedTaskCount    = 0;
-    int abortedTaskCount   = 0;
-    int timedOutTaskCount  = 0;
+    int queuedTaskCount = 0;
+    int pendingTaskCount = 0;
+    int failedTaskCount = 0;
+    int abortedTaskCount = 0;
+    int timedOutTaskCount = 0;
 
     for (HostRoleCommand hostRoleCommand : commands) {
       HostRoleStatus status = hostRoleCommand.getStatus();
@@ -244,14 +317,14 @@ class RequestResourceProvider extends AbstractControllerResourceProvider {
     int inProgressTaskCount = taskCount - completedTaskCount - queuedTaskCount - pendingTaskCount;
 
     // determine request status
-    HostRoleStatus requestStatus = failedTaskCount > 0             ? HostRoleStatus.FAILED :
-                                   abortedTaskCount > 0            ? HostRoleStatus.ABORTED :
-                                   timedOutTaskCount > 0           ? HostRoleStatus.TIMEDOUT :
-                                   inProgressTaskCount > 0         ? HostRoleStatus.IN_PROGRESS :
-                                   completedTaskCount == taskCount ? HostRoleStatus.COMPLETED :
-                                                                     HostRoleStatus.PENDING;
+    HostRoleStatus requestStatus = failedTaskCount > 0 ? HostRoleStatus.FAILED :
+        abortedTaskCount > 0 ? HostRoleStatus.ABORTED :
+            timedOutTaskCount > 0 ? HostRoleStatus.TIMEDOUT :
+                inProgressTaskCount > 0 ? HostRoleStatus.IN_PROGRESS :
+                    completedTaskCount == taskCount ? HostRoleStatus.COMPLETED :
+                        HostRoleStatus.PENDING;
     double progressPercent =
-        ((queuedTaskCount * 0.09 + inProgressTaskCount * 0.35 + completedTaskCount)/(double) taskCount) * 100.0;
+        ((queuedTaskCount * 0.09 + inProgressTaskCount * 0.35 + completedTaskCount) / (double) taskCount) * 100.0;
 
     setResourceProperty(resource, REQUEST_STATUS_PROPERTY_ID, requestStatus.toString(), requestedPropertyIds);
     setResourceProperty(resource, REQUEST_TASK_CNT_ID, taskCount, requestedPropertyIds);

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/8b0e64c5/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
index 3389fca..d4af369 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
@@ -39,7 +39,7 @@ public interface Resource {
    * each key is the absolute category name and the corresponding
    * value is a map of properties(name/value pairs) for that category.
    *
-   * @return  resource properties map
+   * @return resource properties map
    */
   public Map<String, Map<String, Object>> getPropertiesMap();
 
@@ -54,7 +54,7 @@ public interface Resource {
   /**
    * Add an empty category to this resource.
    *
-   * @param id    the category id
+   * @param id the category id
    */
   public void addCategory(String id);
 

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/8b0e64c5/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ActionDefinitionDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ActionDefinitionDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ActionDefinitionDAO.java
new file mode 100644
index 0000000..df1f71a
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ActionDefinitionDAO.java
@@ -0,0 +1,71 @@
+/*
+ * 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.orm.dao;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.persist.Transactional;
+import org.apache.ambari.server.orm.entities.ActionEntity;
+
+import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+import javax.persistence.TypedQuery;
+import java.util.List;
+
+public class ActionDefinitionDAO {
+
+  @Inject
+  Provider<EntityManager> entityManagerProvider;
+
+  @Transactional
+  public ActionEntity findByPK(String actionName) {
+    return entityManagerProvider.get().find(ActionEntity.class, actionName);
+  }
+
+  @Transactional
+  public List<ActionEntity> findAll() {
+    TypedQuery<ActionEntity> query = entityManagerProvider.get().createNamedQuery("allActions",
+        ActionEntity.class);
+    try {
+      return query.getResultList();
+    } catch (NoResultException ignored) {
+    }
+    return null;
+  }
+
+  @Transactional
+  public void create(ActionEntity actionDefinition) {
+    entityManagerProvider.get().persist(actionDefinition);
+  }
+
+  @Transactional
+  public ActionEntity merge(ActionEntity actionDefinition) {
+    return entityManagerProvider.get().merge(actionDefinition);
+  }
+
+  @Transactional
+  public void remove(ActionEntity actionDefinition) {
+    entityManagerProvider.get().remove(merge(actionDefinition));
+  }
+
+  @Transactional
+  public void removeByPK(String actionName) {
+    remove(findByPK(actionName));
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/8b0e64c5/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ExecutionCommandDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ExecutionCommandDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ExecutionCommandDAO.java
index 4bc9b21..216acf3 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ExecutionCommandDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ExecutionCommandDAO.java
@@ -38,18 +38,18 @@ public class ExecutionCommandDAO {
   }
 
   @Transactional
-  public void create(ExecutionCommandEntity stageEntity) {
-    entityManagerProvider.get().persist(stageEntity);
+  public void create(ExecutionCommandEntity executionCommand) {
+    entityManagerProvider.get().persist(executionCommand);
   }
 
   @Transactional
-  public ExecutionCommandEntity merge(ExecutionCommandEntity stageEntity) {
-    return entityManagerProvider.get().merge(stageEntity);
+  public ExecutionCommandEntity merge(ExecutionCommandEntity executionCommand) {
+    return entityManagerProvider.get().merge(executionCommand);
   }
 
   @Transactional
-  public void remove(ExecutionCommandEntity stageEntity) {
-    entityManagerProvider.get().remove(merge(stageEntity));
+  public void remove(ExecutionCommandEntity executionCommand) {
+    entityManagerProvider.get().remove(merge(executionCommand));
   }
 
   @Transactional

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/8b0e64c5/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ActionEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ActionEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ActionEntity.java
new file mode 100644
index 0000000..9e23516
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ActionEntity.java
@@ -0,0 +1,154 @@
+/*
+ * 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.orm.entities;
+
+import org.apache.ambari.server.actionmanager.ActionType;
+import org.apache.ambari.server.actionmanager.TargetHostType;
+
+import javax.persistence.*;
+
+@NamedQueries({
+    @NamedQuery(name = "allActions", query =
+        "SELECT actions " +
+            "FROM ActionEntity actions")
+})
+@Table(name = "action")
+@Entity
+public class ActionEntity {
+
+  @Id
+  @Column(name = "action_name")
+  private String actionName;
+
+  @Column(name = "action_type")
+  @Enumerated(EnumType.STRING)
+  private ActionType actionType = ActionType.DISABLED;
+
+  @Column(name = "inputs")
+  @Basic
+  private String inputs;
+
+  @Column(name = "target_service")
+  @Basic
+  private String targetService;
+
+  @Column(name = "target_component")
+  @Basic
+  private String targetComponent;
+
+  @Column(name = "description")
+  @Basic
+  private String description = "";
+
+  @Column(name = "target_type")
+  @Enumerated(EnumType.STRING)
+  private TargetHostType targetType = TargetHostType.ANY;
+
+  @Basic
+  @Column(name = "default_timeout", nullable = false)
+  private Short defaultTimeout = 600;
+
+  public String getActionName() {
+    return actionName;
+  }
+
+  public void setActionName(String actionName) {
+    this.actionName = actionName;
+  }
+
+  public ActionType getActionType() {
+    return actionType;
+  }
+
+  public void setActionType(ActionType actionType) {
+    this.actionType = actionType;
+  }
+
+  public String getInputs() {
+    return inputs;
+  }
+
+  public void setInputs(String inputs) {
+    this.inputs = inputs;
+  }
+
+  public String getDescription() {
+    return description;
+  }
+
+  public void setDescription(String description) {
+    this.description = description;
+  }
+
+  public TargetHostType getTargetType() {
+    return targetType;
+  }
+
+  public void setTargetType(TargetHostType targetType) {
+    this.targetType = targetType;
+  }
+
+  public String getTargetService() {
+    return targetService;
+  }
+
+  public void setTargetService(String targetService) {
+    this.targetService = targetService;
+  }
+
+  public String getTargetComponent() {
+    return targetComponent;
+  }
+
+  public void setTargetComponent(String targetComponent) {
+    this.targetComponent = targetComponent;
+  }
+
+  public Short getDefaultTimeout() {
+    return defaultTimeout;
+  }
+
+  public void setDefaultTimeout(Short defaultTimeout) {
+    this.defaultTimeout = defaultTimeout;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+
+    ActionEntity that = (ActionEntity) o;
+
+    if (actionName != null ? !actionName.equals(that.actionName) : that.actionName != null) {
+      return false;
+    }
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = actionName != null ? actionName.hashCode() : 0;
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/8b0e64c5/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
index 43954b3..ff33085 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
@@ -119,6 +119,9 @@ GRANT ALL PRIVILEGES ON TABLE ambari.configgroupclusterconfigmapping TO :usernam
 CREATE TABLE ambari.configgrouphostmapping (config_group_id BIGINT NOT NULL, host_name VARCHAR(255) NOT NULL, PRIMARY KEY(config_group_id, host_name));
 GRANT ALL PRIVILEGES ON TABLE ambari.configgrouphostmapping TO :username;
 
+CREATE TABLE ambari.action (action_name VARCHAR(255) NOT NULL, action_type VARCHAR(32) NOT NULL, inputs VARCHAR(1000),
+target_service VARCHAR(255), target_component VARCHAR(255), default_timeout SMALLINT NOT NULL, description VARCHAR(1000), target_type VARCHAR(32), PRIMARY KEY (action_name));
+GRANT ALL PRIVILEGES ON TABLE ambari.action TO :username;
 
 --------altering tables by creating foreign keys----------
 ALTER TABLE ambari.clusterconfig ADD CONSTRAINT FK_clusterconfig_cluster_id FOREIGN KEY (cluster_id) REFERENCES ambari.clusters (cluster_id);

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/8b0e64c5/ambari-server/src/main/resources/META-INF/persistence.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/META-INF/persistence.xml b/ambari-server/src/main/resources/META-INF/persistence.xml
index 60668af..5e2e752 100644
--- a/ambari-server/src/main/resources/META-INF/persistence.xml
+++ b/ambari-server/src/main/resources/META-INF/persistence.xml
@@ -41,6 +41,7 @@
     <class>org.apache.ambari.server.orm.entities.ConfigGroupEntity</class>
     <class>org.apache.ambari.server.orm.entities.ConfigGroupConfigMappingEntity</class>
     <class>org.apache.ambari.server.orm.entities.ConfigGroupHostMappingEntity</class>
+    <class>org.apache.ambari.server.orm.entities.ActionEntity</class>
 
     <properties>
       <!--<property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost/ambari" />-->
@@ -77,6 +78,7 @@
     <!--<class>org.apache.ambari.server.orm.entities.ClusterConfigMappingEntity</class>-->
     <!--<class>org.apache.ambari.server.orm.entities.HostConfigMappingEntity</class>-->
     <!--<class>org.apache.ambari.server.orm.entities.MetainfoEntity</class>-->
+    <!--<class>org.apache.ambari.server.orm.entities.ActionEntity</class>-->
 
     <!--<properties>-->
       <!--<property name="javax.persistence.jdbc.url" value="jdbc:derby:memory:myDB/ambari;create=true" />-->

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/8b0e64c5/ambari-server/src/main/resources/key_properties.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/key_properties.json b/ambari-server/src/main/resources/key_properties.json
index 684a756..3a2be50 100644
--- a/ambari-server/src/main/resources/key_properties.json
+++ b/ambari-server/src/main/resources/key_properties.json
@@ -1,108 +1,106 @@
 {
-  "Cluster":{
-    "Cluster":"Clusters/cluster_name"
-  },
-  "Service":{
-    "Cluster":"ServiceInfo/cluster_name",
-    "Service":"ServiceInfo/service_name"
-  },
-  "Host":{
-    "Cluster":"Hosts/cluster_name",
-    "Host":"Hosts/host_name"
-  },
-  "Component":{
-    "Cluster":"ServiceComponentInfo/cluster_name",
-    "Service":"ServiceComponentInfo/service_name",
-    "Component":"ServiceComponentInfo/component_name",
-    "HostComponent":"ServiceComponentInfo/component_name"
-  },
-  "HostComponent":{
-    "Cluster":"HostRoles/cluster_name",
-    "Host":"HostRoles/host_name",
-    "HostComponent":"HostRoles/component_name",
-    "Component":"HostRoles/component_name"
-  },
-  "Configuration":{
-    "Cluster":"Config/cluster_name",
-    "Configuration":"Config/type"
-  },
-  "Action":{
-    "Cluster":"Actions/cluster_name",
-    "Service":"Actions/service_name",
-    "Action":"Actions/action_name"
-  },
-  "Request":{
-    "Cluster":"Requests/cluster_name",
-    "Request":"Requests/id"
-  },
-  "Task":{
-    "Cluster":"Tasks/cluster_name",
-    "Request":"Tasks/request_id",
-    "Task":"Tasks/id"
-  },
-  "User":{
-    "User":"Users/user_name"
-  },
-  "Stack":{
-    "Stack":"Stacks/stack_name"
-  },
-  "StackVersion":{
-    "Stack":"Versions/stack_name",
-    "StackVersion":"Versions/stack_version"
-  },
-  "OperatingSystem":{
-    "Stack":"OperatingSystems/stack_name",
-    "StackVersion":"OperatingSystems/stack_version",
-    "OperatingSystem":"OperatingSystems/os_type"
-  },
-  "Repository":{
-    "Stack":"Repositories/stack_name",
-    "StackVersion":"Repositories/stack_version",
-    "OperatingSystem":"Repositories/os_type",
-    "Repository":"Repositories/repo_id"
-  },
-  "StackService":{
-    "Stack":"StackServices/stack_name",
-    "StackVersion":"StackServices/stack_version",
-    "StackService":"StackServices/service_name"
-  },
-  "StackConfiguration":{
-    "Stack":"StackConfigurations/stack_name",
-    "StackVersion":"StackConfigurations/stack_version",
-    "StackService":"StackConfigurations/service_name",
-    "StackConfiguration":"StackConfigurations/property_name"
-  },
-  "StackServiceComponent":{
-    "Stack":"StackServiceComponents/stack_name",
-    "StackVersion":"StackServiceComponents/stack_version",
-    "StackService":"StackServiceComponents/service_name",
-    "StackServiceComponent":"StackServiceComponents/component_name"
-  },
-  "DRFeed":{
-    "DRFeed":"Feed/name"
-  },
-  "DRTargetCluster":{
-    "DRTargetCluster":"Cluster/name"
-  },
-  "DRInstance":{
-    "DRFeed":"Instance/feedName",
-    "DRInstance":"Instance/id"
-  },
-  "RootService":{
-    "RootService":"RootService/service_name"
-  },
-  "RootServiceComponent":{
-    "RootService":"RootServiceComponents/service_name",
-    "RootServiceComponent":"RootServiceComponents/component_name"
-  },
-  "RootServiceHostComponent":{
-    "RootService":"RootServiceHostComponents/service_name",
-    "Host":"RootServiceHostComponents/host_name",
-    "RootServiceComponent":"RootServiceHostComponents/component_name",
-    "RootServiceHostComponent":"RootServiceHostComponents/component_name"
-  },
-  "ConfigGroup" : {
-      "Cluster" : "ConfigGroup/cluster_name",
-      "ConfigGroup" : "ConfigGroup/id"
+  "Cluster": {
+    "Cluster": "Clusters/cluster_name"
+  },
+  "Service": {
+    "Cluster": "ServiceInfo/cluster_name",
+    "Service": "ServiceInfo/service_name"
+  },
+  "Host": {
+    "Cluster": "Hosts/cluster_name",
+    "Host": "Hosts/host_name"
+  },
+  "Component": {
+    "Cluster": "ServiceComponentInfo/cluster_name",
+    "Service": "ServiceComponentInfo/service_name",
+    "Component": "ServiceComponentInfo/component_name",
+    "HostComponent": "ServiceComponentInfo/component_name"
+  },
+  "HostComponent": {
+    "Cluster": "HostRoles/cluster_name",
+    "Host": "HostRoles/host_name",
+    "HostComponent": "HostRoles/component_name",
+    "Component": "HostRoles/component_name"
+  },
+  "Configuration": {
+    "Cluster": "Config/cluster_name",
+    "Configuration": "Config/type"
+  },
+  "Action": {
+    "Action": "Actions/action_name"
+  },
+  "Request": {
+    "Cluster": "Requests/cluster_name",
+    "Request": "Requests/id"
+  },
+  "Task": {
+    "Cluster": "Tasks/cluster_name",
+    "Request": "Tasks/request_id",
+    "Task": "Tasks/id"
+  },
+  "User": {
+    "User": "Users/user_name"
+  },
+  "Stack": {
+    "Stack": "Stacks/stack_name"
+  },
+  "StackVersion": {
+    "Stack": "Versions/stack_name",
+    "StackVersion": "Versions/stack_version"
+  },
+  "OperatingSystem": {
+    "Stack": "OperatingSystems/stack_name",
+    "StackVersion": "OperatingSystems/stack_version",
+    "OperatingSystem": "OperatingSystems/os_type"
+  },
+  "Repository": {
+    "Stack": "Repositories/stack_name",
+    "StackVersion": "Repositories/stack_version",
+    "OperatingSystem": "Repositories/os_type",
+    "Repository": "Repositories/repo_id"
+  },
+  "StackService": {
+    "Stack": "StackServices/stack_name",
+    "StackVersion": "StackServices/stack_version",
+    "StackService": "StackServices/service_name"
+  },
+  "StackConfiguration": {
+    "Stack": "StackConfigurations/stack_name",
+    "StackVersion": "StackConfigurations/stack_version",
+    "StackService": "StackConfigurations/service_name",
+    "StackConfiguration": "StackConfigurations/property_name"
+  },
+  "StackServiceComponent": {
+    "Stack": "StackServiceComponents/stack_name",
+    "StackVersion": "StackServiceComponents/stack_version",
+    "StackService": "StackServiceComponents/service_name",
+    "StackServiceComponent": "StackServiceComponents/component_name"
+  },
+  "DRFeed": {
+    "DRFeed": "Feed/name"
+  },
+  "DRTargetCluster": {
+    "DRTargetCluster": "Cluster/name"
+  },
+  "DRInstance": {
+    "DRFeed": "Instance/feedName",
+    "DRInstance": "Instance/id"
+  },
+  "RootService": {
+    "RootService": "RootService/service_name"
+  },
+  "RootServiceComponent": {
+    "RootService": "RootServiceComponents/service_name",
+    "RootServiceComponent": "RootServiceComponents/component_name"
+  },
+  "RootServiceHostComponent": {
+    "RootService": "RootServiceHostComponents/service_name",
+    "Host": "RootServiceHostComponents/host_name",
+    "RootServiceComponent": "RootServiceHostComponents/component_name",
+    "RootServiceHostComponent": "RootServiceHostComponents/component_name"
+  },
+  "ConfigGroup": {
+    "Cluster": "ConfigGroup/cluster_name",
+    "ConfigGroup": "ConfigGroup/id"
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/8b0e64c5/ambari-server/src/main/resources/properties.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/properties.json b/ambari-server/src/main/resources/properties.json
index fa04735..d7e77fe 100644
--- a/ambari-server/src/main/resources/properties.json
+++ b/ambari-server/src/main/resources/properties.json
@@ -85,9 +85,14 @@
         "ConfigGroup/desired_configs"
     ],
     "Action":[
-        "Actions/cluster_name",
-        "Actions/service_name",
         "Actions/action_name",
+        "Actions/action_type",
+        "Actions/inputs",
+        "Actions/target_service",
+        "Actions/target_component",
+        "Actions/description",
+        "Actions/target_type",
+        "Actions/default_timeout",
         "_"
     ],
     "Request":[

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/8b0e64c5/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionDBAccessorImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionDBAccessorImpl.java b/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionDBAccessorImpl.java
index c16e886..f3ca646 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionDBAccessorImpl.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionDBAccessorImpl.java
@@ -80,7 +80,7 @@ public class TestActionDBAccessorImpl {
     db = injector.getInstance(ActionDBAccessorImpl.class);
     
     am = new ActionManager(5000, 1200000, new ActionQueue(), clusters, db,
-        new HostsMap((String) null), null, injector.getInstance(UnitOfWork.class));
+        new HostsMap((String) null), null, injector.getInstance(UnitOfWork.class), null);
   }
 
   @After

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/8b0e64c5/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionManager.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionManager.java b/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionManager.java
index 70606e7..5af4fe5 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionManager.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionManager.java
@@ -86,7 +86,7 @@ public class TestActionManager {
   public void testActionResponse() {
     ActionDBAccessor db = injector.getInstance(ActionDBAccessorImpl.class);
     ActionManager am = new ActionManager(5000, 1200000, new ActionQueue(),
-        clusters, db, new HostsMap((String) null), null, unitOfWork);
+        clusters, db, new HostsMap((String) null), null, unitOfWork, null);
     populateActionDB(db, hostname);
     Stage stage = db.getAllStages(requestId).get(0);
     Assert.assertEquals(stageId, stage.getStageId());
@@ -122,7 +122,7 @@ public class TestActionManager {
   public void testLargeLogs() {
     ActionDBAccessor db = injector.getInstance(ActionDBAccessorImpl.class);
     ActionManager am = new ActionManager(5000, 1200000, new ActionQueue(),
-        clusters, db, new HostsMap((String) null), null, unitOfWork);
+        clusters, db, new HostsMap((String) null), null, unitOfWork, null);
     populateActionDB(db, hostname);
     Stage stage = db.getAllStages(requestId).get(0);
     Assert.assertEquals(stageId, stage.getStageId());
@@ -207,7 +207,7 @@ public class TestActionManager {
 
     replay(queue, db, clusters);
 
-    ActionManager manager = new ActionManager(0, 0, queue, clusters, db, null, null, unitOfWork);
+    ActionManager manager = new ActionManager(0, 0, queue, clusters, db, null, null, unitOfWork, null);
     assertSame(listStages, manager.getActions(requestId));
 
     verify(queue, db, clusters);

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/8b0e64c5/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionScheduler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionScheduler.java b/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionScheduler.java
index dbea0d7..dff78af 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionScheduler.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionScheduler.java
@@ -323,7 +323,7 @@ public class TestActionScheduler {
     ActionScheduler scheduler = new ActionScheduler(100, 50, db, aq, fsm, 3,
         new HostsMap((String) null), new ServerActionManagerImpl(fsm), unitOfWork);
     ActionManager am = new ActionManager(
-        2, 2, aq, fsm, db, new HostsMap((String) null), new ServerActionManagerImpl(fsm), unitOfWork);
+        2, 2, aq, fsm, db, new HostsMap((String) null), new ServerActionManagerImpl(fsm), unitOfWork, null);
 
     scheduler.doWork();
 
@@ -413,7 +413,7 @@ public class TestActionScheduler {
     ActionScheduler scheduler = new ActionScheduler(100, 10000, db, aq, fsm, 3,
         new HostsMap((String) null), new ServerActionManagerImpl(fsm), unitOfWork);
     ActionManager am = new ActionManager(
-        2, 10000, aq, fsm, db, new HostsMap((String) null), new ServerActionManagerImpl(fsm), unitOfWork);
+        2, 10000, aq, fsm, db, new HostsMap((String) null), new ServerActionManagerImpl(fsm), unitOfWork, null);
 
     scheduler.doWork();
 
@@ -527,7 +527,7 @@ public class TestActionScheduler {
     ActionScheduler scheduler = new ActionScheduler(100, 50, db, aq, fsm, 3,
         new HostsMap((String) null), new ServerActionManagerImpl(fsm), unitOfWork);
     ActionManager am = new ActionManager(
-        2, 2, aq, fsm, db, new HostsMap((String) null), new ServerActionManagerImpl(fsm), unitOfWork);
+        2, 2, aq, fsm, db, new HostsMap((String) null), new ServerActionManagerImpl(fsm), unitOfWork, null);
 
     scheduler.doWork();
 

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/8b0e64c5/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestCustomActionDBAccessorImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestCustomActionDBAccessorImpl.java b/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestCustomActionDBAccessorImpl.java
new file mode 100644
index 0000000..55d2021
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestCustomActionDBAccessorImpl.java
@@ -0,0 +1,124 @@
+/**
+ * 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.actionmanager;
+
+import com.google.inject.Guice;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.persist.PersistService;
+import junit.framework.Assert;
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.orm.GuiceJpaInitializer;
+import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
+import org.apache.ambari.server.orm.dao.ActionDefinitionDAO;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+public class TestCustomActionDBAccessorImpl {
+  private static final Logger log = LoggerFactory.getLogger(TestCustomActionDBAccessorImpl.class);
+  CustomActionDBAccessor db;
+  private Injector injector;
+  @Inject
+  private ActionDefinitionDAO actions;
+
+  @Before
+  public void setup() throws AmbariException {
+    injector = Guice.createInjector(new InMemoryDefaultTestModule());
+    injector.getInstance(GuiceJpaInitializer.class);
+    injector.injectMembers(this);
+    db = injector.getInstance(CustomActionDBAccessorImpl.class);
+  }
+
+  @After
+  public void tearDown() throws AmbariException {
+    injector.getInstance(PersistService.class).stop();
+  }
+
+  @Test
+  public void testActionLifeCycle() throws Exception {
+    try {
+      db.createActionDefinition(
+          "a1", ActionType.SYSTEM, "a,b,,c", "desc", TargetHostType.ANY, "HDFS", "DATANODE", Short.parseShort("70"));
+      Assert.fail("createActionDefinition must throw exception.");
+    } catch (AmbariException ex) {
+      Assert.assertTrue(ex.getMessage().contains("Empty parameter cannot be specified as an input parameter"));
+    }
+
+    db.createActionDefinition(
+        "a1", ActionType.SYSTEM, "fileName", "desc", TargetHostType.ANY, "HDFS", "DATANODE", Short.parseShort("70"));
+    ActionDefinition ad = db.getActionDefinition("a1");
+    assertContent(
+        ad, "a1", ActionType.SYSTEM, "fileName", "desc", TargetHostType.ANY, "HDFS", "DATANODE", Short.parseShort("70"));
+
+    ad = db.getActionDefinition("a2");
+    Assert.assertNull(ad);
+
+    try {
+      db.createActionDefinition(
+          "a1", ActionType.SYSTEM, "fileName", "desc", TargetHostType.ANY, "HDFS", "DATANODE", Short.parseShort("70"));
+      Assert.fail("updateActionDefinition must throw exception.");
+    } catch (AmbariException ex) {
+      Assert.assertTrue(ex.getMessage().contains("Action definition a1 already exists"));
+    }
+
+    db.createActionDefinition(
+        "a2", ActionType.SYSTEM, "dirName", "desc2", TargetHostType.ANY, "HDFS", "DATANODE", Short.parseShort("70"));
+    ad = db.getActionDefinition("a2");
+    assertContent(ad, "a2", ActionType.SYSTEM, "dirName", "desc2", TargetHostType.ANY,
+        "HDFS", "DATANODE", Short.parseShort("70"));
+
+    db.updateActionDefinition("a2", ActionType.USER, "desc3", TargetHostType.ALL, Short.parseShort("100"));
+    ad = db.getActionDefinition("a2");
+    assertContent(ad, "a2", ActionType.USER, "dirName", "desc3", TargetHostType.ALL,
+        "HDFS", "DATANODE", Short.parseShort("100"));
+
+    List<ActionDefinition> ads = db.getActionDefinitions();
+    Assert.assertEquals(2, ads.size());
+
+    db.deleteActionDefinition("a1");
+    ads = db.getActionDefinitions();
+    Assert.assertEquals(1, ads.size());
+
+    db.deleteActionDefinition("a1");
+
+    try {
+      db.updateActionDefinition("a1", ActionType.USER, "desc3", TargetHostType.ALL, Short.parseShort("100"));
+      Assert.fail("updateActionDefinition must throw exception.");
+    } catch (AmbariException ex) {
+      Assert.assertTrue(ex.getMessage().contains("Action definition a1 does not exist"));
+    }
+  }
+
+  private void assertContent(ActionDefinition ad, String actionName, ActionType actionType, String inputs,
+                             String description, TargetHostType targetType, String serviceType, String componentType,
+                             Short defaultTimeout) {
+    Assert.assertEquals(actionName, ad.getActionName());
+    Assert.assertEquals(actionType, ad.getActionType());
+    Assert.assertEquals(description, ad.getDescription());
+    Assert.assertEquals(inputs, ad.getInputs());
+    Assert.assertEquals(serviceType, ad.getTargetService());
+    Assert.assertEquals(componentType, ad.getTargetComponent());
+    Assert.assertEquals(defaultTimeout, ad.getDefaultTimeout());
+    Assert.assertEquals(targetType, ad.getTargetType());
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/8b0e64c5/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java b/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java
index d283b0c..ec5e399 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java
@@ -413,7 +413,7 @@ public class TestHeartbeatHandler {
     clusters.addCluster(DummyCluster);
     ActionDBAccessor db = injector.getInstance(ActionDBAccessorImpl.class);
     ActionManager am = new ActionManager(5000, 1200000, new ActionQueue(), clusters, db,
-        new HostsMap((String) null), null, unitOfWork);
+        new HostsMap((String) null), null, unitOfWork, null);
     populateActionDB(db, DummyHostname1);
     Stage stage = db.getAllStages(requestId).get(0);
     Assert.assertEquals(stageId, stage.getStageId());
@@ -1310,7 +1310,7 @@ public class TestHeartbeatHandler {
 
   private ActionManager getMockActionManager() {
     return new ActionManager(0, 0, null, null,
-              new ActionDBInMemoryImpl(), new HostsMap((String) null), null, unitOfWork);
+              new ActionDBInMemoryImpl(), new HostsMap((String) null), null, unitOfWork, null);
   }
 
 

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/8b0e64c5/ambari-server/src/test/java/org/apache/ambari/server/api/services/ActionServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ActionServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ActionServiceTest.java
index fa47d90..934bc31 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ActionServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ActionServiceTest.java
@@ -15,65 +15,73 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.ambari.server.api.services;
-
-import static org.junit.Assert.assertEquals;
 
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.UriInfo;
+package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
 
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.UriInfo;
+
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
 
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Unit tests for ServiceService.
+ */
 public class ActionServiceTest extends BaseServiceTest {
 
   public List<ServiceTestInvocation> getTestInvocations() throws Exception {
     List<ServiceTestInvocation> listInvocations = new ArrayList<ServiceTestInvocation>();
 
-    //getActions
-    ActionService componentService = new TestActionService("clusterName", "serviceName", null);
-    Method m = componentService.getClass().getMethod("getActions", HttpHeaders.class, UriInfo.class);
-    Object[] args = new Object[] {getHttpHeaders(), getUriInfo()};
-    listInvocations.add(new ServiceTestInvocation(Request.Type.GET, componentService, m, args, null));
+    //getActionDefinition
+    ActionService service = new TestActionDefinitionService("actionName");
+    Method m = service.getClass().getMethod("getActionDefinition", HttpHeaders.class, UriInfo.class, String.class);
+    Object[] args = new Object[] {getHttpHeaders(), getUriInfo(), "actionName"};
+    listInvocations.add(new ServiceTestInvocation(Request.Type.GET, service, m, args, null));
+
+    //getActionDefinitions
+    service = new TestActionDefinitionService(null);
+    m = service.getClass().getMethod("getActionDefinitions", HttpHeaders.class, UriInfo.class);
+    args = new Object[] {getHttpHeaders(), getUriInfo()};
+    listInvocations.add(new ServiceTestInvocation(Request.Type.GET, service, m, args, null));
+
+    //createActionDefinition
+    service = new TestActionDefinitionService("actionName");
+    m = service.getClass().getMethod("createActionDefinition", String.class, HttpHeaders.class, UriInfo.class, String.class);
+    args = new Object[] {"body", getHttpHeaders(), getUriInfo(), "actionName"};
+    listInvocations.add(new ServiceTestInvocation(Request.Type.POST, service, m, args, "body"));
 
-    //createAction
-    componentService = new TestActionService("clusterName", "serviceName", "actionName");
-    m = componentService.getClass().getMethod("createAction", String.class, HttpHeaders.class, UriInfo.class, String.class);
+    //updateActionDefinition
+    service = new TestActionDefinitionService("actionName");
+    m = service.getClass().getMethod("updateActionDefinition", String.class, HttpHeaders.class, UriInfo.class, String.class);
     args = new Object[] {"body", getHttpHeaders(), getUriInfo(), "actionName"};
-    listInvocations.add(new ServiceTestInvocation(Request.Type.POST, componentService, m, args, "body"));
+    listInvocations.add(new ServiceTestInvocation(Request.Type.PUT, service, m, args, "body"));
 
-    //createActions
-    componentService = new TestActionService("clusterName", "serviceName", null);
-    m = componentService.getClass().getMethod("createActions", String.class, HttpHeaders.class, UriInfo.class);
-    args = new Object[] {"body", getHttpHeaders(), getUriInfo()};
-    listInvocations.add(new ServiceTestInvocation(Request.Type.POST, componentService, m, args, "body"));
+    //deleteActionDefinition
+    service = new TestActionDefinitionService("actionName");
+    m = service.getClass().getMethod("deleteActionDefinition", HttpHeaders.class, UriInfo.class, String.class);
+    args = new Object[] {getHttpHeaders(), getUriInfo(), "actionName"};
+    listInvocations.add(new ServiceTestInvocation(Request.Type.DELETE, service, m, args, null));
 
     return listInvocations;
   }
 
-  private class TestActionService extends ActionService {
-    private String m_clusterId;
-    private String m_serviceId;
-    private String m_actionId;
-
-    public TestActionService(String clusterName, String serviceName, String actionName) {
+  private class TestActionDefinitionService extends ActionService {
+    private String m_actionName;
 
-      super(clusterName, serviceName);
-      m_clusterId = clusterName;
-      m_serviceId = serviceName;
-      m_actionId  = actionName;
+    private TestActionDefinitionService(String actionName) {
+      m_actionName = actionName;
     }
 
     @Override
-    ResourceInstance createActionResource(String clusterName, String serviceName, String actionName) {
-      assertEquals(m_clusterId, clusterName);
-      assertEquals(m_serviceId, serviceName);
-      assertEquals(m_actionId, actionName);
+    ResourceInstance createActionDefinitionResource(String actionName) {
+      assertEquals(m_actionName, actionName);
       return getTestResource();
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/8b0e64c5/ambari-server/src/test/java/org/apache/ambari/server/controller/ActionRequestTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/ActionRequestTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/ActionRequestTest.java
new file mode 100644
index 0000000..33ef2ac
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/ActionRequestTest.java
@@ -0,0 +1,53 @@
+/**
+ * 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.controller;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ActionRequestTest {
+
+  @Test
+  public void testBasicGetAndSet() {
+    ActionRequest adr1 =
+        new ActionRequest("a1", "SYSTEM", "fileName", "HDFS", "DATANODE", "Desc1", "Any", "100");
+
+    Assert.assertEquals("a1", adr1.getActionName());
+    Assert.assertEquals("SYSTEM", adr1.getActionType());
+    Assert.assertEquals("fileName", adr1.getInputs());
+    Assert.assertEquals("HDFS", adr1.getTargetService());
+    Assert.assertEquals("DATANODE", adr1.getTargetComponent());
+    Assert.assertEquals("Desc1", adr1.getDescription());
+    Assert.assertEquals("Any", adr1.getTargetType());
+    Assert.assertEquals("100", adr1.getDefaultTimeout());
+
+    adr1.setDescription("Desc2");
+    adr1.setActionType("USER");
+
+    Assert.assertEquals("Desc2", adr1.getDescription());
+    Assert.assertEquals("USER", adr1.getActionType());
+  }
+
+  @Test
+  public void testToString() {
+    ActionRequest r1 = ActionRequest.getAllRequest();
+    r1.toString();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/8b0e64c5/ambari-server/src/test/java/org/apache/ambari/server/controller/ActionResponseTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/ActionResponseTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/ActionResponseTest.java
new file mode 100644
index 0000000..4b3c858
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/ActionResponseTest.java
@@ -0,0 +1,46 @@
+package org.apache.ambari.server.controller;
+
+/**
+ * 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.
+ */
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ActionResponseTest {
+
+  @Test
+  public void testBasicGetAndSet() {
+    ActionResponse r1 =
+        new ActionResponse("a1", "SYSTEM", "fileName", "HDFS", "DATANODE", "Desc1", "Any", "100");
+    
+    Assert.assertEquals("a1", r1.getActionName());
+    Assert.assertEquals("SYSTEM", r1.getActionType());
+    Assert.assertEquals("fileName", r1.getInputs());
+    Assert.assertEquals("HDFS", r1.getTargetService());
+    Assert.assertEquals("DATANODE", r1.getTargetComponent());
+    Assert.assertEquals("Desc1", r1.getDescription());
+    Assert.assertEquals("Any", r1.getTargetType());
+    Assert.assertEquals("100", r1.getDefaultTimeout());
+  }
+
+  @Test
+  public void testToString() {
+    ActionResponse r = new ActionResponse(null, null, null, null, null, null, null, null);
+    r.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/8b0e64c5/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
index b9d6d86..f014cdf 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
@@ -43,6 +43,7 @@ import org.apache.ambari.server.actionmanager.Stage;
 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.controller.internal.ActionResourceProviderTest;
 import org.apache.ambari.server.controller.internal.ComponentResourceProviderTest;
 import org.apache.ambari.server.controller.internal.HostResourceProviderTest;
 import org.apache.ambari.server.controller.internal.ServiceResourceProviderTest;
@@ -3442,16 +3443,104 @@ public class AmbariManagementControllerTest {
 
   @SuppressWarnings("serial")
   @Test
-  public void testGetActions() throws Exception {
-    Set<ActionResponse> responses = controller.getActions(
-        new HashSet<ActionRequest>() {{
-          add(new ActionRequest(null, "HDFS", null, null));
-    }});
+  public void testCreateActionsFailures() throws Exception {
+    clusters.addCluster("c1");
+    clusters.getCluster("c1").setDesiredStackVersion(new StackId("HDP-0.1"));
+    clusters.addHost("h1");
+    clusters.getHost("h1").setOsType("centos5");
+    clusters.getHost("h1").persist();
+    Set<String> hostNames = new HashSet<String>(){{
+      add("h1");
+    }};
+
+    clusters.mapHostsToCluster(hostNames, "c1");
+
+    Cluster cluster = clusters.getCluster("c1");
+    cluster.setDesiredStackVersion(new StackId("HDP-0.1"));
+    cluster.setCurrentStackVersion(new StackId("HDP-0.1"));
+
+    ConfigFactory cf = injector.getInstance(ConfigFactory.class);
+    Config config1 = cf.createNew(cluster, "global",
+        new HashMap<String, String>(){{ put("key1", "value1"); }});
+    config1.setVersionTag("version1");
+
+    Config config2 = cf.createNew(cluster, "core-site",
+        new HashMap<String, String>(){{ put("key1", "value1"); }});
+    config2.setVersionTag("version1");
+
+    cluster.addConfig(config1);
+    cluster.addConfig(config2);
+    cluster.addDesiredConfig("_test", config1);
+    cluster.addDesiredConfig("_test", config2);
+
+    Service hdfs = cluster.addService("HDFS");
+    hdfs.persist();
+
+    hdfs.addServiceComponent(Role.HDFS_CLIENT.name()).persist();
+    hdfs.addServiceComponent(Role.NAMENODE.name()).persist();
+    hdfs.addServiceComponent(Role.DATANODE.name()).persist();
+
+    hdfs.getServiceComponent(Role.HDFS_CLIENT.name()).addServiceComponentHost("h1").persist();
+    hdfs.getServiceComponent(Role.NAMENODE.name()).addServiceComponentHost("h1").persist();
+    hdfs.getServiceComponent(Role.DATANODE.name()).addServiceComponentHost("h1").persist();
+
+    Map<String, String> params = new HashMap<String, String>() {{
+      put("test", "test");
+    }};
+    ExecuteActionRequest actionRequest = new ExecuteActionRequest("c1", "NON_EXISTENT_CHECK", "HDFS", params);
+
+    Map<String, String> requestProperties = new HashMap<String, String>();
+    requestProperties.put(REQUEST_CONTEXT_PROPERTY, "Called from a test");
+
+    try {
+      controller.createAction(actionRequest, requestProperties);
+      Assert.fail("createAction should fail for NON_EXISTENT_CHECK");
+    } catch (AmbariException ex) {
+      Assert.assertTrue(ex.getMessage().contains("Unsupported action"));
+    }
+
+    actionRequest = new ExecuteActionRequest("c1", "NON_EXISTENT_SERVICE_CHECK", "HDFS", params);
+    try {
+      controller.createAction(actionRequest, requestProperties);
+      Assert.fail("createAction should fail for NON_EXISTENT_SERVICE_CHECK");
+    } catch (AmbariException ex) {
+      Assert.assertTrue(ex.getMessage().contains("Unsupported action"));
+    }
 
-    assertFalse(responses.isEmpty());
-    assertEquals(1, responses.size());
-    ActionResponse response = responses.iterator().next();
-    assertEquals(Role.HDFS_SERVICE_CHECK.name(), response.getActionName());
+    actionRequest = new ExecuteActionRequest("c1", "DECOMMISSION_DATANODE", "MAPREDUCE", params);
+    try {
+      controller.createAction(actionRequest, requestProperties);
+      Assert.fail("createAction should fail for DECOMMISSION_DATANODE on MAPREDUCE");
+    } catch (AmbariException ex) {
+      Assert.assertTrue(ex.getMessage().contains("Unsupported action DECOMMISSION_DATANODE for MAPREDUCE"));
+    }
+
+    actionRequest = new ExecuteActionRequest("c1", "DECOMMISSION_DATANODE", "HDFS", params);
+    try {
+      controller.createAction(actionRequest, requestProperties);
+      Assert.fail("createAction should fail for DECOMMISSION_DATANODE on HDFS - no excludeFileTag");
+    } catch (IllegalArgumentException ex) {
+      Assert.assertTrue(ex.getMessage().contains("No exclude file specified when decommissioning datanodes"));
+    }
+
+    params.put("excludeFileTag", "tag1");
+    actionRequest = new ExecuteActionRequest("c1", "DECOMMISSION_DATANODE", "HDFS", params);
+    try {
+      controller.createAction(actionRequest, requestProperties);
+      Assert.fail("createAction should fail for DECOMMISSION_DATANODE on HDFS - no config type hdfs-exclude-file");
+    } catch (AmbariException ex) {
+      Assert.assertTrue(ex.getMessage().contains("Decommissioning datanodes requires the cluster"));
+    }
+
+    actionRequest = new ExecuteActionRequest("c1", null, "DECOMMISSION_DATANODE", "HDFS", null, null, params);
+    try {
+      RequestStatusResponse response = controller.createAction(actionRequest, requestProperties);
+      if (response != null) {
+        Assert.fail("createAction should fail for action DECOMMISSION_DATANODE");
+      }
+    } catch (AmbariException ex) {
+      Assert.assertTrue(ex.getMessage().contains("Invalid action request"));
+    }
   }
 
   @SuppressWarnings("serial")
@@ -3501,17 +3590,15 @@ public class AmbariManagementControllerTest {
     hdfs.getServiceComponent(Role.HDFS_CLIENT.name()).addServiceComponentHost("h1").persist();
     mapReduce.getServiceComponent(Role.MAPREDUCE_CLIENT.name()).addServiceComponentHost("h2").persist();
 
-    Set<ActionRequest> actionRequests = new HashSet<ActionRequest>();
-    Map<String, String> params = new HashMap<String, String>(){{
+    Map<String, String> params = new HashMap<String, String>() {{
       put("test", "test");
     }};
-    ActionRequest actionRequest = new ActionRequest("c1", "HDFS", Role.HDFS_SERVICE_CHECK.name(), params);
-    actionRequests.add(actionRequest);
-    
+    ExecuteActionRequest actionRequest = new ExecuteActionRequest("c1", Role.HDFS_SERVICE_CHECK.name(), "HDFS", params);
+
     Map<String, String> requestProperties = new HashMap<String, String>();
     requestProperties.put(REQUEST_CONTEXT_PROPERTY, "Called from a test");
 
-    RequestStatusResponse response = controller.createActions(actionRequests, requestProperties);
+    RequestStatusResponse response = controller.createAction(actionRequest, requestProperties);
     
     assertEquals(1, response.getTasks().size());
     ShortTaskStatus task = response.getTasks().get(0);
@@ -3534,26 +3621,26 @@ public class AmbariManagementControllerTest {
     assertEquals(task.getTaskId(), hostRoleCommand.getTaskId());
     assertEquals(actionRequest.getServiceName(), hostRoleCommand.getExecutionCommandWrapper().getExecutionCommand().getServiceName());
     assertEquals(actionRequest.getClusterName(), hostRoleCommand.getExecutionCommandWrapper().getExecutionCommand().getClusterName());
-    assertEquals(actionRequest.getActionName(), hostRoleCommand.getExecutionCommandWrapper().getExecutionCommand().getRole());
+    assertEquals(actionRequest.getCommandName(), hostRoleCommand.getExecutionCommandWrapper().getExecutionCommand().getRole());
     assertEquals(Role.HDFS_CLIENT.name(), hostRoleCommand.getEvent().getEvent().getServiceComponentName());
     assertEquals(actionRequest.getParameters(), hostRoleCommand.getExecutionCommandWrapper().getExecutionCommand().getRoleParams());
     assertNotNull(hostRoleCommand.getExecutionCommandWrapper().getExecutionCommand().getConfigurations());
     assertEquals(2, hostRoleCommand.getExecutionCommandWrapper().getExecutionCommand().getConfigurations().size());
     assertEquals(requestProperties.get(REQUEST_CONTEXT_PROPERTY), stage.getRequestContext());
-    actionRequests.add(new ActionRequest("c1", "MAPREDUCE", Role.MAPREDUCE_SERVICE_CHECK.name(), null));
+    actionRequest = new ExecuteActionRequest("c1", Role.MAPREDUCE_SERVICE_CHECK.name(), "MAPREDUCE", null);
 
-    response = controller.createActions(actionRequests, requestProperties);
+    response = controller.createAction(actionRequest, requestProperties);
 
-    assertEquals(2, response.getTasks().size());
+    assertEquals(1, response.getTasks().size());
 
     List<HostRoleCommand> tasks = actionDB.getRequestTasks(response.getRequestId());
 
-    assertEquals(2, tasks.size());
+    assertEquals(1, tasks.size());
 
     requestProperties.put(REQUEST_CONTEXT_PROPERTY, null);
-    response = controller.createActions(actionRequests, requestProperties);
+    response = controller.createAction(actionRequest, requestProperties);
 
-    assertEquals(2, response.getTasks().size());
+    assertEquals(1, response.getTasks().size());
   }
 
   private void createUser(String userName) throws Exception {
@@ -5038,12 +5125,11 @@ public class AmbariManagementControllerTest {
     }
     Assert.assertEquals("Expect only one service check.", 1, commandCount);
 
-    Set<ActionRequest> actionRequests = new HashSet<ActionRequest>();
-    ActionRequest actionRequest = new ActionRequest("foo1", "HDFS", Role.HDFS_SERVICE_CHECK.name(), null);
-    actionRequests.add(actionRequest);
+    ExecuteActionRequest actionRequest = new ExecuteActionRequest("foo1", Role.HDFS_SERVICE_CHECK.name(),
+        null, "HDFS", null, null, null);
     Map<String, String> requestProperties = new HashMap<String, String>();
 
-    RequestStatusResponse response = controller.createActions(actionRequests, requestProperties);
+    RequestStatusResponse response = controller.createAction(actionRequest, requestProperties);
     commands = actionDB.getRequestTasks(response.getRequestId());
     commandCount = 0;
     for(HostRoleCommand command : commands) {
@@ -5058,7 +5144,7 @@ public class AmbariManagementControllerTest {
     // When both are unhealthy then just pick one
     clusters.getHost("h3").setState(HostState.WAITING_FOR_HOST_STATUS_UPDATES);
     clusters.getHost("h2").setState(HostState.INIT);
-    response = controller.createActions(actionRequests, requestProperties);
+    response = controller.createAction(actionRequest, requestProperties);
     commands = actionDB.getRequestTasks(response.getRequestId());
     commandCount = 0;
     for(HostRoleCommand command : commands) {
@@ -5436,19 +5522,16 @@ public class AmbariManagementControllerTest {
     Service s = cluster.getService(serviceName);
     Assert.assertEquals(State.STARTED, s.getDesiredState());
 
-    Set<ActionRequest> requests = new HashSet<ActionRequest>();
     Map<String, String> params = new HashMap<String, String>(){{
       put("test", "test");
+      put("excludeFileTag", "tag1");
     }};
-    ActionRequest request = new ActionRequest(clusterName, "HDFS",
-      Role.DECOMMISSION_DATANODE.name(), params);
-    params.put("excludeFileTag", "tag1");
-    requests.add(request);
+    ExecuteActionRequest request = new ExecuteActionRequest(clusterName, Role.DECOMMISSION_DATANODE.name(), "HDFS", params);
 
     Map<String, String> requestProperties = new HashMap<String, String>();
     requestProperties.put(REQUEST_CONTEXT_PROPERTY, "Called from a test");
 
-    RequestStatusResponse response = controller.createActions(requests,
+    RequestStatusResponse response = controller.createAction(request,
       requestProperties);
 
     List<HostRoleCommand> storedTasks = actionDB.getRequestTasks(response.getRequestId());
@@ -7488,8 +7571,8 @@ public class AmbariManagementControllerTest {
 
       amc.createHostComponents(componentHostRequests);
 
-      ActionRequest ar = new ActionRequest(CLUSTER_NAME, "HDFS", Role.HDFS_SERVICE_CHECK.name(), new HashMap<String, String>());
-      amc.createActions(Collections.singleton(ar), null);
+      ExecuteActionRequest ar = new ExecuteActionRequest(CLUSTER_NAME, Role.HDFS_SERVICE_CHECK.name(), "HDFS", null);
+      amc.createAction(ar, null);
 
       // change mind, delete the cluster
       amc.deleteCluster(cr);
@@ -7805,6 +7888,108 @@ public class AmbariManagementControllerTest {
     }
   }
 
+ @Test
+ public void testActionDefinitionLifeCycle() throws Exception {
+   ActionRequest createRequest1 =
+       new ActionRequest("a1", "SYSTEM", "fileName", "HDFS", "DATANODE", "Does file exist", "ANY", "100");
+   ActionResourceProviderTest.createAction(controller, createRequest1);
+
+   ActionRequest getAllRequest = ActionRequest.getAllRequest();
+   Set<ActionResponse> responses = ActionResourceProviderTest.getActions(controller,
+       Collections.singleton(getAllRequest));
+   Assert.assertEquals(1, responses.size());
+
+   ActionRequest createRequest2 =
+       new ActionRequest("a2", "USER", "fileName", "YARN", "NODEMANAGER", "Does file exist", "ANY", "100");
+   ActionResourceProviderTest.createAction(controller, createRequest2);
+
+   responses = ActionResourceProviderTest.getActions(controller, Collections.singleton
+       (getAllRequest));
+   Assert.assertEquals(2, responses.size());
+
+   ActionRequest updateRequest =
+       new ActionRequest("a2", "USER", null, null, null, "Does file really exist", "ANY", "100");
+   RequestStatusResponse response = ActionResourceProviderTest.updateAction(controller,
+       Collections.singleton(updateRequest), null);
+   Assert.assertNull(response);
+
+   ActionRequest getOneRequest =
+       new ActionRequest("a2", null, null, null, null, null, null, null);
+   responses = ActionResourceProviderTest.getActions(controller, Collections.singleton
+       (getOneRequest));
+   Assert.assertEquals(1, responses.size());
+   Assert.assertEquals("Does file really exist", responses.iterator().next().getDescription());
+
+   ActionResourceProviderTest.deleteAction(controller, getOneRequest);
+   responses = ActionResourceProviderTest.getActions(controller, Collections.singleton
+       (getOneRequest));
+   Assert.assertEquals(0, responses.size());
+ }
+
+  @Test
+  public void testActionDefinitionErrors() throws Exception {
+    ActionRequest createRequest =
+        new ActionRequest(null, "SYSTEM", "fileName", "HDFS", "DATANODE", "Does file exist", "ANY", "100");
+    try {
+      ActionResourceProviderTest.createAction(controller, createRequest);
+      Assert.fail("Exception must be thrown");
+    } catch (Exception ex) {
+      LOG.info(ex.getMessage());
+      Assert.assertTrue(ex.getMessage().contains("Action name should be provided"));
+    }
+
+    createRequest =
+        new ActionRequest("a1", "SYSTEM", "fileName", "HDFS", "DATANODE", "Does file exist", "ANY", "10000");
+    try {
+      ActionResourceProviderTest.createAction(controller, createRequest);
+      Assert.fail("Exception must be thrown");
+    } catch (Exception ex) {
+      LOG.info(ex.getMessage());
+      Assert.assertTrue(ex.getMessage().contains("Default timeout should be between 60 and 600"));
+    }
+
+    createRequest =
+        new ActionRequest("a1", "Favorite", "", "HDFS", "", "Does file exist", "ANY", "100");
+    try {
+      ActionResourceProviderTest.createAction(controller, createRequest);
+      Assert.fail("Exception must be thrown");
+    } catch (Exception ex) {
+      LOG.info(ex.getMessage());
+      Assert.assertTrue(ex.getMessage().contains("No enum const class"));
+    }
+
+    createRequest =
+        new ActionRequest("a1", "SYSTEM", "", "HDFS", "", "", "ANY", "100");
+    try {
+      ActionResourceProviderTest.createAction(controller, createRequest);
+      Assert.fail("Exception must be thrown");
+    } catch (Exception ex) {
+      LOG.info(ex.getMessage());
+      Assert.assertTrue(ex.getMessage().contains("Action description cannot be empty"));
+    }
+
+    createRequest =
+        new ActionRequest("a1", "SYSTEM", "", "HDFS", "", "SS", "ANY", "100");
+    try {
+      ActionResourceProviderTest.createAction(controller, createRequest);
+      ActionResourceProviderTest.createAction(controller, createRequest);
+      Assert.fail("Exception must be thrown");
+    } catch (Exception ex) {
+      LOG.info(ex.getMessage());
+      Assert.assertTrue(ex.getMessage().contains("Action definition a1 already exists"));
+    }
+
+    createRequest =
+        new ActionRequest("a1", "SYSTEM", "", "HDFS", "", "SS", "Any", "100");
+    try {
+      ActionResourceProviderTest.createAction(controller, createRequest);
+      Assert.fail("Exception must be thrown");
+    } catch (Exception ex) {
+      LOG.info(ex.getMessage());
+      Assert.assertTrue(ex.getMessage().contains("No enum const class"));
+    }
+  }
+
   @Test
   public void testScheduleSmokeTest() throws Exception {
 

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/8b0e64c5/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AbstractResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AbstractResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AbstractResourceProviderTest.java
index de2ddcb..bc6561c 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AbstractResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AbstractResourceProviderTest.java
@@ -202,13 +202,6 @@ public class AbstractResourceProviderTest {
       return null;
     }
 
-    public static Set<ActionRequest> getActionRequestSet(String clusterName, String serviceName, String actionName)
-    {
-      EasyMock.reportMatcher(new ActionRequestSetMatcher(clusterName, serviceName, actionName));
-      return null;
-    }
-
-
     public static Set<HostRequest> getHostRequestSet(String hostname, String clusterName,
                                                      Map<String, String> hostAttributes)
     {
@@ -329,44 +322,6 @@ public class AbstractResourceProviderTest {
     }
   }
 
-  /**
-   * Matcher for a ActionRequest set containing a single request.
-   */
-  public static class ActionRequestSetMatcher extends HashSet<ActionRequest> implements IArgumentMatcher {
-
-    private final ActionRequest actionRequest;
-
-    public ActionRequestSetMatcher(String clusterName, String serviceName, String actionName) {
-      this.actionRequest = new ActionRequest(clusterName, serviceName, actionName, null);
-      add(this.actionRequest);
-    }
-
-    @Override
-    public boolean matches(Object o) {
-      if (!(o instanceof Set)) {
-        return false;
-      }
-
-      Set set = (Set) o;
-
-      if (set.size() != 1) {
-        return false;
-      }
-
-      Object request = set.iterator().next();
-
-      return request instanceof ActionRequest &&
-          eq(((ActionRequest) request).getClusterName(), actionRequest.getClusterName()) &&
-          eq(((ActionRequest) request).getServiceName(), actionRequest.getServiceName()) &&
-          eq(((ActionRequest) request).getActionName(), actionRequest.getActionName());
-    }
-
-    @Override
-    public void appendTo(StringBuffer stringBuffer) {
-      stringBuffer.append("ActionRequestSetMatcher(").append(actionRequest).append(")");
-    }
-  }
-
 
   /**
    * Matcher for a HostRequest set containing a single request.


Mime
View raw message