Skip to content

Commit 2a92813

Browse files
committed
Add properties for env vars for the instance conversion
1 parent e9176ee commit 2a92813

File tree

6 files changed

+76
-10
lines changed

6 files changed

+76
-10
lines changed

agent/conf/agent.properties

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,3 +451,9 @@ iscsi.session.cleanup.enabled=false
451451

452452
# If set to true, creates VMs as full clones of their templates on KVM hypervisor. Creates as linked clones otherwise.
453453
# create.full.clone=false
454+
455+
# Instance conversion TMPDIR env var
456+
#convert.instance.env.tmpdir=
457+
458+
# Instance conversion VIRT_V2V_TMPDIR env var
459+
#convert.instance.env.virtv2v.tmpdir=

agent/src/main/java/com/cloud/agent/properties/AgentProperties.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,20 @@ public Property<Integer> getWorkers() {
794794
*/
795795
public static final Property<Boolean> VIRTV2V_VERBOSE_ENABLED = new Property<>("virtv2v.verbose.enabled", false);
796796

797+
/**
798+
* Set env TMPDIR var for virt-v2v Instance Conversion from VMware to KVM
799+
* Data type: String.<br>
800+
* Default value: <code>null</code>
801+
*/
802+
public static final Property<String> CONVERT_ENV_TMPDIR = new Property<>("convert.instance.env.tmpdir", null, String.class);
803+
804+
/**
805+
* Set env VIRT_V2V_TMPDIR var for virt-v2v Instance Conversion from VMware to KVM
806+
* Data type: String.<br>
807+
* Default value: <code>null</code>
808+
*/
809+
public static final Property<String> CONVERT_ENV_VIRTV2V_TMPDIR = new Property<>("convert.instance.env.virtv2v.tmpdir", null, String.class);
810+
797811
/**
798812
* BGP controll CIDR
799813
* Data type: String.<br>

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,7 @@ protected enum HealthCheckResult {
882882
protected StorageSubsystemCommandHandler storageHandler;
883883

884884
private boolean convertInstanceVerboseMode = false;
885+
private String[] convertInstanceEnv = null;
885886
protected boolean dpdkSupport = false;
886887
protected String dpdkOvsPath;
887888
protected String directDownloadTemporaryDownloadPath;
@@ -946,6 +947,10 @@ public boolean isConvertInstanceVerboseModeEnabled() {
946947
return convertInstanceVerboseMode;
947948
}
948949

950+
public String[] getConvertInstanceEnv() {
951+
return convertInstanceEnv;
952+
}
953+
949954
/**
950955
* Defines resource's public and private network interface according to what is configured in agent.properties.
951956
*/
@@ -1146,6 +1151,11 @@ public boolean configure(final String name, final Map<String, Object> params) th
11461151

11471152
convertInstanceVerboseMode = BooleanUtils.isTrue(AgentPropertiesFileHandler.getPropertyValue(AgentProperties.VIRTV2V_VERBOSE_ENABLED));
11481153

1154+
String convertEnvTmpDir = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.CONVERT_ENV_TMPDIR);
1155+
String convertEnvVirtv2vTmpDir = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.CONVERT_ENV_VIRTV2V_TMPDIR);
1156+
1157+
setConvertInstanceEnv(convertEnvTmpDir, convertEnvVirtv2vTmpDir);
1158+
11491159
pool = (String)params.get("pool");
11501160
if (pool == null) {
11511161
pool = "/root";
@@ -1422,6 +1432,22 @@ public boolean configure(final String name, final Map<String, Object> params) th
14221432
return true;
14231433
}
14241434

1435+
private void setConvertInstanceEnv(String convertEnvTmpDir, String convertEnvVirtv2vTmpDir) {
1436+
if (StringUtils.isAllBlank(convertEnvTmpDir, convertEnvVirtv2vTmpDir)) {
1437+
return;
1438+
}
1439+
if (StringUtils.isNotBlank(convertEnvTmpDir) && StringUtils.isNotBlank(convertEnvVirtv2vTmpDir)) {
1440+
convertInstanceEnv = new String[2];
1441+
convertInstanceEnv[0] = String.format("%s=%s", "TMPDIR", convertEnvTmpDir);
1442+
convertInstanceEnv[1] = String.format("%s=%s", "VIRT_V2V_TMPDIR", convertEnvTmpDir);
1443+
} else {
1444+
convertInstanceEnv = new String[1];
1445+
String key = StringUtils.isNotBlank(convertEnvTmpDir) ? "TMPDIR" : "VIRT_V2V_TMPDIR";
1446+
String value = StringUtils.isNotBlank(convertEnvTmpDir) ? convertEnvTmpDir : convertEnvVirtv2vTmpDir;
1447+
convertInstanceEnv[0] = String.format("%s=%s", key, value);
1448+
}
1449+
}
1450+
14251451
/**
14261452
* Parses a string containing whitespace-separated CPU feature names and converts it into a list.
14271453
*

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtConvertInstanceCommandWrapper.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ public Answer execute(ConvertInstanceCommand cmd, LibvirtComputingResource serve
118118
boolean cleanupSecondaryStorage = false;
119119
try {
120120
boolean result = performInstanceConversion(sourceInstanceName, sourceOVFDirPath, temporaryConvertPath, temporaryConvertUuid,
121-
timeout, verboseModeEnabled, extraParams);
121+
timeout, verboseModeEnabled, extraParams, serverResource);
122122
if (!result) {
123123
String err = String.format(
124124
"(%s) The virt-v2v conversion for the OVF %s failed. Please check the agent logs " +
@@ -221,7 +221,8 @@ private boolean exportOVAFromVMOnVcenter(String vmExportUrl,
221221
protected boolean performInstanceConversion(String sourceInstanceName, String sourceOVFDirPath,
222222
String temporaryConvertFolder,
223223
String temporaryConvertUuid,
224-
long timeout, boolean verboseModeEnabled, String extraParams) {
224+
long timeout, boolean verboseModeEnabled, String extraParams,
225+
LibvirtComputingResource serverResource) {
225226
Script script = new Script("virt-v2v", timeout, logger);
226227
script.add("--root", "first");
227228
script.add("-i", "ova");
@@ -239,7 +240,7 @@ protected boolean performInstanceConversion(String sourceInstanceName, String so
239240

240241
String logPrefix = String.format("(%s) virt-v2v ovf source: %s progress", sourceInstanceName, sourceOVFDirPath);
241242
OutputInterpreter.LineByLineOutputLogger outputLogger = new OutputInterpreter.LineByLineOutputLogger(logger, logPrefix);
242-
script.execute(outputLogger);
243+
script.execute(outputLogger, serverResource.getConvertInstanceEnv());
243244
int exitValue = script.getExitValue();
244245
return exitValue == 0;
245246
}

plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtConvertInstanceCommandWrapperTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ public void testExecuteConvertFailure() {
167167
Answer answer = convertInstanceCommandWrapper.execute(cmd, libvirtComputingResourceMock);
168168
Assert.assertFalse(answer.getResult());
169169
Mockito.verify(convertInstanceCommandWrapper).performInstanceConversion(Mockito.anyString(), Mockito.anyString(),
170-
Mockito.anyString(), Mockito.anyString(), Mockito.anyLong(), Mockito.anyBoolean(), Mockito.nullable(String.class));
170+
Mockito.anyString(), Mockito.anyString(), Mockito.anyLong(), Mockito.anyBoolean(), Mockito.nullable(String.class), Mockito.any(LibvirtComputingResource.class));
171171
}
172172
}
173173
}

utils/src/main/java/com/cloud/utils/script/Script.java

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242

4343
import org.apache.cloudstack.utils.security.KeyStoreUtils;
4444
import org.apache.commons.io.IOUtils;
45+
import org.apache.commons.lang3.ArrayUtils;
4546
import org.apache.logging.log4j.LogManager;
4647
import org.apache.logging.log4j.Logger;
4748
import org.joda.time.Duration;
@@ -206,6 +207,14 @@ static String stackTraceAsString(Throwable throwable) {
206207
}
207208

208209
public String execute(OutputInterpreter interpreter) {
210+
return execute(interpreter, null);
211+
}
212+
213+
public String execute(OutputInterpreter interpreter, String[] environment) {
214+
return executeInternal(interpreter, environment);
215+
}
216+
217+
public String executeInternal(OutputInterpreter interpreter, String[] environment) {
209218
String[] command = _command.toArray(new String[_command.size()]);
210219
String commandLine = buildCommandLine(command);
211220
if (_logger.isDebugEnabled() && !avoidLoggingCommand) {
@@ -214,13 +223,23 @@ public String execute(OutputInterpreter interpreter) {
214223

215224
try {
216225
_logger.trace(String.format("Creating process for command [%s].", commandLine));
217-
ProcessBuilder pb = new ProcessBuilder(command);
218-
pb.redirectErrorStream(true);
219-
if (_workDir != null)
220-
pb.directory(new File(_workDir));
221226

222-
_logger.trace(String.format("Starting process for command [%s].", commandLine));
223-
_process = pb.start();
227+
if (ArrayUtils.isNotEmpty(environment)) {
228+
// Since Runtime.exec() does not support redirecting the error stream, then append 2>&1 to the command
229+
String[] commands = new String[] {"sh", "-c", String.format("%s 2>&1", commandLine)};
230+
// The PATH variable must be added for indirect calls within the running command
231+
// Example: virt-v2v invokes qemu-img, which cannot be found if PATH is not set
232+
String[] env = ArrayUtils.add(environment, String.format("PATH=%s", System.getenv("PATH")));
233+
_process = Runtime.getRuntime().exec(commands, env, _workDir != null ? new File(_workDir) : null);
234+
} else {
235+
ProcessBuilder pb = new ProcessBuilder(command);
236+
pb.redirectErrorStream(true);
237+
if (_workDir != null)
238+
pb.directory(new File(_workDir));
239+
240+
_logger.trace(String.format("Starting process for command [%s].", commandLine));
241+
_process = pb.start();
242+
}
224243
if (_process == null) {
225244
_logger.warn(String.format("Unable to execute command [%s] because no process was created.", commandLine));
226245
return "Unable to execute the command: " + command[0];

0 commit comments

Comments
 (0)