Skip to content

Commit 7fb0b85

Browse files
Detect password file option while kvm initialisation
1 parent ababa52 commit 7fb0b85

File tree

3 files changed

+58
-63
lines changed

3 files changed

+58
-63
lines changed

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -892,6 +892,7 @@ protected enum HealthCheckResult {
892892
protected String cachePath;
893893
private String vddkTransports = null;
894894
private String vddkThumbprint = null;
895+
private String detectedPasswordFileOption = null;
895896
protected String javaTempDir = System.getProperty("java.io.tmpdir");
896897

897898
private String getEndIpFromStartIp(final String startIp, final int numIps) {
@@ -1185,6 +1186,13 @@ public boolean configure(final String name, final Map<String, Object> params) th
11851186
vddkThumbprint = StringUtils.trimToNull(
11861187
AgentPropertiesFileHandler.getPropertyValue(AgentProperties.VDDK_THUMBPRINT));
11871188

1189+
detectedPasswordFileOption = detectPasswordFileOption();
1190+
if (StringUtils.isNotBlank(detectedPasswordFileOption)) {
1191+
LOGGER.info("Detected virt-v2v password option: {}", detectedPasswordFileOption);
1192+
} else {
1193+
LOGGER.warn("Could not detect virt-v2v password option, VDDK conversions may fail");
1194+
}
1195+
11881196
pool = (String)params.get("pool");
11891197
if (pool == null) {
11901198
pool = "/root";
@@ -5980,6 +5988,40 @@ public boolean hostSupportsOvfExport() {
59805988
return exitValue == 0;
59815989
}
59825990

5991+
/**
5992+
* Detect which password option virt-v2v supports by examining its --help output
5993+
* @return "-ip" if supported (virt-v2v >= 2.8.1), "--password-file" if older version, or null if detection fails
5994+
*/
5995+
protected String detectPasswordFileOption() {
5996+
try {
5997+
ProcessBuilder pb = new ProcessBuilder("virt-v2v", "--help");
5998+
Process process = pb.start();
5999+
6000+
String output = new String(process.getInputStream().readAllBytes());
6001+
process.waitFor();
6002+
6003+
if (output.contains("-ip <filename>")) {
6004+
return "-ip";
6005+
} else if (output.contains("--password-file")) {
6006+
return "--password-file";
6007+
} else {
6008+
LOGGER.error("virt-v2v does not support -ip or --password-file");
6009+
return null;
6010+
}
6011+
} catch (Exception e) {
6012+
LOGGER.error("Failed to detect virt-v2v password option: {}", e.getMessage());
6013+
return null;
6014+
}
6015+
}
6016+
6017+
/**
6018+
* Get the detected password file option for virt-v2v
6019+
* @return the password option ("-ip" or "--password-file") or null if not detected
6020+
*/
6021+
public String getDetectedPasswordFileOption() {
6022+
return detectedPasswordFileOption;
6023+
}
6024+
59836025
public String getHostVirtV2vVersion() {
59846026
if (!hostSupportsInstanceConversion()) {
59856027
return "";

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

Lines changed: 10 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,6 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
5757
private static final List<Hypervisor.HypervisorType> supportedInstanceConvertSourceHypervisors =
5858
List.of(Hypervisor.HypervisorType.VMware);
5959
private static final Pattern SHA1_FINGERPRINT_PATTERN = Pattern.compile("(?i)(?:SHA1\\s+)?Fingerprint\\s*=\\s*([0-9A-F:]+)");
60-
private static final Pattern VERSION_PREFIX_PATTERN = Pattern.compile("^(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?.*");
61-
private static final String LEGACY_PASSWORD_FILE_OPTION = "--password-file";
62-
private static final String PASSWORD_INTERACTIVE_FILE_OPTION = "-ip";
6360

6461
@Override
6562
public Answer execute(ConvertInstanceCommand cmd, LibvirtComputingResource serverResource) {
@@ -115,10 +112,10 @@ public Answer execute(ConvertInstanceCommand cmd, LibvirtComputingResource serve
115112
String libguestfsBackend = StringUtils.defaultIfBlank(resolveVddkSetting(cmd.getLibguestfsBackend(), serverResource.getLibguestfsBackend()), "direct");
116113
String vddkTransports = resolveVddkSetting(cmd.getVddkTransports(), serverResource.getVddkTransports());
117114
String configuredVddkThumbprint = resolveVddkSetting(cmd.getVddkThumbprint(), serverResource.getVddkThumbprint());
118-
String virtV2vVersion = serverResource.getHostVirtV2vVersion();
115+
String passwordOption = serverResource.getDetectedPasswordFileOption();
119116
result = performInstanceConversionVddk(sourceInstance, originalVMName, temporaryConvertPath,
120117
vddkLibDir, libguestfsBackend, vddkTransports, configuredVddkThumbprint,
121-
timeout, verboseModeEnabled, extraParams, virtV2vVersion);
118+
timeout, verboseModeEnabled, extraParams, temporaryConvertUuid, passwordOption);
122119
} else {
123120
logger.info("({}) Using OVF-based conversion (export + local convert)", originalVMName);
124121
String sourceOVFDirPath;
@@ -312,7 +309,7 @@ protected boolean performInstanceConversionVddk(RemoteInstanceTO vmwareInstance,
312309
String libguestfsBackend, String vddkTransports,
313310
String configuredVddkThumbprint,
314311
long timeout, boolean verboseModeEnabled, String extraParams,
315-
String virtV2vVersion) {
312+
String temporaryConvertUuid, String passwordOption) {
316313

317314
String vcenterPassword = vmwareInstance.getVcenterPassword();
318315
if (StringUtils.isBlank(vcenterPassword)) {
@@ -340,7 +337,12 @@ protected boolean performInstanceConversionVddk(RemoteInstanceTO vmwareInstance,
340337
cmd.append("virt-v2v ");
341338
cmd.append("--root first ");
342339
cmd.append("-ic '").append(vpxUrl).append("' ");
343-
cmd.append(getPasswordInputOptionForVersion(virtV2vVersion)).append(" ").append(passwordFilePath).append(" ");
340+
if (StringUtils.isBlank(passwordOption)) {
341+
logger.error("({}) Could not determine supported password file option for virt-v2v", originalVMName);
342+
return false;
343+
}
344+
345+
cmd.append(passwordOption).append(" ").append(passwordFilePath).append(" ");
344346
cmd.append("-it vddk ");
345347
cmd.append("-io vddk-libdir=").append(vddkLibDir).append(" ");
346348
String vddkThumbprint = StringUtils.trimToNull(configuredVddkThumbprint);
@@ -359,6 +361,7 @@ protected boolean performInstanceConversionVddk(RemoteInstanceTO vmwareInstance,
359361
cmd.append("-o local ");
360362
cmd.append("-os ").append(temporaryConvertFolder).append(" ");
361363
cmd.append("-of qcow2 ");
364+
cmd.append("-on ").append(temporaryConvertUuid).append(" ");
362365

363366
if (verboseModeEnabled) {
364367
cmd.append("-v ");
@@ -393,43 +396,6 @@ protected boolean performInstanceConversionVddk(RemoteInstanceTO vmwareInstance,
393396
return exitValue == 0;
394397
}
395398

396-
protected String getPasswordInputOptionForVersion(String virtV2vVersion) {
397-
// virt-v2v 2.8.1 replaced --password-file with -ip.
398-
if (isVersionAtLeast(virtV2vVersion, 2, 8, 1)) {
399-
return PASSWORD_INTERACTIVE_FILE_OPTION;
400-
}
401-
return LEGACY_PASSWORD_FILE_OPTION;
402-
}
403-
404-
private boolean isVersionAtLeast(String version, int major, int minor, int patch) {
405-
int[] parsedVersion = parseVersionPrefix(version);
406-
if (parsedVersion == null) {
407-
return false;
408-
}
409-
if (parsedVersion[0] != major) {
410-
return parsedVersion[0] > major;
411-
}
412-
if (parsedVersion[1] != minor) {
413-
return parsedVersion[1] > minor;
414-
}
415-
return parsedVersion[2] >= patch;
416-
}
417-
418-
private int[] parseVersionPrefix(String version) {
419-
String normalized = StringUtils.trimToNull(version);
420-
if (normalized == null) {
421-
return null;
422-
}
423-
Matcher matcher = VERSION_PREFIX_PATTERN.matcher(normalized);
424-
if (!matcher.matches()) {
425-
return null;
426-
}
427-
return new int[] {
428-
Integer.parseInt(matcher.group(1)),
429-
StringUtils.isNotBlank(matcher.group(2)) ? Integer.parseInt(matcher.group(2)) : 0,
430-
StringUtils.isNotBlank(matcher.group(3)) ? Integer.parseInt(matcher.group(3)) : 0
431-
};
432-
}
433399

434400
protected String getVcenterThumbprint(String vcenterHost, long timeout, String originalVMName) {
435401
if (StringUtils.isBlank(vcenterHost)) {

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

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -214,13 +214,14 @@ public void testPerformInstanceConversionVddkUsesConfiguredLibguestfsBackend() {
214214
filesMock.when(() -> Files.deleteIfExists(passwordFilePath)).thenReturn(true);
215215

216216
boolean result = convertInstanceCommandWrapper.performInstanceConversionVddk(
217-
remoteInstanceTO, vmName, "/tmp/convert", "/opt/vddk", "libvirt", null, null, 1000L, false, null, "1.42.0");
217+
remoteInstanceTO, vmName, "/tmp/convert", "/opt/vddk", "libvirt", null, null, 1000L, false, null, "tmp-uuid", "-ip");
218218

219219
Assert.assertTrue(result);
220220
Script scriptMock = ignored.constructed().get(0);
221221
Mockito.verify(scriptMock).add("-c");
222222
Mockito.verify(scriptMock).add(Mockito.contains("export LIBGUESTFS_BACKEND=libvirt &&"));
223-
Mockito.verify(scriptMock).add(Mockito.contains("--password-file /root/v2v.pass.cloud.vcenter.local "));
223+
Mockito.verify(scriptMock).add(Mockito.contains("-ip /root/v2v.pass.cloud.vcenter.local "));
224+
Mockito.verify(scriptMock).add(Mockito.contains(" -on tmp-uuid "));
224225
Mockito.verify(scriptMock).add(Mockito.contains("-io vddk-thumbprint=28:19:A6:1C:90:ED:46:D7:1C:86:BC:F6:13:52:F0:B9:19:81:0D:81 "));
225226
}
226227
}
@@ -247,7 +248,7 @@ public void testPerformInstanceConversionVddkUsesConfiguredTransportsOrder() {
247248
filesMock.when(() -> Files.deleteIfExists(passwordFilePath)).thenReturn(true);
248249

249250
boolean result = convertInstanceCommandWrapper.performInstanceConversionVddk(
250-
remoteInstanceTO, vmName, "/tmp/convert", "/opt/vddk", "direct", "nbd:nbdssl", null, 1000L, false, null, "1.42.0");
251+
remoteInstanceTO, vmName, "/tmp/convert", "/opt/vddk", "direct", "nbd:nbdssl", null, 1000L, false, null, "tmp-uuid", "-ip");
251252

252253
Assert.assertTrue(result);
253254
Script scriptMock = ignored.constructed().get(0);
@@ -273,7 +274,7 @@ public void testPerformInstanceConversionVddkFailsWhenThumbprintUnavailable() {
273274
filesMock.when(() -> Files.deleteIfExists(passwordFilePath)).thenReturn(true);
274275

275276
boolean result = convertInstanceCommandWrapper.performInstanceConversionVddk(
276-
remoteInstanceTO, vmName, "/tmp/convert", "/opt/vddk", "direct", null, null, 1000L, false, null, "1.42.0");
277+
remoteInstanceTO, vmName, "/tmp/convert", "/opt/vddk", "direct", null, null, 1000L, false, null, "tmp-uuid", "-ip");
277278

278279
Assert.assertFalse(result);
279280
}
@@ -300,7 +301,7 @@ public void testPerformInstanceConversionVddkUsesConfiguredThumbprintFromAgentPr
300301

301302
boolean result = convertInstanceCommandWrapper.performInstanceConversionVddk(
302303
remoteInstanceTO, vmName, "/tmp/convert", "/opt/vddk", "direct", null,
303-
"AA:BB:CC:DD:EE", 1000L, false, null, "1.42.0");
304+
"AA:BB:CC:DD:EE", 1000L, false, null, "tmp-uuid", "-ip");
304305

305306
Assert.assertTrue(result);
306307
Script scriptMock = ignored.constructed().get(0);
@@ -309,18 +310,4 @@ public void testPerformInstanceConversionVddkUsesConfiguredThumbprintFromAgentPr
309310
.getVcenterThumbprint(Mockito.anyString(), Mockito.anyLong(), Mockito.anyString());
310311
}
311312
}
312-
313-
@Test
314-
public void testGetPasswordInputOptionForVersionUsesLegacyOptionForOlderVersions() {
315-
Assert.assertEquals("--password-file", convertInstanceCommandWrapper.getPasswordInputOptionForVersion("1.42.0rhel=8"));
316-
Assert.assertEquals("--password-file", convertInstanceCommandWrapper.getPasswordInputOptionForVersion("2.8.0"));
317-
Assert.assertEquals("--password-file", convertInstanceCommandWrapper.getPasswordInputOptionForVersion(""));
318-
}
319-
320-
@Test
321-
public void testGetPasswordInputOptionForVersionUsesIpOptionForNewerVersions() {
322-
Assert.assertEquals("-ip", convertInstanceCommandWrapper.getPasswordInputOptionForVersion("2.8.1"));
323-
Assert.assertEquals("-ip", convertInstanceCommandWrapper.getPasswordInputOptionForVersion("2.9.0"));
324-
Assert.assertEquals("-ip", convertInstanceCommandWrapper.getPasswordInputOptionForVersion("3.0"));
325-
}
326313
}

0 commit comments

Comments
 (0)