Merge pull request #17 from shapeblue/outofbandmanagement-4.5

CLOUDSTACK-9299: Sync changes from upstream oobm PR
This commit is contained in:
Rohit Yadav 2016-05-13 08:36:29 +05:30
commit 0a6f930a31
7 changed files with 160 additions and 116 deletions

View File

@ -17,6 +17,7 @@
package org.apache.cloudstack.outofbandmanagement.driver.ipmitool;
import com.cloud.utils.component.AdapterBase;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.exception.CloudRuntimeException;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
@ -24,6 +25,7 @@ import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement;
import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementDriver;
import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService;
import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverChangePasswordCommand;
import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverCommand;
import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverPowerCommand;
@ -33,20 +35,25 @@ import org.joda.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class IpmitoolOutOfBandManagementDriver extends AdapterBase implements OutOfBandManagementDriver, Configurable {
public final class IpmitoolOutOfBandManagementDriver extends AdapterBase implements OutOfBandManagementDriver, Configurable {
public static final Logger LOG = Logger.getLogger(IpmitoolOutOfBandManagementDriver.class);
private static volatile boolean isDriverEnabled = false;
private static boolean isIpmiToolBinAvailable = false;
ConfigKey<String> IpmiToolPath = new ConfigKey<String>("Advanced", String.class, "outofbandmanagement.ipmitool.path", "/usr/bin/ipmitool",
private final ExecutorService ipmitoolExecutor = Executors.newFixedThreadPool(OutOfBandManagementService.SyncThreadPoolSize.value(), new NamedThreadFactory("IpmiToolDriver"));
private final IpmitoolWrapper IPMITOOL = new IpmitoolWrapper(ipmitoolExecutor);
public final ConfigKey<String> IpmiToolPath = new ConfigKey<String>("Advanced", String.class, "outofbandmanagement.ipmitool.path", "/usr/bin/ipmitool",
"The out of band management ipmitool path used by the IpmiTool driver. Default: /usr/bin/ipmitool.", true, ConfigKey.Scope.Global);
ConfigKey<String> IpmiToolInterface = new ConfigKey<String>("Advanced", String.class, "outofbandmanagement.ipmitool.interface", "lanplus",
public final ConfigKey<String> IpmiToolInterface = new ConfigKey<String>("Advanced", String.class, "outofbandmanagement.ipmitool.interface", "lanplus",
"The out of band management IpmiTool driver interface to use. Default: lanplus. Valid values are: lan, lanplus, open etc.", true, ConfigKey.Scope.Global);
ConfigKey<String> IpmiToolRetries = new ConfigKey<String>("Advanced", String.class, "outofbandmanagement.ipmitool.retries", "1",
public final ConfigKey<String> IpmiToolRetries = new ConfigKey<String>("Advanced", String.class, "outofbandmanagement.ipmitool.retries", "1",
"The out of band management IpmiTool driver retries option -R. Default 1.", true, ConfigKey.Scope.Global);
private String getIpmiUserId(ImmutableMap<OutOfBandManagement.Option, String> options, final Duration timeOut) {
@ -55,16 +62,16 @@ public class IpmitoolOutOfBandManagementDriver extends AdapterBase implements Ou
throw new CloudRuntimeException("Empty IPMI user configured, cannot proceed to find user's ID");
}
final List<String> ipmiToolCommands = IpmitoolWrapper.getIpmiToolCommandArgs(IpmiToolPath.value(),
final List<String> ipmiToolCommands = IPMITOOL.getIpmiToolCommandArgs(IpmiToolPath.value(),
IpmiToolInterface.value(),
IpmiToolRetries.value(),
options, "user", "list");
OutOfBandManagementDriverResponse output = IpmitoolWrapper.executeCommands(ipmiToolCommands, timeOut);
final OutOfBandManagementDriverResponse output = IPMITOOL.executeCommands(ipmiToolCommands, timeOut);
if (!output.isSuccess()) {
throw new CloudRuntimeException("Failed to find IPMI user to change password, error: " + output.getError());
}
final String userId = IpmitoolWrapper.findIpmiUser(output.getResult(), username);
final String userId = IPMITOOL.findIpmiUser(output.getResult(), username);
if (Strings.isNullOrEmpty(userId)) {
throw new CloudRuntimeException("No IPMI user ID found for the username: " + username);
}
@ -97,30 +104,31 @@ public class IpmitoolOutOfBandManagementDriver extends AdapterBase implements Ou
}
private OutOfBandManagementDriverResponse execute(final OutOfBandManagementDriverPowerCommand cmd) {
List<String> ipmiToolCommands = IpmitoolWrapper.getIpmiToolCommandArgs(IpmiToolPath.value(),
List<String> ipmiToolCommands = IPMITOOL.getIpmiToolCommandArgs(IpmiToolPath.value(),
IpmiToolInterface.value(),
IpmiToolRetries.value(),
cmd.getOptions(), "chassis", "power", IpmitoolWrapper.parsePowerCommand(cmd.getPowerOperation()));
OutOfBandManagementDriverResponse response = IpmitoolWrapper.executeCommands(ipmiToolCommands, cmd.getTimeout());
cmd.getOptions(), "chassis", "power", IPMITOOL.parsePowerCommand(cmd.getPowerOperation()));
final OutOfBandManagementDriverResponse response = IPMITOOL.executeCommands(ipmiToolCommands, cmd.getTimeout());
if (response.isSuccess() && cmd.getPowerOperation().equals(OutOfBandManagement.PowerOperation.STATUS)) {
response.setPowerState(IpmitoolWrapper.parsePowerState(response.getResult().trim()));
response.setPowerState(IPMITOOL.parsePowerState(response.getResult().trim()));
}
return response;
}
private OutOfBandManagementDriverResponse execute(final OutOfBandManagementDriverChangePasswordCommand cmd) {
String outOfBandManagementUserId = getIpmiUserId(cmd.getOptions(), cmd.getTimeout());
final String outOfBandManagementUserId = getIpmiUserId(cmd.getOptions(), cmd.getTimeout());
List<String> ipmiToolCommands = IpmitoolWrapper.getIpmiToolCommandArgs(IpmiToolPath.value(),
final List<String> ipmiToolCommands = IPMITOOL.getIpmiToolCommandArgs(IpmiToolPath.value(),
IpmiToolInterface.value(), IpmiToolRetries.value(),
cmd.getOptions(), "user", "set", "password", outOfBandManagementUserId, cmd.getNewPassword());
return IpmitoolWrapper.executeCommands(ipmiToolCommands, cmd.getTimeout());
return IPMITOOL.executeCommands(ipmiToolCommands, cmd.getTimeout());
}
private void initDriver() {
isDriverEnabled = true;
OutOfBandManagementDriverResponse output = IpmitoolWrapper.executeCommands(Arrays.asList(IpmiToolPath.value(), "-V"), Duration.ZERO);
final OutOfBandManagementDriverResponse output = IPMITOOL.executeCommands(Arrays.asList(IpmiToolPath.value(), "-V"));
if (output.isSuccess() && output.getResult().startsWith("ipmitool version")) {
isIpmiToolBinAvailable = true;
LOG.debug("OutOfBandManagementDriver ipmitool initialized: " + output.getResult());
@ -142,6 +150,7 @@ public class IpmitoolOutOfBandManagementDriver extends AdapterBase implements Ou
@Override
public boolean stop() {
ipmitoolExecutor.shutdown();
stopDriver();
return true;
}

View File

@ -31,11 +31,18 @@ import org.joda.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
public class IpmitoolWrapper {
public final class IpmitoolWrapper {
public static final Logger LOG = Logger.getLogger(IpmitoolWrapper.class);
public static String parsePowerCommand(OutOfBandManagement.PowerOperation operation) {
private final ProcessRunner RUNNER;
public IpmitoolWrapper(ExecutorService executor) {
this.RUNNER = new ProcessRunner(executor);
}
public String parsePowerCommand(OutOfBandManagement.PowerOperation operation) {
if (operation == null) {
throw new IllegalStateException("Invalid power operation requested");
}
@ -53,7 +60,7 @@ public class IpmitoolWrapper {
return operation.toString().toLowerCase();
}
public static OutOfBandManagement.PowerState parsePowerState(final String standardOutput) {
public OutOfBandManagement.PowerState parsePowerState(final String standardOutput) {
if (Strings.isNullOrEmpty(standardOutput)) {
return OutOfBandManagement.PowerState.Unknown;
}
@ -65,10 +72,10 @@ public class IpmitoolWrapper {
return OutOfBandManagement.PowerState.Unknown;
}
public static List<String> getIpmiToolCommandArgs(final String ipmiToolPath, final String ipmiInterface, final String retries,
public List<String> getIpmiToolCommandArgs(final String ipmiToolPath, final String ipmiInterface, final String retries,
final ImmutableMap<OutOfBandManagement.Option, String> options, String... commands) {
ImmutableList.Builder<String> ipmiToolCommands = ImmutableList.<String>builder()
final ImmutableList.Builder<String> ipmiToolCommands = ImmutableList.<String>builder()
.add(ipmiToolPath)
.add("-I")
.add(ipmiInterface)
@ -103,7 +110,7 @@ public class IpmitoolWrapper {
return ipmiToolCommands.build();
}
public static String findIpmiUser(final String usersList, final String username) {
public String findIpmiUser(final String usersList, final String username) {
/**
* Expected usersList string contains legends on first line and users on rest
* ID Name Callin Link Auth IPMI Msg Channel Priv Limit
@ -116,12 +123,12 @@ public class IpmitoolWrapper {
// Assuming user 'Name' index on 2nd position
int usernameIndex = 1;
String[] lines = usersList.split("\\r?\\n");
final String[] lines = usersList.split("\\r?\\n");
if (lines.length < 2) {
throw new CloudRuntimeException("Error parsing user ID from ipmi user listing");
}
// Find user and name indexes from the 1st line if not on default position
String[] legends = lines[0].split(" +");
final String[] legends = lines[0].split(" +");
for (int idx = 0; idx < legends.length; idx++) {
if (legends[idx].equals("ID")) {
idIndex = idx;
@ -133,7 +140,7 @@ public class IpmitoolWrapper {
// Find user 'ID' based on provided username and ID/Name positions
String userId = null;
for (int idx = 1; idx < lines.length; idx++) {
String[] words = lines[idx].split(" +");
final String[] words = lines[idx].split(" +");
if (usernameIndex < words.length && idIndex < words.length) {
if (words[usernameIndex].equals(username)) {
userId = words[idIndex];
@ -143,8 +150,12 @@ public class IpmitoolWrapper {
return userId;
}
public static OutOfBandManagementDriverResponse executeCommands(final List<String> commands, final Duration timeOut) {
final ProcessResult result = ProcessRunner.executeCommands(commands, timeOut);
public OutOfBandManagementDriverResponse executeCommands(final List<String> commands) {
return executeCommands(commands, ProcessRunner.DEFAULT_MAX_TIMEOUT);
}
public OutOfBandManagementDriverResponse executeCommands(final List<String> commands, final Duration timeOut) {
final ProcessResult result = RUNNER.executeCommands(commands, timeOut);
if (LOG.isTraceEnabled()) {
List<String> cleanedCommands = new ArrayList<String>();
int maskNextCommand = 0;

View File

@ -19,11 +19,11 @@
package org.apache.cloudstack.outofbandmanagement.driver.ipmitool;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.exception.CloudRuntimeException;
import com.google.common.collect.ImmutableMap;
import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement;
import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverResponse;
import org.joda.time.Duration;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -31,41 +31,44 @@ import org.mockito.runners.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@RunWith(MockitoJUnitRunner.class)
public class IpmitoolWrapperTest {
@Test
public void testParsePowerCommandValid() {
Assert.assertEquals(IpmitoolWrapper.parsePowerCommand(OutOfBandManagement.PowerOperation.ON), "on");
Assert.assertEquals(IpmitoolWrapper.parsePowerCommand(OutOfBandManagement.PowerOperation.OFF), "off");
Assert.assertEquals(IpmitoolWrapper.parsePowerCommand(OutOfBandManagement.PowerOperation.CYCLE), "cycle");
Assert.assertEquals(IpmitoolWrapper.parsePowerCommand(OutOfBandManagement.PowerOperation.RESET), "reset");
Assert.assertEquals(IpmitoolWrapper.parsePowerCommand(OutOfBandManagement.PowerOperation.SOFT), "soft");
Assert.assertEquals(IpmitoolWrapper.parsePowerCommand(OutOfBandManagement.PowerOperation.STATUS), "status");
}
private static final ExecutorService ipmitoolExecutor = Executors.newFixedThreadPool(20, new NamedThreadFactory("IpmiToolDriverTest"));
private static final IpmitoolWrapper IPMITOOL = new IpmitoolWrapper(ipmitoolExecutor);
@Test
public void testParsePowerCommandValid() {
Assert.assertEquals(IPMITOOL.parsePowerCommand(OutOfBandManagement.PowerOperation.ON), "on");
Assert.assertEquals(IPMITOOL.parsePowerCommand(OutOfBandManagement.PowerOperation.OFF), "off");
Assert.assertEquals(IPMITOOL.parsePowerCommand(OutOfBandManagement.PowerOperation.CYCLE), "cycle");
Assert.assertEquals(IPMITOOL.parsePowerCommand(OutOfBandManagement.PowerOperation.RESET), "reset");
Assert.assertEquals(IPMITOOL.parsePowerCommand(OutOfBandManagement.PowerOperation.SOFT), "soft");
Assert.assertEquals(IPMITOOL.parsePowerCommand(OutOfBandManagement.PowerOperation.STATUS), "status");
}
@Test(expected = IllegalStateException.class)
public void testParsePowerCommandInvalid() {
try {
IpmitoolWrapper.parsePowerCommand(null);
Assert.fail("IpmitoolWrapper.parsePowerCommand failed to throw exception on invalid power state");
} catch (IllegalStateException e) {
}
IPMITOOL.parsePowerCommand(null);
Assert.fail("IpmitoolWrapper.parsePowerCommand failed to throw exception on invalid power state");
}
@Test
public void testParsePowerState() {
Assert.assertEquals(IpmitoolWrapper.parsePowerState(null), OutOfBandManagement.PowerState.Unknown);
Assert.assertEquals(IpmitoolWrapper.parsePowerState(""), OutOfBandManagement.PowerState.Unknown);
Assert.assertEquals(IpmitoolWrapper.parsePowerState(" "), OutOfBandManagement.PowerState.Unknown);
Assert.assertEquals(IpmitoolWrapper.parsePowerState("invalid data"), OutOfBandManagement.PowerState.Unknown);
Assert.assertEquals(IpmitoolWrapper.parsePowerState("Chassis Power is on"), OutOfBandManagement.PowerState.On);
Assert.assertEquals(IpmitoolWrapper.parsePowerState("Chassis Power is off"), OutOfBandManagement.PowerState.Off);
Assert.assertEquals(IPMITOOL.parsePowerState(null), OutOfBandManagement.PowerState.Unknown);
Assert.assertEquals(IPMITOOL.parsePowerState(""), OutOfBandManagement.PowerState.Unknown);
Assert.assertEquals(IPMITOOL.parsePowerState(" "), OutOfBandManagement.PowerState.Unknown);
Assert.assertEquals(IPMITOOL.parsePowerState("invalid data"), OutOfBandManagement.PowerState.Unknown);
Assert.assertEquals(IPMITOOL.parsePowerState("Chassis Power is on"), OutOfBandManagement.PowerState.On);
Assert.assertEquals(IPMITOOL.parsePowerState("Chassis Power is off"), OutOfBandManagement.PowerState.Off);
}
@Test
public void testGetIpmiToolCommandArgs() {
List<String> args = IpmitoolWrapper.getIpmiToolCommandArgs("binpath", "intf", "1", null);
List<String> args = IPMITOOL.getIpmiToolCommandArgs("binpath", "intf", "1", null);
assert args != null;
Assert.assertEquals(args.size(), 6);
Assert.assertArrayEquals(args.toArray(), new String[]{"binpath", "-I", "intf", "-R", "1", "-v"});
@ -73,35 +76,39 @@ public class IpmitoolWrapperTest {
ImmutableMap.Builder<OutOfBandManagement.Option, String> argMap = new ImmutableMap.Builder<>();
argMap.put(OutOfBandManagement.Option.DRIVER, "ipmitool");
argMap.put(OutOfBandManagement.Option.ADDRESS, "127.0.0.1");
List<String> argsWithOpts = IpmitoolWrapper.getIpmiToolCommandArgs("binpath", "intf", "1", argMap.build(), "user", "list");
List<String> argsWithOpts = IPMITOOL.getIpmiToolCommandArgs("binpath", "intf", "1", argMap.build(), "user", "list");
assert argsWithOpts != null;
Assert.assertEquals(argsWithOpts.size(), 10);
Assert.assertArrayEquals(argsWithOpts.toArray(), new String[]{"binpath", "-I", "intf", "-R", "1", "-v", "-H", "127.0.0.1", "user", "list"});
}
@Test
public void testFindIpmiUser() {
// Invalid data
try {
IpmitoolWrapper.findIpmiUser("some invalid string\n", "admin");
Assert.fail("IpmitoolWrapper.findIpmiUser failed to throw exception on invalid data");
} catch (CloudRuntimeException ignore) {
}
Assert.assertEquals(IpmitoolWrapper.findIpmiUser("some\ninvalid\ndata\n", "admin"), null);
@Test(expected = CloudRuntimeException.class)
public void testFindIpmiUserInvalid() {
IPMITOOL.findIpmiUser("some invalid string\n", "admin");
Assert.fail("IpmitoolWrapper.findIpmiUser failed to throw exception on invalid data");
// Valid data
Assert.assertEquals(IPMITOOL.findIpmiUser("some\ninvalid\ndata\n", "admin"), null);
}
@Test
public void testFindIpmiUserNull() {
Assert.assertEquals(IPMITOOL.findIpmiUser("some\ninvalid\ndata\n", "admin"), null);
}
@Test
public void testFindIpmiUserValid() {
String usersList = "ID Name\t Callin Link Auth\tIPMI Msg Channel Priv Limit\n" +
"1 admin true true true ADMINISTRATOR\n" +
"2 operator true false false OPERATOR\n" +
"3 user true true true USER\n";
Assert.assertEquals(IpmitoolWrapper.findIpmiUser(usersList, "admin"), "1");
Assert.assertEquals(IpmitoolWrapper.findIpmiUser(usersList, "operator"), "2");
Assert.assertEquals(IpmitoolWrapper.findIpmiUser(usersList, "user"), "3");
Assert.assertEquals(IPMITOOL.findIpmiUser(usersList, "admin"), "1");
Assert.assertEquals(IPMITOOL.findIpmiUser(usersList, "operator"), "2");
Assert.assertEquals(IPMITOOL.findIpmiUser(usersList, "user"), "3");
}
@Test
public void testExecuteCommands() {
OutOfBandManagementDriverResponse r = IpmitoolWrapper.executeCommands(Arrays.asList("ls", "/tmp"), Duration.ZERO);
OutOfBandManagementDriverResponse r = IPMITOOL.executeCommands(Arrays.asList("ls", "/tmp"));
Assert.assertTrue(r.isSuccess());
Assert.assertTrue(r.getResult().length() > 0);
}

View File

@ -70,7 +70,6 @@ class TestOutOfBandManagement(cloudstackTestCase):
if self.server:
self.server.shutdown()
self.server.server_close()
IpmiServerContext('reset')
except Exception as e:
raise Exception("Warning: Exception during cleanup : %s" % e)

View File

@ -51,7 +51,7 @@ setup(name="Marvin",
"paramiko >= 1.13.0",
"nose >= 1.3.3",
"ddt >= 0.4.0",
"ipmisim >= 0.6"
"ipmisim >= 0.7"
],
py_modules=['marvin.marvinPlugin'],
zip_safe=False,

View File

@ -19,43 +19,55 @@
package org.apache.cloudstack.utils.process;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.io.CharStreams;
import org.apache.log4j.Logger;
import org.joda.time.Duration;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class ProcessRunner {
public final class ProcessRunner {
public static final Logger LOG = Logger.getLogger(ProcessRunner.class);
private static final ExecutorService processExecutor = Executors.newCachedThreadPool(new NamedThreadFactory("ProcessRunner"));
// Default maximum timeout of 5 minutes for any command
public static final Duration DEFAULT_MAX_TIMEOUT = new Duration(5 * 60 * 1000);
private final ExecutorService executor;
private static String readStream(final InputStream inputStream) throws IOException {
final StringBuilder sb = new StringBuilder();
final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = bufferedReader.readLine()) != null) {
sb.append(line);
sb.append("\n");
}
return sb.toString();
public ProcessRunner(ExecutorService executor) {
this.executor = executor;
}
public static ProcessResult executeCommands(final List<String> commands, final Duration timeOut) {
Preconditions.checkArgument(commands != null && timeOut != null);
/**
* Executes a process with provided list of commands with a max default timeout
* of 5 minutes
* @param commands list of string commands
* @return returns process result
*/
public ProcessResult executeCommands(final List<String> commands) {
return executeCommands(commands, DEFAULT_MAX_TIMEOUT);
}
/**
* Executes a process with provided list of commands with a given timeout that is less
* than or equal to DEFAULT_MAX_TIMEOUT
* @param commands list of string commands
* @param timeOut timeout duration
* @return returns process result
*/
public ProcessResult executeCommands(final List<String> commands, final Duration timeOut) {
Preconditions.checkArgument(commands != null && timeOut != null
&& timeOut.getStandardSeconds() > 0L
&& (timeOut.compareTo(DEFAULT_MAX_TIMEOUT) <= 0)
&& executor != null);
int retVal = -2;
String stdOutput = null;
@ -63,38 +75,32 @@ public class ProcessRunner {
try {
final Process process = new ProcessBuilder().command(commands).start();
if (timeOut.getStandardSeconds() > 0) {
final Future<Integer> processFuture = processExecutor.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return process.waitFor();
}
});
try {
retVal = processFuture.get(timeOut.getStandardSeconds(), TimeUnit.SECONDS);
} catch (ExecutionException e) {
retVal = -1;
stdError = e.getMessage();
if (LOG.isTraceEnabled()) {
LOG.trace("Failed to complete the requested command due to execution error: " + e.getMessage());
}
} catch (TimeoutException e) {
retVal = -1;
stdError = "Operation timed out, aborted";
if (LOG.isTraceEnabled()) {
LOG.trace("Failed to complete the requested command within timeout: " + e.getMessage());
}
} finally {
if (Strings.isNullOrEmpty(stdError)) {
stdOutput = readStream(process.getInputStream());
stdError = readStream(process.getErrorStream());
}
process.destroy();
final Future<Integer> processFuture = executor.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return process.waitFor();
}
} else {
retVal = process.waitFor();
stdOutput = readStream(process.getInputStream());
stdError = readStream(process.getErrorStream());
});
try {
retVal = processFuture.get(timeOut.getStandardSeconds(), TimeUnit.SECONDS);
} catch (ExecutionException e) {
retVal = -2;
stdError = e.getMessage();
if (LOG.isTraceEnabled()) {
LOG.trace("Failed to complete the requested command due to execution error: " + e.getMessage());
}
} catch (TimeoutException e) {
retVal = -1;
stdError = "Operation timed out, aborted";
if (LOG.isTraceEnabled()) {
LOG.trace("Failed to complete the requested command within timeout: " + e.getMessage());
}
} finally {
if (Strings.isNullOrEmpty(stdError)) {
stdOutput = CharStreams.toString(new InputStreamReader(process.getInputStream()));
stdError = CharStreams.toString(new InputStreamReader(process.getErrorStream()));
}
process.destroy();
}
if (LOG.isTraceEnabled()) {
LOG.trace("Process standard output: " + stdOutput);

View File

@ -19,6 +19,7 @@
package org.apache.cloudstack.utils.process;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.google.common.base.Strings;
import org.joda.time.Duration;
import org.junit.Assert;
@ -27,13 +28,18 @@ import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@RunWith(MockitoJUnitRunner.class)
public class ProcessTest {
private static final ExecutorService executor = Executors.newFixedThreadPool(10, new NamedThreadFactory("IpmiToolDriverTest"));
private static final ProcessRunner RUNNER = new ProcessRunner(executor);
@Test
public void testProcessRunner() {
ProcessResult result = ProcessRunner.executeCommands(Arrays.asList("ls", "/tmp"), Duration.ZERO);
ProcessResult result = RUNNER.executeCommands(Arrays.asList("ls", "/tmp"));
Assert.assertEquals(result.getReturnCode(), 0);
Assert.assertTrue(Strings.isNullOrEmpty(result.getStdError()));
Assert.assertTrue(result.getStdOutput().length() > 0);
@ -41,7 +47,7 @@ public class ProcessTest {
@Test
public void testProcessRunnerWithTimeout() {
ProcessResult result = ProcessRunner.executeCommands(Arrays.asList("sleep", "5"), Duration.standardSeconds(1));
ProcessResult result = RUNNER.executeCommands(Arrays.asList("sleep", "5"), Duration.standardSeconds(1));
Assert.assertNotEquals(result.getReturnCode(), 0);
Assert.assertTrue(result.getStdError().length() > 0);
Assert.assertEquals(result.getStdError(), "Operation timed out, aborted");
@ -49,9 +55,15 @@ public class ProcessTest {
@Test
public void testProcessRunnerWithTimeoutAndException() {
ProcessResult result = ProcessRunner.executeCommands(Arrays.asList("ls", "/some/dir/that/should/not/exist"), Duration.standardSeconds(2));
ProcessResult result = RUNNER.executeCommands(Arrays.asList("ls", "/some/dir/that/should/not/exist"), Duration.standardSeconds(2));
Assert.assertNotEquals(result.getReturnCode(), 0);
Assert.assertTrue(result.getStdError().length() > 0);
Assert.assertNotEquals(result.getStdError(), "Operation timed out, aborted");
}
@Test(expected = IllegalArgumentException.class)
public void testProcessRunnerWithMoreThanMaxAllowedTimeout() {
RUNNER.executeCommands(Arrays.asList("ls", "/some/dir/that/should/not/exist"), ProcessRunner.DEFAULT_MAX_TIMEOUT.plus(1000));
Assert.fail("Illegal argument exception was expected");
}
}