Browse Source

[FIX-3900][server] Cherry pick from dev to kill multi yarn app in one job (#4151)

* [FIX-3900][server] Cherry pick from dev to kill multi yarn app in one job

* [FIX-3900][server] Cherry pick from dev to kill multi yarn app in one job

Co-authored-by: Eights-LI <yelli.eights@gmail.com>
lgcareer 4 years ago committed by GitHub
parent
commit
d796a63b12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/Constants.java
  2. 714
      dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/utils/ProcessUtils.java
  3. 111
      dolphinscheduler-server/src/test/java/org/apache/dolphinscheduler/server/utils/ProcessUtilsTest.java

10
dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/Constants.java

@ -970,4 +970,14 @@ public final class Constants {
public static final int ABNORMAL_NODE_STATUS = 1; public static final int ABNORMAL_NODE_STATUS = 1;
/**
* exec shell scripts
*/
public static final String SH = "sh";
/**
* pstree, get pud and sub pid
*/
public static final String PSTREE = "pstree";
} }

714
dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/utils/ProcessUtils.java

@ -16,392 +16,436 @@
*/ */
package org.apache.dolphinscheduler.server.utils; package org.apache.dolphinscheduler.server.utils;
import java.nio.charset.StandardCharsets;
import org.apache.dolphinscheduler.common.Constants; import org.apache.dolphinscheduler.common.Constants;
import org.apache.dolphinscheduler.common.enums.ExecutionStatus;
import org.apache.dolphinscheduler.common.utils.CollectionUtils;
import org.apache.dolphinscheduler.common.utils.CommonUtils; import org.apache.dolphinscheduler.common.utils.CommonUtils;
import org.apache.dolphinscheduler.common.utils.FileUtils;
import org.apache.dolphinscheduler.common.utils.HadoopUtils;
import org.apache.dolphinscheduler.common.utils.LoggerUtils; import org.apache.dolphinscheduler.common.utils.LoggerUtils;
import org.apache.dolphinscheduler.common.utils.OSUtils; import org.apache.dolphinscheduler.common.utils.OSUtils;
import org.apache.dolphinscheduler.common.utils.StringUtils; import org.apache.dolphinscheduler.common.utils.StringUtils;
import org.apache.commons.io.FileUtils;
import org.apache.dolphinscheduler.remote.utils.Host; import org.apache.dolphinscheduler.remote.utils.Host;
import org.apache.dolphinscheduler.server.entity.TaskExecutionContext; import org.apache.dolphinscheduler.server.entity.TaskExecutionContext;
import org.apache.dolphinscheduler.service.log.LogClientService; import org.apache.dolphinscheduler.service.log.LogClientService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/** /**
* mainly used to get the start command line of a process * mainly used to get the start command line of a process.
*/ */
public class ProcessUtils { public class ProcessUtils {
/** /**
* logger * logger
*/ */
private final static Logger logger = LoggerFactory.getLogger(ProcessUtils.class); private static final Logger logger = LoggerFactory.getLogger(ProcessUtils.class);
/** /**
* build command line characters * Initialization regularization, solve the problem of pre-compilation performance,
* @param commandList command list * avoid the thread safety problem of multi-thread operation.
* @return command */
* @throws IOException io exception private static final Pattern MACPATTERN = Pattern.compile("-[+|-]-\\s(\\d+)");
*/
public static String buildCommandStr(List<String> commandList) throws IOException { private static final Pattern LINUXPATTERN = Pattern.compile("(\\d+)");
String cmdstr;
String[] cmd = commandList.toArray(new String[commandList.size()]); private static final String LOCAL_PROCESS_EXEC = "jdk.lang.Process.allowAmbiguousCommands";
SecurityManager security = System.getSecurityManager();
boolean allowAmbiguousCommands = false; /**
if (security == null) { * build command line characters.
allowAmbiguousCommands = true; *
String value = System.getProperty("jdk.lang.Process.allowAmbiguousCommands"); * @param commandList command list
if (value != null) { * @return command
allowAmbiguousCommands = !"false".equalsIgnoreCase(value); * @throws IOException io exception
} */
public static String buildCommandStr(List<String> commandList) throws IOException {
String cmdstr;
String[] cmd = commandList.toArray(new String[0]);
SecurityManager security = System.getSecurityManager();
boolean allowAmbiguousCommands = isAllowAmbiguousCommands(security);
if (allowAmbiguousCommands) {
String executablePath = new File(cmd[0]).getPath();
if (needsEscaping(VERIFICATION_LEGACY, executablePath)) {
executablePath = quoteString(executablePath);
}
cmdstr = createCommandLine(
VERIFICATION_LEGACY, executablePath, cmd);
} else {
String executablePath;
try {
executablePath = getExecutablePath(cmd[0]);
} catch (IllegalArgumentException e) {
StringBuilder join = new StringBuilder();
for (String s : cmd) {
join.append(s).append(' ');
}
cmd = getTokensFromCommand(join.toString());
executablePath = getExecutablePath(cmd[0]);
// Check new executable name once more
if (security != null) {
security.checkExec(executablePath);
}
}
cmdstr = createCommandLine(
isShellFile(executablePath) ? VERIFICATION_CMD_BAT : VERIFICATION_WIN32, quoteString(executablePath), cmd);
}
return cmdstr;
} }
if (allowAmbiguousCommands) {
String executablePath = new File(cmd[0]).getPath(); /**
* check is allow ambiguous commands
if (needsEscaping(VERIFICATION_LEGACY, executablePath)) { *
executablePath = quoteString(executablePath); * @param security security manager
} * @return allow ambiguous command flag
*/
cmdstr = createCommandLine( private static boolean isAllowAmbiguousCommands(SecurityManager security) {
VERIFICATION_LEGACY, executablePath, cmd); boolean allowAmbiguousCommands = false;
} else { if (security == null) {
String executablePath; allowAmbiguousCommands = true;
try { String value = System.getProperty(LOCAL_PROCESS_EXEC);
executablePath = getExecutablePath(cmd[0]); if (value != null) {
} catch (IllegalArgumentException e) { allowAmbiguousCommands = !Constants.STRING_FALSE.equalsIgnoreCase(value);
}
StringBuilder join = new StringBuilder();
for (String s : cmd) {
join.append(s).append(' ');
} }
return allowAmbiguousCommands;
}
cmd = getTokensFromCommand(join.toString()); /**
executablePath = getExecutablePath(cmd[0]); * get executable path.
*
// Check new executable name once more * @param path path
if (security != null) { * @return executable path
security.checkExec(executablePath); * @throws IOException io exception
} */
} private static String getExecutablePath(String path) throws IOException {
boolean pathIsQuoted = isQuoted(true, path, "Executable name has embedded quote, split the arguments");
File fileToRun = new File(pathIsQuoted ? path.substring(1, path.length() - 1) : path);
return fileToRun.getPath();
}
/**
* whether is shell file.
*
* @param executablePath executable path
* @return true if endsWith .CMD or .BAT
*/
private static boolean isShellFile(String executablePath) {
String upPath = executablePath.toUpperCase();
return (upPath.endsWith(".CMD") || upPath.endsWith(".BAT"));
}
cmdstr = createCommandLine( /**
* quote string
*
* @param arg argument
* @return format arg
*/
private static String quoteString(String arg) {
StringBuilder argbuf = new StringBuilder(arg.length() + 2);
return argbuf.append('"').append(arg).append('"').toString();
}
isShellFile(executablePath) ? VERIFICATION_CMD_BAT : VERIFICATION_WIN32, quoteString(executablePath), cmd); /**
* get tokens from command.
*
* @param command command
* @return token string array
*/
private static String[] getTokensFromCommand(String command) {
ArrayList<String> matchList = new ArrayList<>(8);
Matcher regexMatcher = LazyPattern.PATTERN.matcher(command);
while (regexMatcher.find()) {
matchList.add(regexMatcher.group());
}
return matchList.toArray(new String[0]);
} }
return cmdstr;
} /**
* Lazy Pattern
/** */
* get executable path private static class LazyPattern {
* /**
* @param path path * Escape-support version:
* @return executable path * "(\")((?:\\\\\\1|.)+?)\\1|([^\\s\"]+)";
* @throws IOException io exception */
*/ private static final Pattern PATTERN = Pattern.compile("[^\\s\"]+|\"[^\"]*\"");
private static String getExecutablePath(String path) throws IOException {
boolean pathIsQuoted = isQuoted(true, path, "Executable name has embedded quote, split the arguments");
File fileToRun = new File(pathIsQuoted ? path.substring(1, path.length() - 1) : path);
return fileToRun.getPath();
}
/**
* whether is shell file
*
* @param executablePath executable path
* @return true if endsWith .CMD or .BAT
*/
private static boolean isShellFile(String executablePath) {
String upPath = executablePath.toUpperCase();
return (upPath.endsWith(".CMD") || upPath.endsWith(".BAT"));
}
/**
* quote string
*
* @param arg argument
* @return format arg
*/
private static String quoteString(String arg) {
StringBuilder argbuf = new StringBuilder(arg.length() + 2);
return argbuf.append('"').append(arg).append('"').toString();
}
/**
* get tokens from command
*
* @param command command
* @return token string array
*/
private static String[] getTokensFromCommand(String command) {
ArrayList<String> matchList = new ArrayList<>(8);
Matcher regexMatcher = LazyPattern.PATTERN.matcher(command);
while (regexMatcher.find()) {
matchList.add(regexMatcher.group());
} }
return matchList.toArray(new String[matchList.size()]);
} /**
* verification cmd bat
/** */
* Lazy Pattern private static final int VERIFICATION_CMD_BAT = 0;
*/
private static class LazyPattern { /**
// Escape-support version: * verification win32
// "(\")((?:\\\\\\1|.)+?)\\1|([^\\s\"]+)"; */
private static final Pattern PATTERN = Pattern.compile("[^\\s\"]+|\"[^\"]*\""); private static final int VERIFICATION_WIN32 = 1;
}
/**
/** * verification legacy
* verification cmd bat */
*/ private static final int VERIFICATION_LEGACY = 2;
private static final int VERIFICATION_CMD_BAT = 0;
/**
/** * escape verification
* verification win32 */
*/ private static final char[][] ESCAPE_VERIFICATION = {{' ', '\t', '<', '>', '&', '|', '^'},
private static final int VERIFICATION_WIN32 = 1;
{' ', '\t', '<', '>'}, {' ', '\t'}};
/**
* verification legacy /**
*/ * create command line
private static final int VERIFICATION_LEGACY = 2; *
* @param verificationType verification type
/** * @param executablePath executable path
* escape verification * @param cmd cmd
*/ * @return command line
private static final char[][] ESCAPE_VERIFICATION = {{' ', '\t', '<', '>', '&', '|', '^'}, */
private static String createCommandLine(int verificationType, final String executablePath, final String[] cmd) {
{' ', '\t', '<', '>'}, {' ', '\t'}}; StringBuilder cmdbuf = new StringBuilder(80);
/** cmdbuf.append(executablePath);
* matcher
*/ for (int i = 1; i < cmd.length; ++i) {
private static Matcher matcher; cmdbuf.append(' ');
String s = cmd[i];
/** if (needsEscaping(verificationType, s)) {
* create command line cmdbuf.append('"').append(s);
* @param verificationType verification type
* @param executablePath executable path if ((verificationType != VERIFICATION_CMD_BAT) && s.endsWith("\\")) {
* @param cmd cmd cmdbuf.append('\\');
* @return command line }
*/ cmdbuf.append('"');
private static String createCommandLine(int verificationType, final String executablePath, final String[] cmd) { } else {
StringBuilder cmdbuf = new StringBuilder(80); cmdbuf.append(s);
}
cmdbuf.append(executablePath);
for (int i = 1; i < cmd.length; ++i) {
cmdbuf.append(' ');
String s = cmd[i];
if (needsEscaping(verificationType, s)) {
cmdbuf.append('"').append(s);
if ((verificationType != VERIFICATION_CMD_BAT) && s.endsWith("\\")) {
cmdbuf.append('\\');
} }
cmdbuf.append('"'); return cmdbuf.toString();
} else {
cmdbuf.append(s);
}
} }
return cmdbuf.toString();
} /**
* whether is quoted
/** *
* whether is quoted * @param noQuotesInside no quotes inside
* @param noQuotesInside * @param arg arg
* @param arg * @param errorMessage error message
* @param errorMessage * @return boolean
* @return boolean */
*/ private static boolean isQuoted(boolean noQuotesInside, String arg, String errorMessage) {
private static boolean isQuoted(boolean noQuotesInside, String arg, String errorMessage) { int lastPos = arg.length() - 1;
int lastPos = arg.length() - 1; if (lastPos >= 1 && arg.charAt(0) == '"' && arg.charAt(lastPos) == '"') {
if (lastPos >= 1 && arg.charAt(0) == '"' && arg.charAt(lastPos) == '"') { // The argument has already been quoted.
// The argument has already been quoted. if (noQuotesInside && arg.indexOf('"', 1) != lastPos) {
if (noQuotesInside) { // There is ["] inside.
if (arg.indexOf('"', 1) != lastPos) { throw new IllegalArgumentException(errorMessage);
// There is ["] inside. }
throw new IllegalArgumentException(errorMessage); return true;
} }
} if (noQuotesInside && arg.indexOf('"') >= 0) {
return true; // There is ["] inside.
} throw new IllegalArgumentException(errorMessage);
if (noQuotesInside) {
if (arg.indexOf('"') >= 0) {
// There is ["] inside.
throw new IllegalArgumentException(errorMessage);
}
}
return false;
}
/**
* whether needs escaping
*
* @param verificationType verification type
* @param arg arg
* @return boolean
*/
private static boolean needsEscaping(int verificationType, String arg) {
boolean argIsQuoted = isQuoted((verificationType == VERIFICATION_CMD_BAT), arg, "Argument has embedded quote, use the explicit CMD.EXE call.");
if (!argIsQuoted) {
char[] testEscape = ESCAPE_VERIFICATION[verificationType];
for (int i = 0; i < testEscape.length; ++i) {
if (arg.indexOf(testEscape[i]) >= 0) {
return true;
} }
} return false;
} }
return false;
}
/**
* kill yarn application
*
* @param appIds app id list
* @param logger logger
* @param tenantCode tenant code
* @param executePath execute path
* @throws IOException io exception
*/
public static void cancelApplication(List<String> appIds, Logger logger, String tenantCode,String executePath)
throws IOException {
if (appIds.size() > 0) {
String appid = appIds.get(appIds.size() - 1);
String commandFile = String
.format("%s/%s.kill", executePath, appid);
String cmd = "yarn application -kill " + appid;
try {
StringBuilder sb = new StringBuilder();
sb.append("#!/bin/sh\n");
sb.append("BASEDIR=$(cd `dirname $0`; pwd)\n");
sb.append("cd $BASEDIR\n");
if (CommonUtils.getSystemEnvPath() != null) {
sb.append("source " + CommonUtils.getSystemEnvPath() + "\n");
}
sb.append("\n\n");
sb.append(cmd);
File f = new File(commandFile);
if (!f.exists()) { /**
FileUtils.writeStringToFile(new File(commandFile), sb.toString(), StandardCharsets.UTF_8); * whether needs escaping
*
* @param verificationType verification type
* @param arg arg
* @return boolean
*/
private static boolean needsEscaping(int verificationType, String arg) {
boolean argIsQuoted = isQuoted((verificationType == VERIFICATION_CMD_BAT), arg, "Argument has embedded quote, use the explicit CMD.EXE call.");
if (!argIsQuoted) {
char[] testEscape = ESCAPE_VERIFICATION[verificationType];
for (char c : testEscape) {
if (arg.indexOf(c) >= 0) {
return true;
}
}
} }
return false;
}
String runCmd = "sh " + commandFile; /**
if (StringUtils.isNotEmpty(tenantCode)) { * kill yarn application
runCmd = "sudo -u " + tenantCode + " " + runCmd; *
* @param appIds app id list
* @param logger logger
* @param tenantCode tenant code
* @param executePath execute path
*/
public static void cancelApplication(List<String> appIds, Logger logger, String tenantCode, String executePath) {
if (CollectionUtils.isNotEmpty(appIds)) {
for (String appId : appIds) {
try {
ExecutionStatus applicationStatus = HadoopUtils.getInstance().getApplicationStatus(appId);
if (!applicationStatus.typeIsFinished()) {
String commandFile = String
.format("%s/%s.kill", executePath, appId);
String cmd = "yarn application -kill " + appId;
execYarnKillCommand(logger, tenantCode, appId, commandFile, cmd);
}
} catch (Exception e) {
logger.error(String.format("Get yarn application app id [%s] status failed: [%s]", appId, e.getMessage()));
}
}
} }
}
logger.info("kill cmd:{}", runCmd); /**
* build kill command for yarn application
Runtime.getRuntime().exec(runCmd); *
} catch (Exception e) { * @param logger logger
logger.error("kill application error", e); * @param tenantCode tenant code
} * @param appId app id
* @param commandFile command file
* @param cmd cmd
*/
private static void execYarnKillCommand(Logger logger, String tenantCode, String appId, String commandFile, String cmd) {
try {
StringBuilder sb = new StringBuilder();
sb.append("#!/bin/sh\n");
sb.append("BASEDIR=$(cd `dirname $0`; pwd)\n");
sb.append("cd $BASEDIR\n");
if (CommonUtils.getSystemEnvPath() != null) {
sb.append("source ").append(CommonUtils.getSystemEnvPath()).append("\n");
}
sb.append("\n\n");
sb.append(cmd);
File f = new File(commandFile);
if (!f.exists()) {
FileUtils.writeStringToFile(new File(commandFile), sb.toString(), StandardCharsets.UTF_8);
}
String runCmd = String.format("%s %s", Constants.SH, commandFile);
if (StringUtils.isNotEmpty(tenantCode)) {
runCmd = "sudo -u " + tenantCode + " " + runCmd;
}
logger.info("kill cmd:{}", runCmd);
OSUtils.exeCmd(runCmd);
} catch (Exception e) {
logger.error(String.format("Kill yarn application app id [%s] failed: [%s]", appId, e.getMessage()));
}
} }
}
/** /**
* kill tasks according to different task types * kill tasks according to different task types
* *
* @param taskExecutionContext taskExecutionContext * @param taskExecutionContext taskExecutionContext
*/ */
public static void kill(TaskExecutionContext taskExecutionContext) { public static void kill(TaskExecutionContext taskExecutionContext) {
try { try {
int processId = taskExecutionContext.getProcessId(); int processId = taskExecutionContext.getProcessId();
if(processId == 0 ){ if (processId == 0) {
logger.error("process kill failed, process id :{}, task id:{}", logger.error("process kill failed, process id :{}, task id:{}",
processId, taskExecutionContext.getTaskInstanceId()); processId, taskExecutionContext.getTaskInstanceId());
return ; return;
} }
String cmd = String.format("sudo kill -9 %s", getPidsStr(processId)); String cmd = String.format("sudo kill -9 %s", getPidsStr(processId));
logger.info("process id:{}, cmd:{}", processId, cmd); logger.info("process id:{}, cmd:{}", processId, cmd);
OSUtils.exeCmd(cmd); OSUtils.exeCmd(cmd);
// find log and kill yarn job // find log and kill yarn job
killYarnJob(taskExecutionContext); killYarnJob(taskExecutionContext);
} catch (Exception e) { } catch (Exception e) {
logger.error("kill task failed", e); logger.error("kill task failed", e);
} }
}
/**
* get pids str
*
* @param processId process id
* @return pids
* @throws Exception exception
*/
public static String getPidsStr(int processId)throws Exception{
StringBuilder sb = new StringBuilder();
Matcher mat;
// pstree pid get sub pids
if (OSUtils.isMacOS()) {
String pids = OSUtils.exeCmd("pstree -sp " + processId);
mat = Pattern.compile("-[+|-]-\\s(\\d+)").matcher(pids);
} else {
String pids = OSUtils.exeCmd("pstree -p " + processId);
mat = Pattern.compile("(\\d+)").matcher(pids);
} }
while (mat.find()){ /**
sb.append(mat.group(1)).append(" "); * get pids str
} *
return sb.toString().trim(); * @param processId process id
} * @return pids pid String
* @throws Exception exception
/** */
* find logs and kill yarn tasks public static String getPidsStr(int processId) throws Exception {
* StringBuilder sb = new StringBuilder();
* @param taskExecutionContext taskExecutionContext Matcher mat = null;
*/ // pstree pid get sub pids
public static void killYarnJob(TaskExecutionContext taskExecutionContext) { if (OSUtils.isMacOS()) {
try { String pids = OSUtils.exeCmd(String.format("%s -sp %d", Constants.PSTREE, processId));
Thread.sleep(Constants.SLEEP_TIME_MILLIS); if (null != pids) {
LogClientService logClient = null; mat = MACPATTERN.matcher(pids);
String log = null; }
try { } else {
logClient = new LogClientService(); String pids = OSUtils.exeCmd(String.format("%s -p %d", Constants.PSTREE, processId));
log = logClient.viewLog(Host.of(taskExecutionContext.getHost()).getIp(), mat = LINUXPATTERN.matcher(pids);
Constants.RPC_PORT,
taskExecutionContext.getLogPath());
} finally {
if(logClient != null){
logClient.close();
}
}
if (StringUtils.isNotEmpty(log)) {
List<String> appIds = LoggerUtils.getAppIds(log, logger);
String workerDir = taskExecutionContext.getExecutePath();
if (StringUtils.isEmpty(workerDir)) {
logger.error("task instance work dir is empty");
throw new RuntimeException("task instance work dir is empty");
} }
if (appIds.size() > 0) {
cancelApplication(appIds, logger, taskExecutionContext.getTenantCode(), taskExecutionContext.getExecutePath()); if (null != mat) {
while (mat.find()) {
sb.append(mat.group(1)).append(" ");
}
} }
}
} catch (Exception e) { return sb.toString().trim();
logger.error("kill yarn job failure",e); }
/**
* find logs and kill yarn tasks
*
* @param taskExecutionContext taskExecutionContext
*/
public static void killYarnJob(TaskExecutionContext taskExecutionContext) {
try {
Thread.sleep(Constants.SLEEP_TIME_MILLIS);
LogClientService logClient = null;
String log;
try {
logClient = new LogClientService();
log = logClient.viewLog(Host.of(taskExecutionContext.getHost()).getIp(),
Constants.RPC_PORT,
taskExecutionContext.getLogPath());
} finally {
if (logClient != null) {
logClient.close();
}
}
if (StringUtils.isNotEmpty(log)) {
List<String> appIds = LoggerUtils.getAppIds(log, logger);
String workerDir = taskExecutionContext.getExecutePath();
if (StringUtils.isEmpty(workerDir)) {
logger.error("task instance work dir is empty");
throw new RuntimeException("task instance work dir is empty");
}
if (CollectionUtils.isNotEmpty(appIds)) {
cancelApplication(appIds, logger, taskExecutionContext.getTenantCode(), taskExecutionContext.getExecutePath());
}
}
} catch (Exception e) {
logger.error("kill yarn job failure", e);
}
} }
}
} }

111
dolphinscheduler-server/src/test/java/org/apache/dolphinscheduler/server/utils/ProcessUtilsTest.java

@ -16,35 +16,124 @@
*/ */
package org.apache.dolphinscheduler.server.utils; package org.apache.dolphinscheduler.server.utils;
import org.junit.Assert; import static org.powermock.api.mockito.PowerMockito.when;
import org.junit.Test;
import org.slf4j.Logger; import org.apache.dolphinscheduler.common.Constants;
import org.slf4j.LoggerFactory; import org.apache.dolphinscheduler.common.enums.ExecutionStatus;
import org.apache.dolphinscheduler.common.utils.HadoopUtils;
import org.apache.dolphinscheduler.common.utils.OSUtils;
import org.apache.dolphinscheduler.server.entity.TaskExecutionContext;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@RunWith(PowerMockRunner.class)
@PrepareForTest({System.class, OSUtils.class, HadoopUtils.class})
public class ProcessUtilsTest { public class ProcessUtilsTest {
private static final Logger logger = LoggerFactory.getLogger(ProcessUtilsTest.class); private static final Logger logger = LoggerFactory.getLogger(ProcessUtils.class);
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test @Test
public void getPidsStr() throws Exception { public void getPidsStr() throws Exception {
String pidList = ProcessUtils.getPidsStr(1); int processId = 1;
String pidList = ProcessUtils.getPidsStr(processId);
Assert.assertNotEquals("The child process of process 1 should not be empty", pidList, ""); Assert.assertNotEquals("The child process of process 1 should not be empty", pidList, "");
logger.info("Sub process list : {}", pidList);
PowerMockito.mockStatic(OSUtils.class);
when(OSUtils.isMacOS()).thenReturn(true);
when(OSUtils.exeCmd(String.format("%s -p %d", Constants.PSTREE, processId))).thenReturn(null);
String pidListMac = ProcessUtils.getPidsStr(processId);
Assert.assertEquals("", pidListMac);
} }
@Test @Test
public void testBuildCommandStr() { public void testBuildCommandStr() throws IOException {
List<String> commands = new ArrayList<>(); List<String> commands = new ArrayList<>();
commands.add("sudo"); commands.add("sudo");
commands.add("-u");
commands.add("tenantCode");
//allowAmbiguousCommands false
Assert.assertEquals("sudo -u tenantCode", ProcessUtils.buildCommandStr(commands));
//quota
commands.clear();
commands.add("\"sudo\"");
Assert.assertEquals("\"sudo\"", ProcessUtils.buildCommandStr(commands));
//allowAmbiguousCommands true
commands.clear();
commands.add("sudo");
System.setProperty("jdk.lang.Process.allowAmbiguousCommands", "false");
Assert.assertEquals("\"sudo\"", ProcessUtils.buildCommandStr(commands));
}
@Test
public void testKill() {
//get taskExecutionContext
TaskExecutionContext taskExecutionContext = new TaskExecutionContext();
//process id eq 0
taskExecutionContext.setProcessId(0);
ProcessUtils.kill(taskExecutionContext);
//process id not eq 0
taskExecutionContext.setProcessId(1);
PowerMockito.mockStatic(OSUtils.class);
try { try {
Assert.assertEquals(ProcessUtils.buildCommandStr(commands), "sudo"); when(OSUtils.exeCmd(String.format("%s -sp %d", Constants.PSTREE, 1))).thenReturn("1111");
} catch (IOException e) { when(OSUtils.exeCmd(String.format("%s -p %d", Constants.PSTREE, 1))).thenReturn("1111");
Assert.fail(e.getMessage()); when(OSUtils.exeCmd("sudo kill -9")).thenReturn("1111");
} catch (Exception e) {
e.printStackTrace();
} }
taskExecutionContext.setHost("127.0.0.1:8888");
taskExecutionContext.setLogPath("/log/1.log");
ProcessUtils.kill(taskExecutionContext);
Assert.assertEquals(1, taskExecutionContext.getProcessId());
} }
@Test
public void testCancelApplication() {
List<String> appIds = new ArrayList<>();
appIds.add("application_1585532379175_228491");
appIds.add("application_1598885606600_3677");
String tenantCode = "dev";
String executePath = "/ds-exec/1/1/1";
ExecutionStatus running = ExecutionStatus.RUNNING_EXEUTION;
PowerMockito.mockStatic(HadoopUtils.class);
HadoopUtils hadoop = HadoopUtils.getInstance();
try {
PowerMockito.whenNew(HadoopUtils.class).withAnyArguments().thenReturn(hadoop);
} catch (Exception e) {
e.printStackTrace();
}
try {
when(hadoop.getApplicationStatus("application_1585532379175_228491")).thenReturn(running);
when(hadoop.getApplicationStatus("application_1598885606600_3677")).thenReturn(running);
} catch (Exception e) {
e.printStackTrace();
ProcessUtils.cancelApplication(appIds, logger, tenantCode, executePath);
}
Assert.assertNotNull(appIds);
}
} }

Loading…
Cancel
Save