瀏覽代碼

AMBARI-6665. Unable to Deploy New Cluster Due to RecommendationService (Jonathan Hurley via ncole)

Nate Cole 11 年之前
父節點
當前提交
cc51c2a60d

+ 46 - 25
ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRunner.java

@@ -20,17 +20,19 @@ package org.apache.ambari.server.api.services.stackadvisor;
 
 import java.io.File;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 
 import org.apache.commons.io.FileUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.inject.Singleton;
 
 @Singleton
 public class StackAdvisorRunner {
 
-  private static Log LOG = LogFactory.getLog(StackAdvisorRunner.class);
+  private final static Logger LOG = LoggerFactory.getLogger(StackAdvisorRunner.class);
 
   /**
    * Runs stack_advisor.py script in the specified {@code actionDirectory}.
@@ -42,66 +44,85 @@ public class StackAdvisorRunner {
    *         otherwise.
    */
   public boolean runScript(String script, StackAdvisorCommand saCommand, File actionDirectory) {
-    LOG.info(String.format("Script=%s, actionDirectory=%s, command=%s", script, actionDirectory,
-        saCommand));
+    LOG.info("Script={}, actionDirectory={}, command={}", script,
+        actionDirectory, saCommand);
 
     String outputFile = actionDirectory + File.separator + "stackadvisor.out";
     String errorFile = actionDirectory + File.separator + "stackadvisor.err";
 
-    String shellCommand[] = prepareShellCommand(script, saCommand, actionDirectory, outputFile,
+    ProcessBuilder builder = prepareShellCommand(script, saCommand,
+        actionDirectory, outputFile,
         errorFile);
-    String[] env = new String[] {};
 
     try {
-      Process process = Runtime.getRuntime().exec(shellCommand, env);
+      Process process = builder.start();
 
       try {
-        LOG.info(String.format("Stack-advisor output=%s, error=%s", outputFile, errorFile));
+        LOG.info("Stack-advisor output={}, error={}", outputFile, errorFile);
 
         int exitCode = process.waitFor();
         try {
           String outMessage = FileUtils.readFileToString(new File(outputFile));
           String errMessage = FileUtils.readFileToString(new File(errorFile));
-          LOG.info("Script log message: " + outMessage + "\n\n" + errMessage);
+          LOG.info("Stack advisor output files");
+          LOG.info("    advisor script stdout: {}", outMessage);
+          LOG.info("    advisor script stderr: {}", errMessage);
         } catch (IOException io) {
-          LOG.info("Error in reading script log files", io);
+          LOG.error("Error in reading script log files", io);
         }
 
         return exitCode == 0;
       } finally {
         process.destroy();
       }
-    } catch (Exception io) {
-      LOG.info("Error executing stack advisor " + io.getMessage());
+    } catch (Exception ioe) {
+      LOG.error("Error executing stack advisor", ioe);
       return false;
     }
   }
 
-  private String[] prepareShellCommand(String script, StackAdvisorCommand saCommand,
+  /**
+   * Gets an instance of a {@link ProcessBuilder} that's ready to execute the
+   * shell command to run the stack advisor script. This will take the
+   * environment variables from the current process.
+   * 
+   * @param script
+   * @param saCommand
+   * @param actionDirectory
+   * @param outputFile
+   * @param errorFile
+   * @return
+   */
+  private ProcessBuilder prepareShellCommand(String script,
+      StackAdvisorCommand saCommand,
       File actionDirectory, String outputFile, String errorFile) {
     String hostsFile = actionDirectory + File.separator + "hosts.json";
     String servicesFile = actionDirectory + File.separator + "services.json";
 
-    String shellCommand[] = new String[] { "sh", "-c", null /* to be calculated */};
-    String commands[] = new String[] { script, saCommand.toString(), hostsFile, servicesFile };
+    // includes the original command plus the arguments for it
+    List<String> builderParameters = new ArrayList<String>();
+    builderParameters.add("sh");
+    builderParameters.add("-c");
+
+    // for the 3rd argument, build a single parameter since we use -c
+    // ProcessBuilder doesn't support output redirection until JDK 1.7
+    String commandStringParameters[] = new String[] { script,
+        saCommand.toString(), hostsFile,
+        servicesFile, "1>", outputFile, "2>", errorFile };
 
     StringBuilder commandString = new StringBuilder();
-    for (String command : commands) {
-      commandString.append(" " + command);
+    for (String command : commandStringParameters) {
+      commandString.append(command).append(" ");
     }
 
-    if (LOG.isDebugEnabled()) {
-      LOG.debug(commandString);
-    }
+    builderParameters.add(commandString.toString());
 
-    commandString.append(" 1> " + outputFile + " 2>" + errorFile);
-    shellCommand[2] = commandString.toString();
+    LOG.debug("Stack advisor command is {}", builderParameters);
 
-    return shellCommand;
+    return new ProcessBuilder(builderParameters);
   }
 
   public enum StackAdvisorCommand {
-
     RECOMMEND_COMPONENT_LAYOUT("recommend-component-layout"),
 
     VALIDATE_COMPONENT_LAYOUT("validate-component-layout"),