@Override
  public RequestStatusResponse createAction(ExecuteActionRequest actionRequest,
      Map<String, String> requestProperties)
      throws AmbariException {
    String clusterName = actionRequest.getClusterName();

    String requestContext = "";

    if (requestProperties != null) {
      requestContext = StringEscapeUtils.escapeHtml4(requestProperties.get(RequestResourceProvider.CONTEXT));
      if (requestContext == null) {
        // guice needs a non-null value as there is no way to mark this parameter @Nullable
        requestContext = "";
      }
    }

    Cluster cluster = null;
    if (null != clusterName) {
      cluster = clusters.getCluster(clusterName);

      LOG.info("Received action execution request"
        + ", clusterName=" + actionRequest.getClusterName()
        + ", request=" + actionRequest);
    }

    ActionExecutionContext actionExecContext = getActionExecutionContext(actionRequest);
    if (actionRequest.isCommand()) {
      customCommandExecutionHelper.validateAction(actionRequest);
    } else {
      actionExecutionHelper.validateAction(actionRequest);
    }
    // TODO Alejandro, Called First. insert params.version. Called during Rebalance HDFS, ZOOKEEPER Restart, Zookeeper Service Check.
    long requestId = actionManager.getNextRequestId();
    RequestStageContainer requestStageContainer = new RequestStageContainer(
        requestId,
        null,
        requestFactory,
        actionManager,
        actionRequest);

    @Experimental(feature=ExperimentalFeature.MULTI_SERVICE,
        comment = "This must change with Multi-Service since the cluster won't have a desired stack version")
    ExecuteCommandJson jsons = customCommandExecutionHelper.getCommandJson(actionExecContext, cluster,
        null == cluster ? null : cluster.getDesiredStackVersion(), requestContext);

    String commandParamsForStage = jsons.getCommandParamsForStage();

    Map<String, String> commandParamsStage = gson.fromJson(commandParamsForStage, new TypeToken<Map<String, String>>()
      {}.getType());
    // Ensure that the specified requestContext (if any) is set as the request context
    if (!requestContext.isEmpty()) {
      requestStageContainer.setRequestContext(requestContext);
    }

    // replace password references in requestProperties
    SecretReference.replaceReferencesWithPasswords(commandParamsStage, cluster);

    // If the request is to perform the Kerberos service check, set up the stages to
    // ensure that the (cluster-level) smoke user principal and keytab is available on all hosts
    boolean kerberosServiceCheck = Role.KERBEROS_SERVICE_CHECK.name().equals(actionRequest.getCommandName());
    if (kerberosServiceCheck) {
      // Parse the command parameters into a map so that additional values may be added to it

      try {
        requestStageContainer = kerberosHelper.createTestIdentity(cluster, commandParamsStage, requestStageContainer);
      } catch (KerberosOperationException e) {
        throw new IllegalArgumentException(e.getMessage(), e);
      }
    }

    commandParamsForStage = gson.toJson(commandParamsStage);

    Stage stage = createNewStage(requestStageContainer.getLastStageId(), cluster, requestId, requestContext,
        commandParamsForStage, jsons.getHostParamsForStage());

    if (actionRequest.isCommand()) {
      customCommandExecutionHelper.addExecutionCommandsToStage(actionExecContext, stage,
          requestProperties, jsons);
    } else {
      actionExecutionHelper.addExecutionCommandsToStage(actionExecContext, stage, requestProperties);
    }

    RoleGraph rg;
    if (null != cluster) {
      RoleCommandOrder rco = getRoleCommandOrder(cluster);
      rg = roleGraphFactory.createNew(rco);
    } else {
      rg = roleGraphFactory.createNew();
    }

    rg.build(stage);
    List<Stage> stages = rg.getStages();

    if (stages != null && !stages.isEmpty()) {
      requestStageContainer.addStages(stages);
    }

    // If the request is to perform the Kerberos service check, delete the test-specific principal
    // and keytab that was created for this service check
    if (kerberosServiceCheck) {
      // Parse the command parameters into a map so that existing values may be accessed and
      // additional values may be added to it.
      commandParamsStage = gson.fromJson(commandParamsForStage,
          new TypeToken<Map<String, String>>() {
          }.getType());

      try {
        requestStageContainer = kerberosHelper.deleteTestIdentity(cluster, commandParamsStage, requestStageContainer);
      } catch (KerberosOperationException e) {
        throw new IllegalArgumentException(e.getMessage(), e);
      }
    }

    requestStageContainer.persist();
    return requestStageContainer.getRequestStatusResponse();
  }
Chooses a healthy host from the list of candidate hosts randomly. If there
are no healthy hosts, then this method will return {@code null}.
<p/>
The host's {@link HostState} is used to determine if a host is healthy.

@return a random healthy host, or {@code null}.
@throws AmbariException
@see {@link HostState#HEALTHY}
ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java