Skip to content

Commit ababa52

Browse files
password file related changes and vddk support addition in host details
1 parent cb42c2f commit ababa52

6 files changed

Lines changed: 85 additions & 14 deletions

File tree

api/src/main/java/com/cloud/host/Host.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ public static String[] toStrings(Host.Type... types) {
5757
String HOST_UEFI_ENABLE = "host.uefi.enable";
5858
String HOST_VOLUME_ENCRYPTION = "host.volume.encryption";
5959
String HOST_INSTANCE_CONVERSION = "host.instance.conversion";
60+
String HOST_VDDK_SUPPORT = "host.vddk.support";
6061
String HOST_OVFTOOL_VERSION = "host.ovftool.version";
6162
String HOST_VIRTV2V_VERSION = "host.virtv2v.version";
6263
String HOST_SSH_PORT = "host.ssh.port";

engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -805,8 +805,9 @@ protected AgentAttache notifyMonitorsOfConnection(final AgentAttache attache, fi
805805
String uefiEnabled = detailsMap.get(Host.HOST_UEFI_ENABLE);
806806
String virtv2vVersion = detailsMap.get(Host.HOST_VIRTV2V_VERSION);
807807
String ovftoolVersion = detailsMap.get(Host.HOST_OVFTOOL_VERSION);
808+
String vddkSupport = detailsMap.get(Host.HOST_VDDK_SUPPORT);
808809
logger.debug("Got HOST_UEFI_ENABLE [{}] for host [{}]:", uefiEnabled, host);
809-
if (ObjectUtils.anyNotNull(uefiEnabled, virtv2vVersion, ovftoolVersion)) {
810+
if (ObjectUtils.anyNotNull(uefiEnabled, virtv2vVersion, ovftoolVersion, vddkSupport)) {
810811
_hostDao.loadDetails(host);
811812
boolean updateNeeded = false;
812813
if (StringUtils.isNotBlank(uefiEnabled) && !uefiEnabled.equals(host.getDetails().get(Host.HOST_UEFI_ENABLE))) {
@@ -821,6 +822,10 @@ protected AgentAttache notifyMonitorsOfConnection(final AgentAttache attache, fi
821822
host.getDetails().put(Host.HOST_OVFTOOL_VERSION, ovftoolVersion);
822823
updateNeeded = true;
823824
}
825+
if (StringUtils.isNotBlank(vddkSupport) && !vddkSupport.equals(host.getDetails().get(Host.HOST_VDDK_SUPPORT))) {
826+
host.getDetails().put(Host.HOST_VDDK_SUPPORT, vddkSupport);
827+
updateNeeded = true;
828+
}
824829
if (updateNeeded) {
825830
_hostDao.saveDetails(host);
826831
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import static com.cloud.host.Host.HOST_INSTANCE_CONVERSION;
2020
import static com.cloud.host.Host.HOST_OVFTOOL_VERSION;
21+
import static com.cloud.host.Host.HOST_VDDK_SUPPORT;
2122
import static com.cloud.host.Host.HOST_VIRTV2V_VERSION;
2223
import static com.cloud.host.Host.HOST_VOLUME_ENCRYPTION;
2324
import static org.apache.cloudstack.utils.linux.KVMHostInfo.isHostS390x;
@@ -4245,6 +4246,7 @@ public StartupCommand[] initialize() {
42454246
cmd.setHostTags(getHostTags());
42464247
boolean instanceConversionSupported = hostSupportsInstanceConversion();
42474248
cmd.getHostDetails().put(HOST_INSTANCE_CONVERSION, String.valueOf(instanceConversionSupported));
4249+
cmd.getHostDetails().put(HOST_VDDK_SUPPORT, String.valueOf(hostSupportsVddk()));
42484250
if (instanceConversionSupported) {
42494251
cmd.getHostDetails().put(HOST_VIRTV2V_VERSION, getHostVirtV2vVersion());
42504252
}
@@ -5960,6 +5962,10 @@ public boolean hostSupportsInstanceConversion() {
59605962
return exitValue == 0;
59615963
}
59625964

5965+
public boolean hostSupportsVddk() {
5966+
return hostSupportsInstanceConversion() && StringUtils.isNotBlank(vddkLibDir) && new File(vddkLibDir).isDirectory();
5967+
}
5968+
59635969
public boolean hostSupportsWindowsGuestConversion() {
59645970
if (isUbuntuOrDebianHost()) {
59655971
int exitValue = Script.runSimpleBashScriptForExitValue(UBUNTU_WINDOWS_GUEST_CONVERSION_SUPPORTED_CHECK_CMD);

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

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ 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";
6063

6164
@Override
6265
public Answer execute(ConvertInstanceCommand cmd, LibvirtComputingResource serverResource) {
@@ -112,9 +115,10 @@ public Answer execute(ConvertInstanceCommand cmd, LibvirtComputingResource serve
112115
String libguestfsBackend = StringUtils.defaultIfBlank(resolveVddkSetting(cmd.getLibguestfsBackend(), serverResource.getLibguestfsBackend()), "direct");
113116
String vddkTransports = resolveVddkSetting(cmd.getVddkTransports(), serverResource.getVddkTransports());
114117
String configuredVddkThumbprint = resolveVddkSetting(cmd.getVddkThumbprint(), serverResource.getVddkThumbprint());
118+
String virtV2vVersion = serverResource.getHostVirtV2vVersion();
115119
result = performInstanceConversionVddk(sourceInstance, originalVMName, temporaryConvertPath,
116120
vddkLibDir, libguestfsBackend, vddkTransports, configuredVddkThumbprint,
117-
timeout, verboseModeEnabled, extraParams);
121+
timeout, verboseModeEnabled, extraParams, virtV2vVersion);
118122
} else {
119123
logger.info("({}) Using OVF-based conversion (export + local convert)", originalVMName);
120124
String sourceOVFDirPath;
@@ -307,15 +311,17 @@ protected boolean performInstanceConversionVddk(RemoteInstanceTO vmwareInstance,
307311
String temporaryConvertFolder, String vddkLibDir,
308312
String libguestfsBackend, String vddkTransports,
309313
String configuredVddkThumbprint,
310-
long timeout, boolean verboseModeEnabled, String extraParams) {
314+
long timeout, boolean verboseModeEnabled, String extraParams,
315+
String virtV2vVersion) {
311316

312317
String vcenterPassword = vmwareInstance.getVcenterPassword();
313318
if (StringUtils.isBlank(vcenterPassword)) {
314319
logger.error("({}) Could not determine vCenter password for {}", originalVMName, vmwareInstance.getVcenterHost());
315320
return false;
316321
}
317322

318-
String passwordFilePath = "/root/v2v.pass.cloud";
323+
String passwordFilePath = String.format("/root/v2v.pass.cloud.%s",
324+
StringUtils.defaultIfBlank(vmwareInstance.getVcenterHost(), "unknown"));
319325
try {
320326
Files.writeString(Path.of(passwordFilePath), vcenterPassword);
321327
logger.debug("({}) Written vCenter password to {}", originalVMName, passwordFilePath);
@@ -334,7 +340,7 @@ protected boolean performInstanceConversionVddk(RemoteInstanceTO vmwareInstance,
334340
cmd.append("virt-v2v ");
335341
cmd.append("--root first ");
336342
cmd.append("-ic '").append(vpxUrl).append("' ");
337-
cmd.append("--password-file ").append(passwordFilePath).append(" ");
343+
cmd.append(getPasswordInputOptionForVersion(virtV2vVersion)).append(" ").append(passwordFilePath).append(" ");
338344
cmd.append("-it vddk ");
339345
cmd.append("-io vddk-libdir=").append(vddkLibDir).append(" ");
340346
String vddkThumbprint = StringUtils.trimToNull(configuredVddkThumbprint);
@@ -387,6 +393,44 @@ protected boolean performInstanceConversionVddk(RemoteInstanceTO vmwareInstance,
387393
return exitValue == 0;
388394
}
389395

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+
}
433+
390434
protected String getVcenterThumbprint(String vcenterHost, long timeout, String originalVMName) {
391435
if (StringUtils.isBlank(vcenterHost)) {
392436
return null;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public Answer execute(final ReadyCommand command, final LibvirtComputingResource
5050
if (libvirtComputingResource.hostSupportsInstanceConversion()) {
5151
hostDetails.put(Host.HOST_VIRTV2V_VERSION, libvirtComputingResource.getHostVirtV2vVersion());
5252
}
53+
hostDetails.put(Host.HOST_VDDK_SUPPORT, Boolean.toString(libvirtComputingResource.hostSupportsVddk()));
5354

5455
if (libvirtComputingResource.hostSupportsOvfExport()) {
5556
hostDetails.put(Host.HOST_OVFTOOL_VERSION, libvirtComputingResource.getHostOvfToolVersion());

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

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -209,18 +209,18 @@ public void testPerformInstanceConversionVddkUsesConfiguredLibguestfsBackend() {
209209
Mockito.when(mock.execute(Mockito.any())).thenReturn("");
210210
Mockito.when(mock.getExitValue()).thenReturn(0);
211211
})) {
212-
Path passwordFilePath = Path.of("/root/v2v.pass.cloud");
212+
Path passwordFilePath = Path.of("/root/v2v.pass.cloud.vcenter.local");
213213
filesMock.when(() -> Files.writeString(passwordFilePath, "secret")).thenReturn(passwordFilePath);
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);
217+
remoteInstanceTO, vmName, "/tmp/convert", "/opt/vddk", "libvirt", null, null, 1000L, false, null, "1.42.0");
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 "));
223+
Mockito.verify(scriptMock).add(Mockito.contains("--password-file /root/v2v.pass.cloud.vcenter.local "));
224224
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 "));
225225
}
226226
}
@@ -242,12 +242,12 @@ public void testPerformInstanceConversionVddkUsesConfiguredTransportsOrder() {
242242
Mockito.when(mock.execute(Mockito.any())).thenReturn("");
243243
Mockito.when(mock.getExitValue()).thenReturn(0);
244244
})) {
245-
Path passwordFilePath = Path.of("/root/v2v.pass.cloud");
245+
Path passwordFilePath = Path.of("/root/v2v.pass.cloud.vcenter.local");
246246
filesMock.when(() -> Files.writeString(passwordFilePath, "secret")).thenReturn(passwordFilePath);
247247
filesMock.when(() -> Files.deleteIfExists(passwordFilePath)).thenReturn(true);
248248

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

252252
Assert.assertTrue(result);
253253
Script scriptMock = ignored.constructed().get(0);
@@ -268,12 +268,12 @@ public void testPerformInstanceConversionVddkFailsWhenThumbprintUnavailable() {
268268
.when(convertInstanceCommandWrapper).getVcenterThumbprint(Mockito.anyString(), Mockito.anyLong(), Mockito.anyString());
269269

270270
try (MockedStatic<Files> filesMock = Mockito.mockStatic(Files.class)) {
271-
Path passwordFilePath = Path.of("/root/v2v.pass.cloud");
271+
Path passwordFilePath = Path.of("/root/v2v.pass.cloud.vcenter.local");
272272
filesMock.when(() -> Files.writeString(passwordFilePath, "secret")).thenReturn(passwordFilePath);
273273
filesMock.when(() -> Files.deleteIfExists(passwordFilePath)).thenReturn(true);
274274

275275
boolean result = convertInstanceCommandWrapper.performInstanceConversionVddk(
276-
remoteInstanceTO, vmName, "/tmp/convert", "/opt/vddk", "direct", null, null, 1000L, false, null);
276+
remoteInstanceTO, vmName, "/tmp/convert", "/opt/vddk", "direct", null, null, 1000L, false, null, "1.42.0");
277277

278278
Assert.assertFalse(result);
279279
}
@@ -294,13 +294,13 @@ public void testPerformInstanceConversionVddkUsesConfiguredThumbprintFromAgentPr
294294
Mockito.when(mock.execute(Mockito.any())).thenReturn("");
295295
Mockito.when(mock.getExitValue()).thenReturn(0);
296296
})) {
297-
Path passwordFilePath = Path.of("/root/v2v.pass.cloud");
297+
Path passwordFilePath = Path.of("/root/v2v.pass.cloud.vcenter.local");
298298
filesMock.when(() -> Files.writeString(passwordFilePath, "secret")).thenReturn(passwordFilePath);
299299
filesMock.when(() -> Files.deleteIfExists(passwordFilePath)).thenReturn(true);
300300

301301
boolean result = convertInstanceCommandWrapper.performInstanceConversionVddk(
302302
remoteInstanceTO, vmName, "/tmp/convert", "/opt/vddk", "direct", null,
303-
"AA:BB:CC:DD:EE", 1000L, false, null);
303+
"AA:BB:CC:DD:EE", 1000L, false, null, "1.42.0");
304304

305305
Assert.assertTrue(result);
306306
Script scriptMock = ignored.constructed().get(0);
@@ -309,4 +309,18 @@ public void testPerformInstanceConversionVddkUsesConfiguredThumbprintFromAgentPr
309309
.getVcenterThumbprint(Mockito.anyString(), Mockito.anyLong(), Mockito.anyString());
310310
}
311311
}
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+
}
312326
}

0 commit comments

Comments
 (0)