You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by dm...@apache.org on 2013/11/26 21:57:49 UTC

[8/8] git commit: AMBARI-3548. Changes to stacks definitions to allow custom services support (needed by an ambari-agent) (dlysnichenko)

AMBARI-3548. Changes to stacks definitions to allow custom services support (needed by an ambari-agent) (dlysnichenko)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/cc49fb9e
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/cc49fb9e
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/cc49fb9e

Branch: refs/heads/trunk
Commit: cc49fb9e651cb647e20c7187d66b674d81d2c185
Parents: 8d1da2d
Author: Lisnichenko Dmitro <dl...@hortonworks.com>
Authored: Tue Nov 26 22:55:53 2013 +0200
Committer: Lisnichenko Dmitro <dl...@hortonworks.com>
Committed: Tue Nov 26 22:55:53 2013 +0200

----------------------------------------------------------------------
 .../ambari_agent/CustomServiceOrchestrator.py   |    2 +-
 .../src/main/python/ambari_agent/FileCache.py   |    3 +-
 .../TestCustomServiceOrchestrator.py            |    2 +-
 .../test/python/ambari_agent/TestFileCache.py   |    3 +-
 .../org/apache/ambari/server/RoleCommand.java   |    1 +
 .../server/actionmanager/ActionScheduler.java   |    4 +-
 .../ambari/server/actionmanager/HostAction.java |  104 -
 .../server/actionmanager/HostRoleCommand.java   |    1 -
 .../ambari/server/actionmanager/Stage.java      |    5 +
 .../ambari/server/agent/ExecutionCommand.java   |   30 +
 .../server/api/services/AmbariMetaInfo.java     |   25 +-
 .../server/api/util/StackExtensionHelper.java   |  207 +-
 .../controller/AmbariActionExecutionHelper.java |    6 +-
 .../AmbariCustomCommandExecutionHelper.java     |  256 +-
 .../AmbariCustomCommandExecutionHelperImpl.java |  471 ++
 .../controller/AmbariManagementController.java  |   41 +
 .../AmbariManagementControllerImpl.java         |  238 +-
 .../server/controller/ControllerModule.java     |    1 +
 .../server/metadata/RoleCommandOrder.java       |   24 +-
 .../server/state/CommandScriptDefinition.java   |   44 +
 .../ambari/server/state/ComponentInfo.java      |   29 +-
 .../server/state/CustomCommandDefinition.java   |   39 +
 .../apache/ambari/server/state/ServiceInfo.java |  124 +-
 .../ambari/server/state/ServiceOsSpecific.java  |  122 +
 .../state/stack/ServiceMetainfoV2Xml.java       |   51 +
 .../apache/ambari/server/utils/StageUtils.java  |   19 +-
 .../src/main/resources/role_command_order.json  |   36 +-
 .../stacks/HDP/2.0.6/role_command_order.json    |   36 +-
 .../stacks/HDP/2.0.8/role_command_order.json    |   36 +-
 .../resources/stacks/HDP/2.0._/metainfo.xml     |   22 +
 .../stacks/HDP/2.0._/repos/repoinfo.xml         |   75 +
 .../stacks/HDP/2.0._/role_command_order.json    |  100 +
 .../HDP/2.0._/services/GANGLIA/metainfo.xml     |   36 +
 .../services/HBASE/configuration/global.xml     |  160 +
 .../HBASE/configuration/hbase-policy.xml        |   53 +
 .../services/HBASE/configuration/hbase-site.xml |  356 +
 .../HDP/2.0._/services/HBASE/metainfo.xml       |   38 +-
 .../HBASE/package/scripts/service_check.py      |    2 +-
 .../HDP/2.0._/services/HCATALOG/metainfo.xml    |   30 +
 .../services/HDFS/configuration/core-site.xml   |  167 +
 .../services/HDFS/configuration/global.xml      |  192 +
 .../HDFS/configuration/hadoop-policy.xml        |  134 +
 .../services/HDFS/configuration/hdfs-site.xml   |  484 ++
 .../stacks/HDP/2.0._/services/HDFS/metainfo.xml |   60 +
 .../stacks/HDP/2.0._/services/HDFS/metrics.json | 7790 ++++++++++++++++++
 .../services/HIVE/configuration/hive-site.xml   |  260 +
 .../stacks/HDP/2.0._/services/HIVE/metainfo.xml |   45 +
 .../configuration/container-executor.cfg        |   20 +
 .../MAPREDUCE2/configuration/core-site.xml      |   20 +
 .../MAPREDUCE2/configuration/global.xml         |   44 +
 .../configuration/mapred-queue-acls.xml         |   39 +
 .../MAPREDUCE2/configuration/mapred-site.xml    |  381 +
 .../HDP/2.0._/services/MAPREDUCE2/metainfo.xml  |   37 +
 .../HDP/2.0._/services/MAPREDUCE2/metrics.json  |  383 +
 .../HDP/2.0._/services/NAGIOS/metainfo.xml      |   30 +
 .../services/OOZIE/configuration/oozie-site.xml |  313 +
 .../HDP/2.0._/services/OOZIE/metainfo.xml       |   38 +
 .../services/PIG/configuration/pig.properties   |   52 +
 .../stacks/HDP/2.0._/services/PIG/metainfo.xml  |   30 +
 .../HDP/2.0._/services/SQOOP/metainfo.xml       |   30 +
 .../WEBHCAT/configuration/webhcat-site.xml      |  126 +
 .../HDP/2.0._/services/WEBHCAT/metainfo.xml     |   31 +
 .../YARN/configuration/capacity-scheduler.xml   |  120 +
 .../YARN/configuration/container-executor.cfg   |   20 +
 .../services/YARN/configuration/core-site.xml   |   20 +
 .../services/YARN/configuration/global.xml      |   64 +
 .../services/YARN/configuration/yarn-site.xml   |  326 +
 .../stacks/HDP/2.0._/services/YARN/metainfo.xml |   42 +
 .../stacks/HDP/2.0._/services/YARN/metrics.json | 2494 ++++++
 .../services/ZOOKEEPER/configuration/global.xml |   75 +
 .../HDP/2.0._/services/ZOOKEEPER/metainfo.xml   |   35 +
 .../server/api/services/AmbariMetaInfoTest.java |    2 +
 .../api/util/StackExtensionHelperTest.java      |  161 +
 .../AmbariManagementControllerTest.java         |   10 +-
 .../ambari/server/metadata/RoleGraphTest.java   |    6 +-
 .../stacks/HDP/2.0.6/role_command_order.json    |   36 +-
 .../resources/stacks/HDP/2.0.7/metainfo.xml     |   24 +
 .../stacks/HDP/2.0.7/repos/repoinfo.xml         |   61 +
 .../stacks/HDP/2.0.7/role_command_order.json    |  100 +
 .../services/HBASE/configuration/global.xml     |  160 +
 .../HBASE/configuration/hbase-policy.xml        |   53 +
 .../services/HBASE/configuration/hbase-site.xml |  356 +
 .../HDP/2.0.7/services/HBASE/metainfo.xml       |  116 +
 .../HDP/2.0.7/services/HBASE/scripts/hbase.py   |    1 +
 .../services/HBASE/scripts/hbase_client.py      |    1 +
 .../services/HBASE/scripts/hbase_master.py      |    1 +
 .../HBASE/scripts/hbase_regionserver.py         |    1 +
 .../services/YARN/configuration/yarn-site.xml   |   60 +
 .../stacks/HDP/2.0.7/services/YARN/metainfo.xml |   45 +
 89 files changed, 17219 insertions(+), 709 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/cc49fb9e/ambari-agent/src/main/python/ambari_agent/CustomServiceOrchestrator.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/CustomServiceOrchestrator.py b/ambari-agent/src/main/python/ambari_agent/CustomServiceOrchestrator.py
index b568335..6c86858 100644
--- a/ambari-agent/src/main/python/ambari_agent/CustomServiceOrchestrator.py
+++ b/ambari-agent/src/main/python/ambari_agent/CustomServiceOrchestrator.py
@@ -84,7 +84,7 @@ class CustomServiceOrchestrator():
     """
     Incapsulates logic of script location determination.
     """
-    path = os.path.join(base_dir, "package", script)
+    path = os.path.join(base_dir, script)
     if not os.path.exists(path):
       message = "Script {0} does not exist".format(path)
       raise AgentException(message)

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc49fb9e/ambari-agent/src/main/python/ambari_agent/FileCache.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/FileCache.py b/ambari-agent/src/main/python/ambari_agent/FileCache.py
index c02f217..27c4030 100644
--- a/ambari-agent/src/main/python/ambari_agent/FileCache.py
+++ b/ambari-agent/src/main/python/ambari_agent/FileCache.py
@@ -46,7 +46,8 @@ class FileCache():
     Returns a base directory for service
     """
     metadata_path = os.path.join(self.cache_dir, "stacks", str(stack_name),
-                                 str(stack_version), "services", str(service))
+                                 str(stack_version), "services", str(service),
+                                 "package")
     if not os.path.isdir(metadata_path):
       # TODO: Metadata downloading will be implemented at Phase 2
       # As of now, all stack definitions are packaged and distributed with

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc49fb9e/ambari-agent/src/test/python/ambari_agent/TestCustomServiceOrchestrator.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/TestCustomServiceOrchestrator.py b/ambari-agent/src/test/python/ambari_agent/TestCustomServiceOrchestrator.py
index b9aab2a..724dd5f 100644
--- a/ambari-agent/src/test/python/ambari_agent/TestCustomServiceOrchestrator.py
+++ b/ambari-agent/src/test/python/ambari_agent/TestCustomServiceOrchestrator.py
@@ -82,7 +82,7 @@ class TestCustomServiceOrchestrator(TestCase):
     # Testing existing path
     exists_mock.return_value = True
     path = orchestrator.\
-      resolve_script_path("/HBASE", "scripts/hbase_master.py", "PYTHON")
+      resolve_script_path("/HBASE/package", "scripts/hbase_master.py", "PYTHON")
     self.assertEqual("/HBASE/package/scripts/hbase_master.py", path)
     # Testing not existing path
     exists_mock.return_value = False

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc49fb9e/ambari-agent/src/test/python/ambari_agent/TestFileCache.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/TestFileCache.py b/ambari-agent/src/test/python/ambari_agent/TestFileCache.py
index 8426012..eb30e0c 100644
--- a/ambari-agent/src/test/python/ambari_agent/TestFileCache.py
+++ b/ambari-agent/src/test/python/ambari_agent/TestFileCache.py
@@ -58,7 +58,8 @@ class TestFileCache(TestCase):
     isdir_mock.return_value = True
     base = fileCache.get_service_base_dir("HDP", "2.0.7",
                                           "HBASE", "REGION_SERVER")
-    self.assertEqual(base, "/var/lib/ambari-agent/cache/stacks/HDP/2.0.7/services/HBASE")
+    self.assertEqual(base, "/var/lib/ambari-agent/cache/stacks/HDP/2.0.7/"
+                           "services/HBASE/package")
 
 
   def tearDown(self):

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc49fb9e/ambari-server/src/main/java/org/apache/ambari/server/RoleCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/RoleCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/RoleCommand.java
index ad006ec..94013c2 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/RoleCommand.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/RoleCommand.java
@@ -25,5 +25,6 @@ public enum RoleCommand {
   EXECUTE,
   ABORT,
   UPGRADE,
+  SERVICE_CHECK,
   ACTIONEXECUTE
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc49fb9e/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionScheduler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionScheduler.java b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionScheduler.java
index 9a8d708..29a4904 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionScheduler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionScheduler.java
@@ -193,7 +193,7 @@ class ActionScheduler implements Runnable {
             try {
               long now = System.currentTimeMillis();
               String hostName = cmd.getHostname();
-              String roleName = cmd.getRole().toString();
+              String roleName = cmd.getRole();
 
               s.setStartTime(hostName, roleName, now);
               s.setLastAttemptTime(hostName, roleName, now);
@@ -323,7 +323,7 @@ class ActionScheduler implements Runnable {
       Host hostObj = fsmObject.getHost(host);
       for(ExecutionCommandWrapper wrapper : commandWrappers) {
         ExecutionCommand c = wrapper.getExecutionCommand();
-        String roleStr = c.getRole().toString();
+        String roleStr = c.getRole();
         HostRoleStatus status = s.getHostRoleStatus(host, roleStr);
         if (timeOutActionNeeded(status, s, hostObj, roleStr, now,
           taskTimeout)) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc49fb9e/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/HostAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/HostAction.java b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/HostAction.java
deleted file mode 100644
index 2327d07..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/HostAction.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/**
- * 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 java.util.ArrayList;
-import java.util.List;
-
-import org.apache.ambari.server.agent.ExecutionCommand;
-import org.apache.ambari.server.utils.StageUtils;
-
-/**
- * Encapsulates entire task for a host for a stage or action. This class
- * contains all the information to generate an
- * {@link org.apache.ambari.server.agent.ExecutionCommand} that will be
- * scheduled for a host.
- */
-public class HostAction {
-  private final String host;
-  private List<HostRoleCommand> roles;
-  private long startTime = -1;
-  private long lastAttemptTime = -1;
-  private short attemptCount = 0;
-
-  /**
-   * This object will be serialized and sent to the agent.
-   */
-  private ExecutionCommand commandToHost;
-
-  public String getManifest() {
-    //generate manifest
-    return null;
-  }
-
-  public HostAction(String host) {
-    this.host = host;
-    roles = new ArrayList<HostRoleCommand>();
-    commandToHost = new ExecutionCommand();
-    commandToHost.setHostname(host);
-  }
-
-  public HostAction(HostAction ha) {
-    this.host = ha.host;
-    this.roles = ha.roles;
-    this.startTime = ha.startTime;
-    this.lastAttemptTime = ha.lastAttemptTime;
-    this.attemptCount = ha.attemptCount;
-    this.commandToHost = ha.commandToHost;
-  }
-
-  public void addHostRoleCommand(HostRoleCommand cmd) {
-    roles.add(cmd);
-  }
-
-  public List<HostRoleCommand> getRoleCommands() {
-    return roles;
-  }
-
-  public long getStartTime() {
-    return startTime;
-  }
-
-  public long getLastAttemptTime() {
-    return this.lastAttemptTime;
-  }
-
-  public void setLastAttemptTime(long t) {
-    this.lastAttemptTime = t;
-  }
-
-  public void incrementAttemptCount() {
-    this.attemptCount ++;
-  }
-
-  public short getAttemptCount() {
-    return this.attemptCount;
-  }
-
-  public ExecutionCommand getCommandToHost() {
-    return this.commandToHost;
-  }
-
-  public synchronized void setCommandId(long requestId, long stageId) {
-    commandToHost.setCommandId(StageUtils.getActionId(requestId, stageId));
-  }
-
-  public void setStartTime(long startTime) {
-    this.startTime = startTime;
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc49fb9e/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/HostRoleCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/HostRoleCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/HostRoleCommand.java
index 21ec077..b797a7b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/HostRoleCommand.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/HostRoleCommand.java
@@ -35,7 +35,6 @@ import com.google.inject.Injector;
  * particular role which action manager needs. It doesn't capture actual
  * command and parameters, but just the stuff enough for action manager to
  * track the request.
- * For the actual command refer {@link HostAction#commandToHost}
  */
 public class HostRoleCommand {
   private static final Logger log = LoggerFactory.getLogger(HostRoleCommand.class);

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc49fb9e/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/Stage.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/Stage.java b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/Stage.java
index cee8812..264e5d7 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/Stage.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/Stage.java
@@ -231,6 +231,11 @@ public class Stage {
     execCmdList.add(wrapper);
   }
 
+
+  /**
+   *  Creates server-side execution command. As of now, it seems to
+   *  be used only for server upgrade
+   */
   public synchronized void addServerActionCommand(
       String actionName, Role role,  RoleCommand command, String clusterName,
       ServiceComponentHostUpgradeEvent event, String hostName) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc49fb9e/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
index c72c14b..0909020 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
@@ -40,6 +40,8 @@ public class ExecutionCommand extends AgentCommand {
   public ExecutionCommand() {
     super(AgentCommandType.EXECUTION_COMMAND);
   }
+
+
   private String clusterName;
   private long taskId;
   private String commandId;
@@ -227,4 +229,32 @@ public class ExecutionCommand extends AgentCommand {
     return configurationTags;
   }
 
+
+  /**
+   * Contains key name strings. These strings are used inside maps
+   * incapsulated inside command.
+   */
+  public static interface KeyNames {
+
+    String SCHEMA_VERSION = "schema_version";
+    String COMMAND_TIMEOUT = "command_timeout";
+    String SCRIPT = "script";
+    String SCRIPT_TYPE = "script_type";
+    String SERVICE_METADATA_FOLDER = "service_metadata_folder";
+    String STACK_NAME = "stack_name";
+    String STACK_VERSION = "stack_version";
+    String SERVICE_REPO_INFO = "service_repo_info";
+    String PACKAGE_LIST = "package_list";
+    String JDK_LOCATION = "jdk_location";
+    String MYSQL_JDBC_URL = "mysql_jdbc_url";
+    String ORACLE_JDBC_URL = "oracle_jdbc_url";
+    String DB_DRIVER_FILENAME = "db_driver_filename";
+    String REPO_INFO = "repo_info";
+    String DB_NAME = "db_name";
+    String SERVICE_CHECK = "SERVICE_CHECK"; // TODO: is it standart command? maybe add it to RoleCommand enum?
+
+    String COMMAND_TIMEOUT_DEFAULT = "600"; // TODO: Will be replaced by proper initialization in another jira
+
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc49fb9e/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
index 942be70..2305d5e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
@@ -85,11 +85,27 @@ public class AmbariMetaInfo {
   
   public static final String SERVICE_METRIC_FILE_NAME = "metrics.json";
 
+  /**
+   * This string is used in placeholder in places that are common for
+   * all operating systems or in situations where os type is not important.
+   */
+  public static final String ANY_OS = "any";
+
+  /**
+   * Value for legacy xml files that don't contain schema property
+   */
+  public static final String SCHEMA_VERSION_LEGACY = "1.0";
+
+  /**
+   * Version of XML files with support of custom services and custom commands
+   */
+  public static final String SCHEMA_VERSION_2 = "2.0";
+
+
   public static final FilenameFilter FILENAME_FILTER = new FilenameFilter() {
     @Override
     public boolean accept(File dir, String s) {
-      if (s.equals(".svn") || s.equals(".git")
-              || s.endsWith("_")) // Temporary hack: ignore such names
+      if (s.equals(".svn") || s.equals(".git"))
         return false;
       return true;
     }
@@ -554,6 +570,10 @@ public class AmbariMetaInfo {
     return propertyResult;
   }
 
+
+  /**
+   * Lists operatingsystems supported by stack
+   */
   public Set<OperatingSystemInfo> getOperatingSystems(String stackName, String version)
       throws AmbariException {
 
@@ -613,6 +633,7 @@ public class AmbariMetaInfo {
 
     StackExtensionHelper stackExtensionHelper = new StackExtensionHelper
       (stackRoot);
+    stackExtensionHelper.fillInfo();
 
     List<StackInfo> stacks = stackExtensionHelper.getAllAvailableStacks();
     if (stacks.isEmpty()) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc49fb9e/ambari-server/src/main/java/org/apache/ambari/server/api/util/StackExtensionHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/util/StackExtensionHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/api/util/StackExtensionHelper.java
index 6307db3..0883ad4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/util/StackExtensionHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/util/StackExtensionHelper.java
@@ -18,6 +18,7 @@
 package org.apache.ambari.server.api.util;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
@@ -29,18 +30,22 @@ import java.util.Map;
 import javax.xml.bind.JAXBContext;
 import javax.xml.bind.JAXBException;
 import javax.xml.bind.Unmarshaller;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
 
+import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
-import org.apache.ambari.server.state.ComponentInfo;
-import org.apache.ambari.server.state.PropertyInfo;
-import org.apache.ambari.server.state.ServiceInfo;
-import org.apache.ambari.server.state.StackInfo;
-import org.apache.ambari.server.state.stack.ConfigurationXml;
-import org.apache.ambari.server.state.stack.RepositoryXml;
-import org.apache.ambari.server.state.stack.ServiceMetainfoXml;
-import org.apache.ambari.server.state.stack.StackMetainfoXml;
+import org.apache.ambari.server.state.*;
+import org.apache.ambari.server.state.stack.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
 
 /**
  * Helper methods for providing stack extension behavior -
@@ -52,25 +57,40 @@ public class StackExtensionHelper {
     .getLogger(StackExtensionHelper.class);
   private final Map<String, StackInfo> stackVersionMap = new HashMap<String,
     StackInfo>();
-  private final Map<String, List<StackInfo>> stackParentsMap;
+  private Map<String, List<StackInfo>> stackParentsMap = null;
 
   private static final Map<Class<?>, JAXBContext> _jaxbContexts =
       new HashMap<Class<?>, JAXBContext> ();
   static {
     try {
-      // two classes define the top-level element "metainfo", so we need 2 contexts.
+      // three classes define the top-level element "metainfo", so we need 3 contexts.
       JAXBContext ctx = JAXBContext.newInstance(StackMetainfoXml.class, RepositoryXml.class, ConfigurationXml.class);
       _jaxbContexts.put(StackMetainfoXml.class, ctx);
       _jaxbContexts.put(RepositoryXml.class, ctx);
       _jaxbContexts.put(ConfigurationXml.class, ctx);
       _jaxbContexts.put(ServiceMetainfoXml.class, JAXBContext.newInstance(ServiceMetainfoXml.class));
+      _jaxbContexts.put(ServiceMetainfoV2Xml.class, JAXBContext.newInstance(ServiceMetainfoV2Xml.class));
     } catch (JAXBException e) {
       throw new RuntimeException (e);
     }
-  }  
-  
-  public StackExtensionHelper(File stackRoot) throws Exception {
+  }
+
+  /**
+   * Note: constructor does not perform inialisation now. After instance
+   * creation, you have to call fillInfo() manually
+   */
+  public StackExtensionHelper(File stackRoot) {
     this.stackRoot = stackRoot;
+  }
+
+
+  /**
+   * Must be manually called after creation of StackExtensionHelper instance
+   */
+  public void fillInfo() throws Exception {
+    if (stackParentsMap != null) {
+      throw new AmbariException("fillInfo() method has already been called");
+    }
     File[] stackFiles = stackRoot.listFiles(AmbariMetaInfo.FILENAME_FILTER);
     for (File stack : stackFiles) {
       if (stack.isFile()) {
@@ -85,11 +105,13 @@ public class StackExtensionHelper {
         stackVersionMap.put(stackName + stackVersion, getStackInfo(stackFolder));
       }
     }
-    this.stackParentsMap = getParentStacksInOrder(stackVersionMap.values());
+    stackParentsMap = getParentStacksInOrder(stackVersionMap.values());
   }
 
+
   private ServiceInfo mergeServices(ServiceInfo parentService,
                                     ServiceInfo childService) {
+    // TODO: Allow extending stack with custom services
     ServiceInfo mergedServiceInfo = new ServiceInfo();
     mergedServiceInfo.setName(childService.getName());
     mergedServiceInfo.setComment(childService.getComment());
@@ -186,7 +208,9 @@ public class StackExtensionHelper {
     return new ArrayList<ServiceInfo>(serviceInfoMap.values());
   }
 
-  private void populateServicesForStack(StackInfo stackInfo) {
+  void populateServicesForStack(StackInfo stackInfo) throws
+          ParserConfigurationException, SAXException,
+          XPathExpressionException, IOException, JAXBException {
     List<ServiceInfo> services = new ArrayList<ServiceInfo>();
     File servicesFolder = new File(stackRoot.getAbsolutePath() + File
       .separator + stackInfo.getName() + File.separator + stackInfo.getVersion()
@@ -196,50 +220,76 @@ public class StackExtensionHelper {
       "-" + stackInfo.getVersion());
 
     } else {
-      File[] servicesFolders = servicesFolder.listFiles(AmbariMetaInfo
-        .FILENAME_FILTER);
-      if (servicesFolders != null) {
+      try {
+        File[] servicesFolders = servicesFolder.listFiles(AmbariMetaInfo
+          .FILENAME_FILTER);
+        if (servicesFolders == null) {
+          String message = String.format("No service folders found at %s",
+                  servicesFolder.getAbsolutePath());
+          throw new AmbariException(message);
+        }
+        // Iterate over service folders
         for (File serviceFolder : servicesFolders) {
           if (!serviceFolder.isDirectory())
             continue;
-          
-          // Get information about service
-          ServiceInfo serviceInfo = new ServiceInfo();
-          serviceInfo.setName(serviceFolder.getName());
+          // Get metainfo schema format version
           File metainfoFile = new File(serviceFolder.getAbsolutePath()
-            + File.separator + AmbariMetaInfo.SERVICE_METAINFO_FILE_NAME);
-          
-          setMetaInfo(metainfoFile, serviceInfo);
-          
+                  + File.separator + AmbariMetaInfo.SERVICE_METAINFO_FILE_NAME);
           // get metrics file, if it exists
           File metricsJson = new File(serviceFolder.getAbsolutePath()
-              + File.separator + AmbariMetaInfo.SERVICE_METRIC_FILE_NAME);
-          if (metricsJson.exists())
-            serviceInfo.setMetricsFile(metricsJson);
-          
-          // Add now to be removed while iterating extension graph
-          services.add(serviceInfo);
-
-          // Get all properties from all "configs/*-site.xml" files
-          File serviceConfigFolder = new File(serviceFolder.getAbsolutePath()
-            + File.separator + AmbariMetaInfo.SERVICE_CONFIG_FOLDER_NAME);
-          File[] configFiles = serviceConfigFolder.listFiles
-            (AmbariMetaInfo.FILENAME_FILTER);
-          if (configFiles != null) {
-            for (File config : configFiles) {
-              if (config.getName().endsWith
-                (AmbariMetaInfo.SERVICE_CONFIG_FILE_NAME_POSTFIX)) {
-                serviceInfo.getProperties().addAll(getProperties(config));
-              }
+            + File.separator + AmbariMetaInfo.SERVICE_METRIC_FILE_NAME);
+          String version = getSchemaVersion(metainfoFile);
+          if (AmbariMetaInfo.SCHEMA_VERSION_LEGACY.equals(version)) {
+            // Get information about service
+            ServiceInfo serviceInfo = new ServiceInfo();
+            serviceInfo.setSchemaVersion(AmbariMetaInfo.SCHEMA_VERSION_LEGACY);
+            serviceInfo.setName(serviceFolder.getName());
+            ServiceMetainfoXml smx = unmarshal(ServiceMetainfoXml.class, metainfoFile);
+            serviceInfo.setComment(smx.getComment());
+            serviceInfo.setUser(smx.getUser());
+            serviceInfo.setVersion(smx.getVersion());
+            serviceInfo.setDeleted(smx.isDeleted());
+			      serviceInfo.setConfigDependencies(smx.getConfigDependencies());
+            serviceInfo.getComponents().addAll(smx.getComponents());
+
+            if (metricsJson.exists())
+              serviceInfo.setMetricsFile(metricsJson);            
+
+            // Get all properties from all "configs/*-site.xml" files
+            setPropertiesFromConfigs(serviceFolder, serviceInfo);
+
+            // Add now to be removed while iterating extension graph
+            services.add(serviceInfo);
+          } else { //Reading v2 service metainfo (may contain multiple services)
+            // Get services from metadata
+            ServiceMetainfoV2Xml smiv2x =
+                    unmarshal(ServiceMetainfoV2Xml.class, metainfoFile);
+            List<ServiceInfo> serviceInfos = smiv2x.getServices();
+            for (ServiceInfo serviceInfo : serviceInfos) {
+              serviceInfo.setSchemaVersion(AmbariMetaInfo.SCHEMA_VERSION_2);
+              serviceInfo.setServiceMetadataFolder(serviceFolder.getName());
+              // TODO: allow repository overriding when extending stack
+
+              if (metricsJson.exists())
+                serviceInfo.setMetricsFile(metricsJson);
+
+              // Get all properties from all "configs/*-site.xml" files
+              setPropertiesFromConfigs(serviceFolder, serviceInfo);
+
+              // Add now to be removed while iterating extension graph
+              services.add(serviceInfo);
             }
           }
         }
+      } catch (Exception e) {
+        LOG.error("Error while parsing metainfo.xml for a service", e);
       }
     }
 
     stackInfo.getServices().addAll(services);
   }
 
+
   public List<StackInfo> getAllAvailableStacks() {
     return new ArrayList<StackInfo>(stackVersionMap.values());
   }
@@ -271,6 +321,36 @@ public class StackExtensionHelper {
     return parentStacksMap;
   }
 
+
+  /**
+   * Determines schema version of a given metainfo file
+   * @param stackMetainfoFile  xml file
+   */
+  String getSchemaVersion(File stackMetainfoFile) throws IOException,
+          ParserConfigurationException, SAXException, XPathExpressionException {
+    // Using XPath to get a single value from an metainfo file
+    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+    DocumentBuilder builder = factory.newDocumentBuilder();
+    Document doc = builder.parse(stackMetainfoFile);
+    XPathFactory xPathfactory = XPathFactory.newInstance();
+    XPath xpath = xPathfactory.newXPath();
+    XPathExpression schemaPath = xpath.compile("/metainfo/schemaVersion[1]");
+
+    String value = schemaPath.evaluate(doc).trim();
+    if ( "".equals(value) || // If schemaVersion is not defined
+            AmbariMetaInfo.SCHEMA_VERSION_LEGACY.equals(value)) {
+      return AmbariMetaInfo.SCHEMA_VERSION_LEGACY;
+    } else if (AmbariMetaInfo.SCHEMA_VERSION_2.equals(value)) {
+      return AmbariMetaInfo.SCHEMA_VERSION_2;
+    } else {
+      String message = String.format("Unknown schema version %s at file " +
+              "%s", value, stackMetainfoFile.getAbsolutePath());
+      throw new AmbariException(message);
+    }
+
+  }
+
+
   private StackInfo getStackInfo(File stackVersionFolder) throws JAXBException {
     StackInfo stackInfo = new StackInfo();
 
@@ -308,22 +388,6 @@ public class StackExtensionHelper {
     return stackInfo;
   }
 
-  private void setMetaInfo(File metainfoFile, ServiceInfo serviceInfo) {
-    try {
-      ServiceMetainfoXml smx = unmarshal(ServiceMetainfoXml.class, metainfoFile);
-      
-      serviceInfo.setComment(smx.getComment());
-      serviceInfo.setUser(smx.getUser());
-      serviceInfo.setVersion(smx.getVersion());
-      serviceInfo.setDeleted(smx.isDeleted());
-      serviceInfo.setConfigDependencies(smx.getConfigDependencies());
-      
-      serviceInfo.getComponents().addAll(smx.getComponents());
-    } catch (Exception e) {
-      LOG.error("Error while parsing metainfo.xml for a service", e);
-    }
-
-  }
 
   private List<PropertyInfo> getProperties(File propertyFile) {
     
@@ -340,13 +404,32 @@ public class StackExtensionHelper {
         pi.setFilename(propertyFile.getName());
         list.add(pi);
       }
-      
       return list;
     } catch (Exception e) {
       LOG.error("Could not load configuration for " + propertyFile, e);
       return null;
     }
   }
+
+
+  /**
+   * Get all properties from all "configs/*-site.xml" files
+   */
+  void setPropertiesFromConfigs(File serviceFolder, ServiceInfo serviceInfo) {
+    File serviceConfigFolder = new File(serviceFolder.getAbsolutePath()
+            + File.separator + AmbariMetaInfo.SERVICE_CONFIG_FOLDER_NAME);
+    File[] configFiles = serviceConfigFolder.listFiles
+            (AmbariMetaInfo.FILENAME_FILTER);
+    if (configFiles != null) {
+      for (File config : configFiles) {
+        if (config.getName().endsWith
+                (AmbariMetaInfo.SERVICE_CONFIG_FILE_NAME_POSTFIX)) {
+          serviceInfo.getProperties().addAll(getProperties(config));
+        }
+      }
+    }
+  }
+
   
   public static <T> T unmarshal(Class<T> clz, File file) throws JAXBException {
     Unmarshaller u = _jaxbContexts.get(clz).createUnmarshaller();
@@ -354,4 +437,4 @@ public class StackExtensionHelper {
     return clz.cast(u.unmarshal(file));
   }  
   
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc49fb9e/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariActionExecutionHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariActionExecutionHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariActionExecutionHelper.java
index 632b11d..a008780 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariActionExecutionHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariActionExecutionHelper.java
@@ -51,7 +51,7 @@ import java.util.TreeMap;
  */
 public class AmbariActionExecutionHelper {
   private final static Logger LOG =
-      LoggerFactory.getLogger(AmbariCustomCommandExecutionHelper.class);
+      LoggerFactory.getLogger(AmbariActionExecutionHelper.class);
   private ActionMetadata actionMetadata;
   private Clusters clusters;
   private AmbariManagementControllerImpl amcImpl;
@@ -275,6 +275,10 @@ public class AmbariActionExecutionHelper {
       ExecutionCommand execCmd = stage.getExecutionCommandWrapper(hostName,
           actionContext.getActionName()).getExecutionCommand();
 
+      /*
+       * TODO Execution command field population should be (partially?)
+        * combined with the same code at createHostAction()
+        */
       execCmd.setConfigurations(configurations);
       execCmd.setConfigurationTags(configTags);
       execCmd.setHostLevelParams(hostLevelParams);

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc49fb9e/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
index fa7522b..6165f59 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
@@ -1,239 +1,37 @@
-/**
- * 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.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.Role;
 import org.apache.ambari.server.RoleCommand;
 import org.apache.ambari.server.actionmanager.Stage;
-import org.apache.ambari.server.agent.ExecutionCommand;
-import org.apache.ambari.server.configuration.Configuration;
-import org.apache.ambari.server.metadata.ActionMetadata;
 import org.apache.ambari.server.state.Cluster;
-import org.apache.ambari.server.state.Clusters;
-import org.apache.ambari.server.state.Config;
-import org.apache.ambari.server.state.ConfigHelper;
-import org.apache.ambari.server.state.ServiceComponent;
 import org.apache.ambari.server.state.ServiceComponentHost;
-import org.apache.ambari.server.state.svccomphost.ServiceComponentHostOpInProgressEvent;
-import org.apache.ambari.server.utils.StageUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.ambari.server.state.ServiceComponentHostEvent;
 
-import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
-import java.util.TreeMap;
-
-/**
- * Helper class containing logic to process custom command execution requests
- */
-public class AmbariCustomCommandExecutionHelper {
-  private final static Logger LOG =
-      LoggerFactory.getLogger(AmbariCustomCommandExecutionHelper.class);
-  private ActionMetadata actionMetadata;
-  private Clusters clusters;
-  private AmbariManagementControllerImpl amcImpl;
-
-  public AmbariCustomCommandExecutionHelper(ActionMetadata actionMetadata, Clusters clusters,
-                                            AmbariManagementControllerImpl amcImpl) {
-    this.amcImpl = amcImpl;
-    this.actionMetadata = actionMetadata;
-    this.clusters = clusters;
-  }
-
-  public void validateCustomCommand(ExecuteActionRequest actionRequest) throws AmbariException {
-    if (actionRequest.getServiceName() == null
-        || actionRequest.getServiceName().isEmpty()
-        || actionRequest.getCommandName() == null
-        || actionRequest.getCommandName().isEmpty()) {
-      throw new AmbariException("Invalid request : " + "cluster="
-          + actionRequest.getClusterName() + ", service="
-          + actionRequest.getServiceName() + ", command="
-          + actionRequest.getCommandName());
-    }
-
-    LOG.info("Received a command execution request"
-        + ", clusterName=" + actionRequest.getClusterName()
-        + ", serviceName=" + actionRequest.getServiceName()
-        + ", request=" + actionRequest.toString());
-
-    if (!isValidCommand(actionRequest.getCommandName(), actionRequest.getServiceName())) {
-      throw new AmbariException(
-          "Unsupported action " + actionRequest.getCommandName() + " for " + actionRequest.getServiceName());
-    }
-  }
-
-  private Boolean isValidCommand(String command, String service) {
-    List<String> actions = actionMetadata.getActions(service);
-    if (actions == null || actions.size() == 0) {
-      return false;
-    }
-
-    if (!actions.contains(command)) {
-      return false;
-    }
-
-    return true;
-  }
-
-  public void addAction(ExecuteActionRequest actionRequest, Stage stage,
-                        Configuration configuration, HostsMap hostsMap, Map<String, String> hostLevelParams)
-      throws AmbariException {
-    if (actionRequest.getCommandName().contains("SERVICE_CHECK")) {
-      addServiceCheckAction(actionRequest, stage, configuration, hostsMap, hostLevelParams);
-    } else if (actionRequest.getCommandName().equals("DECOMMISSION_DATANODE")) {
-      addDecommissionDatanodeAction(actionRequest, stage, hostLevelParams);
-    } else {
-      throw new AmbariException("Unsupported action " + actionRequest.getCommandName());
-    }
-  }
-
-  private void addServiceCheckAction(ExecuteActionRequest actionRequest, Stage stage,
-                                     Configuration configuration, HostsMap hostsMap,
-                                     Map<String, String> hostLevelParams)
-      throws AmbariException {
-    String clusterName = actionRequest.getClusterName();
-    String componentName = actionMetadata.getClient(actionRequest
-        .getServiceName());
-
-    String hostName;
-    if (componentName != null) {
-      Map<String, ServiceComponentHost> components = clusters
-          .getCluster(clusterName).getService(actionRequest.getServiceName())
-          .getServiceComponent(componentName).getServiceComponentHosts();
-
-      if (components.isEmpty()) {
-        throw new AmbariException("Hosts not found, component="
-            + componentName + ", service=" + actionRequest.getServiceName()
-            + ", cluster=" + clusterName);
-      }
-      hostName = amcImpl.getHealthyHost(components.keySet());
-    } else {
-      Map<String, ServiceComponent> components = clusters
-          .getCluster(clusterName).getService(actionRequest.getServiceName())
-          .getServiceComponents();
-
-      if (components.isEmpty()) {
-        throw new AmbariException("Components not found, service="
-            + actionRequest.getServiceName() + ", cluster=" + clusterName);
-      }
-
-      ServiceComponent serviceComponent = components.values().iterator()
-          .next();
-
-      if (serviceComponent.getServiceComponentHosts().isEmpty()) {
-        throw new AmbariException("Hosts not found, component="
-            + serviceComponent.getName() + ", service="
-            + actionRequest.getServiceName() + ", cluster=" + clusterName);
-      }
-
-      hostName = serviceComponent.getServiceComponentHosts().keySet()
-          .iterator().next();
-    }
-
-    stage.addHostRoleExecutionCommand(hostName, Role.valueOf(actionRequest
-        .getCommandName()), RoleCommand.EXECUTE,
-        new ServiceComponentHostOpInProgressEvent(componentName, hostName,
-            System.currentTimeMillis()), clusterName, actionRequest
-        .getServiceName());
-
-    stage.getExecutionCommandWrapper(hostName, actionRequest.getCommandName()).getExecutionCommand()
-        .setRoleParams(actionRequest.getParameters());
-
-    Cluster cluster = clusters.getCluster(clusterName);
-
-    // [ type -> [ key, value ] ]
-    Map<String, Map<String, String>> configurations = new TreeMap<String, Map<String, String>>();
-    Map<String, Map<String, String>> configTags = amcImpl.findConfigurationTagsWithOverrides(cluster, hostName);
-
-    ExecutionCommand execCmd = stage.getExecutionCommandWrapper(hostName,
-        actionRequest.getCommandName()).getExecutionCommand();
-
-    execCmd.setConfigurations(configurations);
-    execCmd.setConfigurationTags(configTags);
-    execCmd.setHostLevelParams(hostLevelParams);
-
-    // Generate cluster host info
-    execCmd.setClusterHostInfo(
-        StageUtils.getClusterHostInfo(clusters.getHostsForCluster(clusterName), cluster, hostsMap, configuration));
-  }
-
-  private void addDecommissionDatanodeAction(ExecuteActionRequest decommissionRequest, Stage stage,
-                                             Map<String, String> hostLevelParams)
-      throws AmbariException {
-    String hdfsExcludeFileType = "hdfs-exclude-file";
-    // Find hdfs admin host, just decommission from namenode.
-    String clusterName = decommissionRequest.getClusterName();
-    Cluster cluster = clusters.getCluster(clusterName);
-    String serviceName = decommissionRequest.getServiceName();
-    String namenodeHost = clusters.getCluster(clusterName)
-        .getService(serviceName).getServiceComponent(Role.NAMENODE.toString())
-        .getServiceComponentHosts().keySet().iterator().next();
-
-    String excludeFileTag = null;
-    if (decommissionRequest.getParameters() != null
-        && (decommissionRequest.getParameters().get("excludeFileTag") != null)) {
-      excludeFileTag = decommissionRequest.getParameters()
-          .get("excludeFileTag");
-    }
-
-    if (excludeFileTag == null) {
-      throw new AmbariException("No exclude file specified"
-          + " when decommissioning datanodes. Provide parameter excludeFileTag with the tag for config type "
-          + hdfsExcludeFileType);
-    }
-
-    Config config = clusters.getCluster(clusterName).getConfig(
-        hdfsExcludeFileType, excludeFileTag);
-    if (config == null) {
-      throw new AmbariException("Decommissioning datanodes requires the cluster to be associated with config type " +
-          hdfsExcludeFileType + " with a list of datanodes to be decommissioned (\"datanodes\" : list).");
-    }
-
-    LOG.info("Decommissioning data nodes: " + config.getProperties().get("datanodes") +
-        " " + hdfsExcludeFileType + " tag: " + excludeFileTag);
-
-    Map<String, Map<String, String>> configurations =
-        new TreeMap<String, Map<String, String>>();
-
-
-    Map<String, Map<String, String>> configTags = amcImpl.findConfigurationTagsWithOverrides(cluster, namenodeHost);
-
-    // Add the tag for hdfs-exclude-file
-    Map<String, String> excludeTags = new HashMap<String, String>();
-    excludeTags.put(ConfigHelper.CLUSTER_DEFAULT_TAG, config.getVersionTag());
-    configTags.put(hdfsExcludeFileType, excludeTags);
-
-    stage.addHostRoleExecutionCommand(
-        namenodeHost,
-        Role.DECOMMISSION_DATANODE,
-        RoleCommand.EXECUTE,
-        new ServiceComponentHostOpInProgressEvent(Role.DECOMMISSION_DATANODE
-            .toString(), namenodeHost, System.currentTimeMillis()),
-        clusterName, serviceName);
-
-    ExecutionCommand execCmd = stage.getExecutionCommandWrapper(namenodeHost,
-        Role.DECOMMISSION_DATANODE.toString()).getExecutionCommand();
 
-    execCmd.setConfigurations(configurations);
-    execCmd.setConfigurationTags(configTags);
-    execCmd.setHostLevelParams(hostLevelParams);
-  }
-}
\ No newline at end of file
+public interface AmbariCustomCommandExecutionHelper {
+  void validateCustomCommand(ExecuteActionRequest actionRequest) throws AmbariException;
+
+  void addAction(ExecuteActionRequest actionRequest, Stage stage,
+                 HostsMap hostsMap, Map<String, String> hostLevelParams)
+      throws AmbariException;
+
+  void addServiceCheckActionImpl(Stage stage,
+                                 String hostname, String smokeTestRole,
+                                 long nowTimestamp,
+                                 String serviceName,
+                                 String componentName,
+                                 Map<String, String> roleParameters,
+                                 HostsMap hostsMap,
+                                 Map<String, String> hostLevelParams)
+              throws AmbariException;
+
+  void createHostAction(Cluster cluster,
+                        Stage stage, ServiceComponentHost scHost,
+                        Map<String, Map<String, String>> configurations,
+                        Map<String, Map<String, String>> configTags,
+                        RoleCommand roleCommand,
+                        Map<String, String> commandParams,
+                        ServiceComponentHostEvent event)
+                      throws AmbariException;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc49fb9e/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperImpl.java
new file mode 100644
index 0000000..cd5f6fb
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperImpl.java
@@ -0,0 +1,471 @@
+/**
+ * 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 com.google.gson.Gson;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.Role;
+import org.apache.ambari.server.RoleCommand;
+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.metadata.ActionMetadata;
+import org.apache.ambari.server.state.*;
+import org.apache.ambari.server.state.svccomphost.ServiceComponentHostOpInProgressEvent;
+import org.apache.ambari.server.utils.StageUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.*;
+
+
+/**
+ * Helper class containing logic to process custom command execution requests
+ */
+@Singleton
+public class AmbariCustomCommandExecutionHelperImpl implements AmbariCustomCommandExecutionHelper {
+  private final static Logger LOG =
+      LoggerFactory.getLogger(AmbariCustomCommandExecutionHelperImpl.class);
+
+  @Inject
+  private ActionMetadata actionMetadata;
+  @Inject
+  private Clusters clusters;
+  @Inject
+  private AmbariManagementController amc;
+  @Inject
+  private Gson gson;
+  @Inject
+  private Configuration configs;
+  @Inject
+  private AmbariMetaInfo ambariMetaInfo;
+  @Inject
+  private ConfigHelper configHelper;
+
+
+  @Override
+  public void validateCustomCommand(ExecuteActionRequest actionRequest) throws AmbariException {
+    if (actionRequest.getServiceName() == null
+        || actionRequest.getServiceName().isEmpty()
+        || actionRequest.getCommandName() == null
+        || actionRequest.getCommandName().isEmpty()) {
+      throw new AmbariException("Invalid request : " + "cluster="
+          + actionRequest.getClusterName() + ", service="
+          + actionRequest.getServiceName() + ", command="
+          + actionRequest.getCommandName());
+    }
+
+    LOG.info("Received a command execution request"
+        + ", clusterName=" + actionRequest.getClusterName()
+        + ", serviceName=" + actionRequest.getServiceName()
+        + ", request=" + actionRequest.toString());
+
+    if (!isValidCommand(actionRequest.getCommandName(), actionRequest.getServiceName())) {
+      throw new AmbariException(
+          "Unsupported action " + actionRequest.getCommandName() + " for " + actionRequest.getServiceName());
+    }
+  }
+
+  private Boolean isValidCommand(String command, String service) {
+    List<String> actions = actionMetadata.getActions(service);
+    if (actions == null || actions.size() == 0) {
+      return false;
+    }
+
+    if (!actions.contains(command)) {
+      return false;
+    }
+
+    return true;
+  }
+
+  @Override
+  public void addAction(ExecuteActionRequest actionRequest, Stage stage,
+                        HostsMap hostsMap, Map<String, String> hostLevelParams)
+      throws AmbariException {
+    if (actionRequest.getCommandName().contains("SERVICE_CHECK")) {
+      addServiceCheckAction(actionRequest, stage, hostsMap, hostLevelParams);
+    } else if (actionRequest.getCommandName().equals("DECOMMISSION_DATANODE")) {
+      addDecommissionDatanodeAction(actionRequest, stage, hostLevelParams);
+    } else {
+      throw new AmbariException("Unsupported action " + actionRequest.getCommandName());
+    }
+  }
+
+  private void addServiceCheckAction(ExecuteActionRequest actionRequest, Stage stage,
+                                     HostsMap hostsMap,
+                                     Map<String, String> hostLevelParams)
+      throws AmbariException {
+    String clusterName = actionRequest.getClusterName();
+    String componentName = actionMetadata.getClient(actionRequest
+        .getServiceName());
+    String serviceName = actionRequest.getServiceName();
+    String smokeTestRole = actionRequest.getCommandName();
+    long nowTimestamp = System.currentTimeMillis();
+    Map<String, String> roleParameters = actionRequest.getParameters();
+
+    String hostName;
+    if (componentName != null) {
+      Map<String, ServiceComponentHost> components = clusters
+          .getCluster(clusterName).getService(actionRequest.getServiceName())
+          .getServiceComponent(componentName).getServiceComponentHosts();
+
+      if (components.isEmpty()) {
+        throw new AmbariException("Hosts not found, component="
+            + componentName + ", service=" + actionRequest.getServiceName()
+            + ", cluster=" + clusterName);
+      }
+      hostName = amc.getHealthyHost(components.keySet());
+    } else {
+      Map<String, ServiceComponent> components = clusters
+          .getCluster(clusterName).getService(actionRequest.getServiceName())
+          .getServiceComponents();
+
+      if (components.isEmpty()) {
+        throw new AmbariException("Components not found, service="
+            + actionRequest.getServiceName() + ", cluster=" + clusterName);
+      }
+
+      ServiceComponent serviceComponent = components.values().iterator()
+          .next();
+
+      if (serviceComponent.getServiceComponentHosts().isEmpty()) {
+        throw new AmbariException("Hosts not found, component="
+            + serviceComponent.getName() + ", service="
+            + actionRequest.getServiceName() + ", cluster=" + clusterName);
+      }
+
+      hostName = serviceComponent.getServiceComponentHosts().keySet()
+          .iterator().next();
+    }
+
+
+    addServiceCheckActionImpl(stage, hostName, smokeTestRole, nowTimestamp,
+            serviceName, componentName, roleParameters, hostsMap,
+            hostLevelParams);
+  }
+
+
+
+  /**
+   * Creates and populates service check EXECUTION_COMMAND for host.
+   * Not all EXECUTION_COMMAND parameters are populated here because they
+   * are not needed by service check.
+   */
+  @Override
+  public void addServiceCheckActionImpl(Stage stage,
+                                        String hostname, String smokeTestRole,
+                                        long nowTimestamp,
+                                        String serviceName,
+                                        String componentName,
+                                        Map<String, String> roleParameters,
+                                        HostsMap hostsMap,
+                                        Map<String, String> hostLevelParams)
+          throws AmbariException{
+
+    String clusterName = stage.getClusterName();
+    Cluster cluster = clusters.getCluster(clusterName);
+    StackId stackId = cluster.getDesiredStackVersion();
+    AmbariMetaInfo ambariMetaInfo = amc.getAmbariMetaInfo();
+    ServiceInfo serviceInfo =
+            ambariMetaInfo.getServiceInfo(stackId.getStackName(),
+              stackId.getStackVersion(), serviceName);
+
+
+    stage.addHostRoleExecutionCommand(hostname,
+            Role.valueOf(smokeTestRole),
+            RoleCommand.SERVICE_CHECK,
+            new ServiceComponentHostOpInProgressEvent(componentName, hostname,
+                    nowTimestamp), cluster.getClusterName(), serviceName);
+
+    // [ type -> [ key, value ] ]
+    Map<String, Map<String, String>> configurations =
+            new TreeMap<String, Map<String, String>>();
+    Map<String, Map<String, String>> configTags =
+            amc.findConfigurationTagsWithOverrides(cluster, hostname);
+
+    ExecutionCommand execCmd =  stage.getExecutionCommandWrapper(hostname,
+            smokeTestRole).getExecutionCommand();
+
+    execCmd.setConfigurations(configurations);
+    execCmd.setConfigurationTags(configTags);
+
+    // Generate cluster host info
+    execCmd.setClusterHostInfo(
+            StageUtils.getClusterHostInfo(clusters.getHostsForCluster(clusterName), cluster, hostsMap, configs));
+
+    if (hostLevelParams == null) {
+      hostLevelParams = new TreeMap<String, String>();
+    }
+    hostLevelParams.put(JDK_LOCATION, amc.getJdkResourceUrl());
+    hostLevelParams.put(STACK_NAME, stackId.getStackName());
+    hostLevelParams.put(STACK_VERSION,stackId.getStackVersion());
+    execCmd.setHostLevelParams(hostLevelParams);
+
+    Map<String,String> commandParams = new TreeMap<String, String>();
+    commandParams.put(SCHEMA_VERSION, serviceInfo.getSchemaVersion());
+
+    String commandTimeout = COMMAND_TIMEOUT_DEFAULT;
+
+
+    if (serviceInfo.getSchemaVersion().equals(AmbariMetaInfo.SCHEMA_VERSION_2)) {
+      // Service check command is not custom command
+      CommandScriptDefinition script = serviceInfo.getCommandScript();
+      if (script != null) {
+        commandParams.put(SCRIPT, script.getScript());
+        commandParams.put(SCRIPT_TYPE, script.getScriptType().toString());
+        commandTimeout = String.valueOf(script.getTimeout());
+      } else {
+        String message = String.format("Service %s has not command script " +
+                "defined. It is not possible to run service check" +
+                " for this service", serviceName);
+        throw new AmbariException(message);
+      }
+      // We don't need package/repo infomation to perform service check
+    }
+    commandParams.put(COMMAND_TIMEOUT, commandTimeout);
+
+    commandParams.put(SERVICE_METADATA_FOLDER,
+            serviceInfo.getServiceMetadataFolder());
+
+    execCmd.setCommandParams(commandParams);
+
+    if (roleParameters != null) { // If defined
+      execCmd.setRoleParams(roleParameters);
+    }
+
+  }
+
+  private void addDecommissionDatanodeAction(ExecuteActionRequest decommissionRequest, Stage stage,
+                                             Map<String, String> hostLevelParams)
+      throws AmbariException {
+    String hdfsExcludeFileType = "hdfs-exclude-file";
+    // Find hdfs admin host, just decommission from namenode.
+    String clusterName = decommissionRequest.getClusterName();
+    Cluster cluster = clusters.getCluster(clusterName);
+    String serviceName = decommissionRequest.getServiceName();
+    String namenodeHost = clusters.getCluster(clusterName)
+        .getService(serviceName).getServiceComponent(Role.NAMENODE.toString())
+        .getServiceComponentHosts().keySet().iterator().next();
+
+    String excludeFileTag = null;
+    if (decommissionRequest.getParameters() != null
+        && (decommissionRequest.getParameters().get("excludeFileTag") != null)) {
+      excludeFileTag = decommissionRequest.getParameters()
+          .get("excludeFileTag");
+    }
+
+    if (excludeFileTag == null) {
+      throw new AmbariException("No exclude file specified"
+          + " when decommissioning datanodes. Provide parameter excludeFileTag with the tag for config type "
+          + hdfsExcludeFileType);
+    }
+
+    Config config = clusters.getCluster(clusterName).getConfig(
+        hdfsExcludeFileType, excludeFileTag);
+    if (config == null) {
+      throw new AmbariException("Decommissioning datanodes requires the cluster to be associated with config type " +
+          hdfsExcludeFileType + " with a list of datanodes to be decommissioned (\"datanodes\" : list).");
+    }
+
+    LOG.info("Decommissioning data nodes: " + config.getProperties().get("datanodes") +
+        " " + hdfsExcludeFileType + " tag: " + excludeFileTag);
+
+    Map<String, Map<String, String>> configurations =
+        new TreeMap<String, Map<String, String>>();
+
+
+    Map<String, Map<String, String>> configTags = amc.findConfigurationTagsWithOverrides(cluster, namenodeHost);
+
+    // Add the tag for hdfs-exclude-file
+    Map<String, String> excludeTags = new HashMap<String, String>();
+    excludeTags.put(ConfigHelper.CLUSTER_DEFAULT_TAG, config.getVersionTag());
+    configTags.put(hdfsExcludeFileType, excludeTags);
+
+    stage.addHostRoleExecutionCommand(
+        namenodeHost,
+        Role.DECOMMISSION_DATANODE,
+        RoleCommand.EXECUTE,
+        new ServiceComponentHostOpInProgressEvent(Role.DECOMMISSION_DATANODE
+            .toString(), namenodeHost, System.currentTimeMillis()),
+        clusterName, serviceName);
+
+    ExecutionCommand execCmd = stage.getExecutionCommandWrapper(namenodeHost,
+        Role.DECOMMISSION_DATANODE.toString()).getExecutionCommand();
+
+    execCmd.setConfigurations(configurations);
+    execCmd.setConfigurationTags(configTags);
+    /*
+     TODO: When migrating to custom services, datanode decommision
+     probably will be implemented as a custom action; that's why
+     we have no schema version 2 command parameters here
+    */
+    execCmd.setHostLevelParams(hostLevelParams);
+  }
+
+
+  /**
+   * Creates and populates an EXECUTION_COMMAND for host
+   */
+  @Override
+  public void createHostAction(Cluster cluster,
+                               Stage stage, ServiceComponentHost scHost,
+                               Map<String, Map<String, String>> configurations,
+                               Map<String, Map<String, String>> configTags,
+                               RoleCommand roleCommand,
+                               Map<String, String> commandParams,
+                               ServiceComponentHostEvent event)
+          throws AmbariException {
+
+    stage.addHostRoleExecutionCommand(scHost.getHostName(), Role.valueOf(scHost
+            .getServiceComponentName()), roleCommand,
+            event, scHost.getClusterName(),
+            scHost.getServiceName());
+    String serviceName = scHost.getServiceName();
+    String componentName = event.getServiceComponentName();
+    String hostname = scHost.getHostName();
+    String osType = clusters.getHost(hostname).getOsType();
+    StackId stackId = cluster.getDesiredStackVersion();
+    ServiceInfo serviceInfo = ambariMetaInfo.getServiceInfo(stackId.getStackName(),
+            stackId.getStackVersion(), serviceName);
+    ComponentInfo componentInfo = ambariMetaInfo.getComponent(
+            stackId.getStackName(), stackId.getStackVersion(),
+            serviceName, componentName);
+
+    ExecutionCommand execCmd = stage.getExecutionCommandWrapper(scHost.getHostName(),
+            scHost.getServiceComponentName()).getExecutionCommand();
+
+    Host host = clusters.getHost(scHost.getHostName());
+
+    // Hack - Remove passwords from configs
+    if (event.getServiceComponentName().equals(Role.HIVE_CLIENT.toString())) {
+      configHelper.applyCustomConfig(configurations, Configuration.HIVE_CONFIG_TAG,
+              Configuration.HIVE_METASTORE_PASSWORD_PROPERTY, "", true);
+    }
+
+    execCmd.setConfigurations(configurations);
+    execCmd.setConfigurationTags(configTags);
+    if (commandParams == null) { // if not defined
+      commandParams = new TreeMap<String, String>();
+    }
+    commandParams.put(SCHEMA_VERSION, serviceInfo.getSchemaVersion());
+
+
+    // Get command script info for custom command/custom action
+    /*
+     * TODO: Custom actions are not supported yet, that's why we just pass
+     * component main commandScript to agent. This script is only used for
+     * default commads like INSTALL/STOP/START/CONFIGURE
+     */
+    String commandTimeout = ExecutionCommand.KeyNames.COMMAND_TIMEOUT_DEFAULT;
+    CommandScriptDefinition script = componentInfo.getCommandScript();
+    if (serviceInfo.getSchemaVersion().equals(AmbariMetaInfo.SCHEMA_VERSION_2)) {
+      if (script != null) {
+        commandParams.put(SCRIPT, script.getScript());
+        commandParams.put(SCRIPT_TYPE, script.getScriptType().toString());
+        commandTimeout = String.valueOf(script.getTimeout());
+      } else {
+        String message = String.format("Component %s of service %s has not " +
+                "command script defined", componentName, serviceName);
+        throw new AmbariException(message);
+      }
+    }
+    commandParams.put(COMMAND_TIMEOUT, commandTimeout);
+    commandParams.put(SERVICE_METADATA_FOLDER,
+            serviceInfo.getServiceMetadataFolder());
+
+    execCmd.setCommandParams(commandParams);
+
+    Map<String, List<RepositoryInfo>> repos = ambariMetaInfo.getRepository(
+            stackId.getStackName(), stackId.getStackVersion());
+    String repoInfo = "";
+    if (!repos.containsKey(host.getOsType())) {
+      // FIXME should this be an error?
+      LOG.warn("Could not retrieve repo information for host"
+              + ", hostname=" + scHost.getHostName()
+              + ", clusterName=" + cluster.getClusterName()
+              + ", stackInfo=" + stackId.getStackId());
+    } else {
+      repoInfo = gson.toJson(repos.get(host.getOsType()));
+    }
+
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("Sending repo information to agent"
+              + ", hostname=" + scHost.getHostName()
+              + ", clusterName=" + cluster.getClusterName()
+              + ", stackInfo=" + stackId.getStackId()
+              + ", repoInfo=" + repoInfo);
+    }
+
+    Map<String, String> hostParams = new TreeMap<String, String>();
+    // TODO: Move parameter population to org.apache.ambari.server.controller.AmbariManagementControllerImpl.createAction()
+    hostParams.put(REPO_INFO, repoInfo);
+    hostParams.put(JDK_LOCATION, amc.getJdkResourceUrl());
+    hostParams.put(STACK_NAME, stackId.getStackName());
+    hostParams.put(STACK_VERSION, stackId.getStackVersion());
+    hostParams.put(DB_NAME, amc.getServerDB());
+    hostParams.put(MYSQL_JDBC_URL, amc.getMysqljdbcUrl());
+    hostParams.put(ORACLE_JDBC_URL, amc.getOjdbcUrl());
+
+    // Write down os specific info for the service
+    ServiceOsSpecific anyOs = null;
+    if (serviceInfo.getOsSpecifics().containsKey(AmbariMetaInfo.ANY_OS)) {
+      anyOs = serviceInfo.getOsSpecifics().get(AmbariMetaInfo.ANY_OS);
+    }
+    ServiceOsSpecific hostOs = null;
+    if (serviceInfo.getOsSpecifics().containsKey(osType)) {
+      hostOs = serviceInfo.getOsSpecifics().get(osType);
+      // Choose repo that is relevant for host
+      ServiceOsSpecific.Repo serviceRepo= hostOs.getRepo();
+      if (serviceRepo != null) {
+        String serviceRepoInfo = gson.toJson(serviceInfo);
+        hostParams.put(SERVICE_REPO_INFO, serviceRepoInfo);
+      }
+    }
+    // Build package list that is relevant for host
+    List<ServiceOsSpecific.Package> packages =
+            new ArrayList<ServiceOsSpecific.Package>();
+    if (anyOs != null) {
+      packages.addAll(anyOs.getPackages());
+    }
+
+    if (hostOs != null) {
+      packages.addAll(hostOs.getPackages());
+    }
+    String packageList = gson.toJson(packages);
+    hostParams.put(PACKAGE_LIST, packageList);
+
+    if (configs.getServerDBName().equalsIgnoreCase(Configuration
+            .ORACLE_DB_NAME)) {
+      hostParams.put(DB_DRIVER_FILENAME, configs.getOjdbcJarName());
+    } else if (configs.getServerDBName().equalsIgnoreCase(Configuration
+            .MYSQL_DB_NAME)) {
+      hostParams.put(DB_DRIVER_FILENAME, configs.getMySQLJarName());
+    }
+    execCmd.setHostLevelParams(hostParams);
+
+    Map<String, String> roleParams = new TreeMap<String, String>();
+    execCmd.setRoleParams(roleParams);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc49fb9e/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
index 67b2475..1dd461e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
@@ -441,5 +441,46 @@ public interface AmbariManagementController {
                                             Map<String, Map<State, List<ServiceComponentHost>>> changedHosts,
                                             Collection<ServiceComponentHost> ignoredHosts,
                                             boolean runSmokeTest, boolean reconfigureClients) throws AmbariException;
+
+
+  /**
+   * Getter for the url of JDK, stored at server resources folder
+   */
+  public String getJdkResourceUrl();
+
+  /**
+   * Getter for the name of server database
+   */
+  public String getServerDB();
+
+  /**
+   * Getter for the url of Oracle JDBC driver, stored at server resources folder
+   */
+  public String getOjdbcUrl();
+
+  /**
+   * Getter for the url of MySQL JDBC driver, stored at server resources folder
+   */
+  public String getMysqljdbcUrl();
+
+  /**
+   * Return a healthy host if found otherwise any random host
+   * @throws AmbariException
+   */
+  public String getHealthyHost(Set<String> hostList) throws AmbariException;
+
+
+  /**
+   * Find configuration tags with applied overrides
+   *
+   * @param cluster   the cluster
+   * @param hostName  the host name
+   *
+   * @return the configuration tags
+   *
+   * @throws AmbariException if configuration tags can not be obtained
+   */
+  public Map<String, Map<String,String>> findConfigurationTagsWithOverrides(
+          Cluster cluster, String hostName) throws AmbariException;
 }
   

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc49fb9e/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
index 257c189..1a33f28 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
@@ -18,11 +18,21 @@
 
 package org.apache.ambari.server.controller;
 
-import com.google.gson.Gson;
-import com.google.inject.Inject;
-import com.google.inject.Injector;
-import com.google.inject.Singleton;
-import com.google.inject.persist.Transactional;
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+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;
@@ -39,7 +49,6 @@ import org.apache.ambari.server.actionmanager.ActionManager;
 import org.apache.ambari.server.actionmanager.HostRoleCommand;
 import org.apache.ambari.server.actionmanager.Stage;
 import org.apache.ambari.server.actionmanager.StageFactory;
-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.URLStreamProvider;
@@ -49,33 +58,11 @@ import org.apache.ambari.server.security.authorization.AuthorizationHelper;
 import org.apache.ambari.server.security.authorization.User;
 import org.apache.ambari.server.security.authorization.Users;
 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.ConfigHelper;
-import org.apache.ambari.server.state.Host;
-import org.apache.ambari.server.state.HostState;
-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.*;
 import org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
 import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostInstallEvent;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostMaintenanceEvent;
-import org.apache.ambari.server.state.svccomphost.ServiceComponentHostOpInProgressEvent;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostRestoreEvent;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostStartEvent;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostStopEvent;
@@ -86,20 +73,13 @@ import org.apache.commons.lang.StringUtils;
 import org.apache.http.client.utils.URIBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import java.io.File;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.TreeMap;
+
+import com.google.gson.Gson;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.Singleton;
+import com.google.inject.persist.Transactional;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.*;
 
 @Singleton
 public class AmbariManagementControllerImpl implements
@@ -166,7 +146,8 @@ public class AmbariManagementControllerImpl implements
   final private String serverDB;
   final private String mysqljdbcUrl;
 
-  final private AmbariCustomCommandExecutionHelper customCommandExecutionHelper;
+  @Inject
+  private AmbariCustomCommandExecutionHelper customCommandExecutionHelper;
   final private AmbariActionExecutionHelper actionExecutionHelper;
 
   @Inject
@@ -204,8 +185,6 @@ public class AmbariManagementControllerImpl implements
       this.serverDB = null;
     }
 
-    this.customCommandExecutionHelper = new AmbariCustomCommandExecutionHelper(
-        this.actionMetadata, this.clusters, this);
     this.actionExecutionHelper = new AmbariActionExecutionHelper(
         this.actionMetadata, this.clusters, this);
   }
@@ -548,76 +527,6 @@ public class AmbariManagementControllerImpl implements
     return stageFactory.createNew(requestId, logDir, cluster.getClusterName(), requestContext, clusterHostInfo);
   }
 
-  private void createHostAction(Cluster cluster,
-                                Stage stage, ServiceComponentHost scHost,
-                                Map<String, Map<String, String>> configurations,
-                                Map<String, Map<String, String>> configTags,
-                                RoleCommand command,
-                                Map<String, String> commandParams,
-                                ServiceComponentHostEvent event) throws AmbariException {
-
-    stage.addHostRoleExecutionCommand(scHost.getHostName(), Role.valueOf(scHost
-        .getServiceComponentName()), command,
-        event, scHost.getClusterName(),
-        scHost.getServiceName());
-    ExecutionCommand execCmd = stage.getExecutionCommandWrapper(scHost.getHostName(),
-        scHost.getServiceComponentName()).getExecutionCommand();
-
-    Host host = clusters.getHost(scHost.getHostName());
-
-    // Hack - Remove passwords from configs
-    if (event.getServiceComponentName().equals(Role.HIVE_CLIENT.toString())) {
-      configHelper.applyCustomConfig(configurations, Configuration.HIVE_CONFIG_TAG,
-          Configuration.HIVE_METASTORE_PASSWORD_PROPERTY, "", true);
-    }
-
-    execCmd.setConfigurations(configurations);
-    execCmd.setConfigurationTags(configTags);
-    execCmd.setCommandParams(commandParams);
-
-    // send stack info to agent
-    StackId stackId = scHost.getDesiredStackVersion();
-    Map<String, List<RepositoryInfo>> repos = ambariMetaInfo.getRepository(
-        stackId.getStackName(), stackId.getStackVersion());
-    String repoInfo = "";
-    if (!repos.containsKey(host.getOsType())) {
-      // FIXME should this be an error?
-      LOG.warn("Could not retrieve repo information for host"
-          + ", hostname=" + scHost.getHostName()
-          + ", clusterName=" + cluster.getClusterName()
-          + ", stackInfo=" + stackId.getStackId());
-    } else {
-      repoInfo = gson.toJson(repos.get(host.getOsType()));
-    }
-
-    if (LOG.isDebugEnabled()) {
-      LOG.debug("Sending repo information to agent"
-          + ", hostname=" + scHost.getHostName()
-          + ", clusterName=" + cluster.getClusterName()
-          + ", stackInfo=" + stackId.getStackId()
-          + ", repoInfo=" + repoInfo);
-    }
-
-    Map<String, String> params = new TreeMap<String, String>();
-    params.put("repo_info",       repoInfo);
-    params.put("jdk_location",    jdkResourceUrl);
-    params.put("stack_version",   stackId.getStackVersion());
-    params.put("db_name",         serverDB);
-    params.put("mysql_jdbc_url" , mysqljdbcUrl);
-    params.put("oracle_jdbc_url", ojdbcUrl);
-
-    if (configs.getServerDBName().equalsIgnoreCase(Configuration
-        .ORACLE_DB_NAME)) {
-      params.put("db_driver_filename", configs.getOjdbcJarName());
-    } else if (configs.getServerDBName().equalsIgnoreCase(Configuration
-        .MYSQL_DB_NAME)) {
-      params.put("db_driver_filename", configs.getMySQLJarName());
-    }
-    execCmd.setHostLevelParams(params);
-
-    Map<String, String> roleParams = new TreeMap<String, String>();
-    execCmd.setRoleParams(roleParams);
-  }
 
   private synchronized Set<ClusterResponse> getClusters(ClusterRequest request)
       throws AmbariException {
@@ -1090,18 +999,9 @@ public class AmbariManagementControllerImpl implements
     }
   }
 
-  /**
-   * Find configuration tags with applied overrides
-   *
-   * @param cluster   the cluster
-   * @param hostName  the host name
-   *
-   * @return the configuration tags
-   *
-   * @throws AmbariException if configuration tags can not be obtained
-   */
-  protected Map<String, Map<String,String>> findConfigurationTagsWithOverrides(
-    Cluster cluster, String hostName) throws AmbariException {
+  @Override
+  public Map<String, Map<String,String>> findConfigurationTagsWithOverrides(
+          Cluster cluster, String hostName) throws AmbariException {
 
     return configHelper.getEffectiveDesiredTags(cluster, hostName);
   }
@@ -1303,15 +1203,15 @@ public class AmbariManagementControllerImpl implements
               }
             }
 
-            createHostAction(cluster, stage, scHost, configurations, configTags,
-                roleCommand, requestParameters, event);
+            customCommandExecutionHelper.createHostAction(cluster, stage, scHost,
+                    configurations, configTags,
+                    roleCommand, requestParameters, event);
           }
         }
       }
 
-      for (String serviceName : smokeTestServices) {
+      for (String serviceName : smokeTestServices) { // Creates smoke test commands
         Service s = cluster.getService(serviceName);
-
         // find service component host
         String clientHost = getClientHostForRunningAction(cluster, s);
         String smokeTestRole =
@@ -1326,39 +1226,10 @@ public class AmbariManagementControllerImpl implements
               + ", serviceCheckRole=" + smokeTestRole);
           continue;
         }
-
-        stage.addHostRoleExecutionCommand(clientHost,
-            Role.valueOf(smokeTestRole),
-            RoleCommand.EXECUTE,
-            new ServiceComponentHostOpInProgressEvent(null, clientHost,
-                nowTimestamp), cluster.getClusterName(), serviceName);
-
-        // [ type -> [ key, value ] ]
-        Map<String, Map<String, String>> configurations = new TreeMap<String, Map<String,String>>();
-        Map<String, Map<String, String>> configTags =
-          findConfigurationTagsWithOverrides(cluster, clientHost);
-
-        stage.getExecutionCommandWrapper(clientHost,
-            smokeTestRole).getExecutionCommand()
-            .setConfigurations(configurations);
-
-        stage.getExecutionCommandWrapper(clientHost,
-          smokeTestRole).getExecutionCommand()
-          .setConfigurationTags(configTags);
-        
-        // Generate cluster host info
-        stage.getExecutionCommandWrapper(clientHost, smokeTestRole)
-            .getExecutionCommand()
-            .setClusterHostInfo(StageUtils.getClusterHostInfo(
-                clusters.getHostsForCluster(cluster.getClusterName()), cluster, hostsMap,
-                injector.getInstance(Configuration.class)));
-
-        Map<String,String> hostParams = new HashMap<String, String>();
-        hostParams.put("stack_version", cluster.getDesiredStackVersion().getStackVersion());
-        // smoke tests need stack version
-        stage.getExecutionCommandWrapper(clientHost,
-            smokeTestRole).getExecutionCommand()
-            .setHostLevelParams(hostParams);
+        Configuration configuration = injector.getInstance(Configuration.class);
+        customCommandExecutionHelper.addServiceCheckActionImpl(stage, clientHost,
+                smokeTestRole, nowTimestamp, serviceName,
+                null, null, hostsMap, null);
 
       }
 
@@ -2064,8 +1935,9 @@ public class AmbariManagementControllerImpl implements
     return null;
   }
 
-  protected String getHealthyHost(Set<String> hostList) throws AmbariException {
-    // Return a healthy host if found otherwise any random host
+
+  @Override
+  public String getHealthyHost(Set<String> hostList) throws AmbariException {
     String hostName = null;
     for (String candidateHostName : hostList) {
       hostName = candidateHostName;
@@ -2081,7 +1953,6 @@ public class AmbariManagementControllerImpl implements
   public RequestStatusResponse createAction(ExecuteActionRequest actionRequest, Map<String, String> requestProperties)
       throws AmbariException {
     String clusterName;
-    Configuration configuration = injector.getInstance(Configuration.class);
     String requestContext = "";
 
     if (requestProperties != null) {
@@ -2109,7 +1980,7 @@ public class AmbariManagementControllerImpl implements
 
     Map<String, List<String>> clusterHostInfo = StageUtils.getClusterHostInfo(
         clusters.getHostsForCluster(cluster.getClusterName()), cluster, hostsMap,
-        injector.getInstance(Configuration.class));
+        configs);
 
     String clusterHostInfoJson = StageUtils.getGson().toJson(clusterHostInfo);
     Stage stage = createNewStage(cluster, actionManager.getNextRequestId(), requestContext, clusterHostInfoJson);
@@ -2117,13 +1988,14 @@ public class AmbariManagementControllerImpl implements
     stage.setStageId(0);
 
     Map<String, String> params = new TreeMap<String, String>();
-    params.put("jdk_location", this.jdkResourceUrl);
-    params.put("stack_version", cluster.getDesiredStackVersion().getStackVersion());
+    // TODO : Update parameter population to be done only here
+    params.put(JDK_LOCATION, this.jdkResourceUrl);
+    params.put(STACK_VERSION, cluster.getDesiredStackVersion().getStackVersion());
 
     if (actionRequest.isCommand()) {
-      customCommandExecutionHelper.addAction(actionRequest, stage, configuration, hostsMap, params);
+      customCommandExecutionHelper.addAction(actionRequest, stage, hostsMap, params);
     } else {
-      actionExecutionHelper.addAction(actionExecContext, stage, configuration, hostsMap, params);
+      actionExecutionHelper.addAction(actionExecContext, stage, configs, hostsMap, params);
     }
 
     RoleCommandOrder rco = this.getRoleCommandOrder(cluster);
@@ -2645,4 +2517,24 @@ public class AmbariManagementControllerImpl implements
   public ActionManager getActionManager() {
     return actionManager;
   }
+
+  @Override
+  public String getJdkResourceUrl() {
+    return jdkResourceUrl;
+  }
+
+  @Override
+  public String getServerDB() {
+    return serverDB;
+  }
+
+  @Override
+  public String getOjdbcUrl() {
+    return ojdbcUrl;
+  }
+
+  @Override
+  public String getMysqljdbcUrl() {
+    return mysqljdbcUrl;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc49fb9e/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
index 0859322..7d60bab 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
@@ -97,6 +97,7 @@ public class ControllerModule extends AbstractModule {
 
     bind(Gson.class).in(Scopes.SINGLETON);
     bind(Clusters.class).to(ClustersImpl.class);
+    bind(AmbariCustomCommandExecutionHelper.class).to(AmbariCustomCommandExecutionHelperImpl.class);
     bind(ActionDBAccessor.class).to(ActionDBAccessorImpl.class);
     bind(CustomActionDBAccessor.class).to(CustomActionDBAccessorImpl.class);
     bindConstant().annotatedWith(Names.named("schedulerSleeptime")).to(10000L);