diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtConvertInstanceCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtConvertInstanceCommandWrapper.java index 93895349a6e8..d1a2e20643c9 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtConvertInstanceCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtConvertInstanceCommandWrapper.java @@ -25,6 +25,7 @@ import java.util.UUID; import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; +import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import com.cloud.agent.api.Answer; @@ -244,7 +245,12 @@ protected boolean performInstanceConversion(String originalVMName, String source String logPrefix = String.format("(%s) virt-v2v ovf source: %s progress", originalVMName, sourceOVFDirPath); OutputInterpreter.LineByLineOutputLogger outputLogger = new OutputInterpreter.LineByLineOutputLogger(logger, logPrefix); - script.execute(outputLogger); + String[] convertInstanceEnv = serverResource.getConvertInstanceEnv(); + if (ArrayUtils.isEmpty(convertInstanceEnv)) { + script.execute(outputLogger); + } else { + script.execute(outputLogger, convertInstanceEnv); + } int exitValue = script.getExitValue(); return exitValue == 0; } diff --git a/utils/src/main/java/com/cloud/utils/script/Script.java b/utils/src/main/java/com/cloud/utils/script/Script.java index b56a457aeaae..f6e17060e3a9 100644 --- a/utils/src/main/java/com/cloud/utils/script/Script.java +++ b/utils/src/main/java/com/cloud/utils/script/Script.java @@ -43,6 +43,7 @@ import org.apache.cloudstack.utils.security.KeyStoreUtils; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.ArrayUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.joda.time.Duration; @@ -236,6 +237,14 @@ static String stackTraceAsString(Throwable throwable) { } public String execute(OutputInterpreter interpreter) { + return execute(interpreter, null); + } + + public String execute(OutputInterpreter interpreter, String[] environment) { + return executeInternal(interpreter, environment); + } + + public String executeInternal(OutputInterpreter interpreter, String[] environment) { String[] command = _command.toArray(new String[_command.size()]); String commandLine = buildCommandLine(command); if (_logger.isDebugEnabled() && !avoidLoggingCommand) { @@ -245,13 +254,23 @@ public String execute(OutputInterpreter interpreter) { try { _logger.trace(String.format("Creating process for command [%s].", commandLine)); - ProcessBuilder pb = new ProcessBuilder(command); - pb.redirectErrorStream(true); - if (_workDir != null) - pb.directory(new File(_workDir)); + if (ArrayUtils.isEmpty(environment)) { + ProcessBuilder pb = new ProcessBuilder(command); + pb.redirectErrorStream(true); + if (_workDir != null) + pb.directory(new File(_workDir)); + + _logger.trace(String.format("Starting process for command [%s].", commandLine)); + _process = pb.start(); + } else { + // Since Runtime.exec() does not support redirecting the error stream, then append 2>&1 to the command + String[] commands = new String[] {"sh", "-c", String.format("%s 2>&1", commandLine)}; + // The PATH variable must be added for indirect calls within the running command + // Example: virt-v2v invokes qemu-img, which cannot be found if PATH is not set + String[] env = ArrayUtils.add(environment, String.format("PATH=%s", System.getenv("PATH"))); + _process = Runtime.getRuntime().exec(commands, env, _workDir != null ? new File(_workDir) : null); + } - _logger.trace(String.format("Starting process for command [%s].", commandLine)); - _process = pb.start(); if (_process == null) { _logger.warn(String.format("Unable to execute command [%s] because no process was created.", commandLine)); return "Unable to execute the command: " + command[0];