From 96adeb06fc4aa629af182100b0b01aa73d6f2715 Mon Sep 17 00:00:00 2001 From: nvazquez Date: Thu, 12 Jun 2025 16:35:23 -0300 Subject: [PATCH 1/4] [Vmware to KVM Migration] Display virt-v2v and ovftool versions for supported hosts for migration --- api/src/main/java/com/cloud/host/Host.java | 4 ++++ .../cloud/agent/manager/AgentManagerImpl.java | 17 ++++++++++++++++- .../kvm/resource/LibvirtComputingResource.java | 11 ++++++++++- .../wrapper/LibvirtReadyCommandWrapper.java | 8 ++++++++ ui/src/views/tools/ImportUnmanagedInstance.vue | 6 ++++++ 5 files changed, 44 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/com/cloud/host/Host.java b/api/src/main/java/com/cloud/host/Host.java index 56b4ed75a311..ecd7d419bfe7 100644 --- a/api/src/main/java/com/cloud/host/Host.java +++ b/api/src/main/java/com/cloud/host/Host.java @@ -57,6 +57,10 @@ public static String[] toStrings(Host.Type... types) { public static final String HOST_VOLUME_ENCRYPTION = "host.volume.encryption"; public static final String HOST_INSTANCE_CONVERSION = "host.instance.conversion"; + // Vmware to KVM Migration + String KVM_HOST_OVFTOOL_VERSION = "kvm.host.ovftool.version"; + String KVM_HOST_VIRTV2V_VERSION = "kvm.host.virtv2v.version"; + /** * @return name of the machine. */ diff --git a/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java index 9137d1c1dff9..81e7aa19d230 100644 --- a/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java @@ -54,6 +54,7 @@ import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.ThreadContext; @@ -703,11 +704,25 @@ protected AgentAttache notifyMonitorsOfConnection(final AgentAttache attache, fi Map detailsMap = readyAnswer.getDetailsMap(); if (detailsMap != null) { String uefiEnabled = detailsMap.get(Host.HOST_UEFI_ENABLE); + String virtv2vVersion = detailsMap.get(Host.KVM_HOST_VIRTV2V_VERSION); + String ovftoolVersion = detailsMap.get(Host.KVM_HOST_OVFTOOL_VERSION); logger.debug("Got HOST_UEFI_ENABLE [{}] for host [{}]:", uefiEnabled, host); - if (uefiEnabled != null) { + if (ObjectUtils.anyNotNull(uefiEnabled, virtv2vVersion, ovftoolVersion)) { _hostDao.loadDetails(host); + boolean updateNeeded = false; if (!uefiEnabled.equals(host.getDetails().get(Host.HOST_UEFI_ENABLE))) { host.getDetails().put(Host.HOST_UEFI_ENABLE, uefiEnabled); + updateNeeded = true; + } + if (StringUtils.isNotBlank(virtv2vVersion) && !virtv2vVersion.equals(host.getDetails().get(Host.KVM_HOST_VIRTV2V_VERSION))) { + host.getDetails().put(Host.KVM_HOST_VIRTV2V_VERSION, virtv2vVersion); + updateNeeded = true; + } + if (StringUtils.isNotBlank(ovftoolVersion) && !ovftoolVersion.equals(host.getDetails().get(Host.KVM_HOST_OVFTOOL_VERSION))) { + host.getDetails().put(Host.KVM_HOST_OVFTOOL_VERSION, ovftoolVersion); + updateNeeded = true; + } + if (updateNeeded) { _hostDao.saveDetails(host); } } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index 13518de5cb3c..657bfadb03d2 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -5368,8 +5368,17 @@ public boolean hostSupportsOvfExport() { return exitValue == 0; } + public String getHostVirtV2vVersion() { + String cmd = String.format("%s | awk '{print $2}'", INSTANCE_CONVERSION_SUPPORTED_CHECK_CMD); + return Script.runSimpleBashScript(cmd); + } + + public String getHostOvfToolVersion() { + return Script.runSimpleBashScript(OVF_EXPORT_TOOl_GET_VERSION_CMD); + } + public boolean ovfExportToolSupportsParallelThreads() { - String ovfExportToolVersion = Script.runSimpleBashScript(OVF_EXPORT_TOOl_GET_VERSION_CMD); + String ovfExportToolVersion = getHostOvfToolVersion(); if (StringUtils.isBlank(ovfExportToolVersion)) { return false; } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReadyCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReadyCommandWrapper.java index 8f23e79e4a32..5739da9a5d78 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReadyCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReadyCommandWrapper.java @@ -47,6 +47,14 @@ public Answer execute(final ReadyCommand command, final LibvirtComputingResource hostDetails.put(Host.HOST_UEFI_ENABLE, Boolean.TRUE.toString()); } + if (libvirtComputingResource.hostSupportsInstanceConversion()) { + hostDetails.put(Host.KVM_HOST_VIRTV2V_VERSION, libvirtComputingResource.getHostVirtV2vVersion()); + } + + if (libvirtComputingResource.hostSupportsOvfExport()) { + hostDetails.put(Host.KVM_HOST_OVFTOOL_VERSION, libvirtComputingResource.getHostOvfToolVersion()); + } + return new ReadyAnswer(command, hostDetails); } diff --git a/ui/src/views/tools/ImportUnmanagedInstance.vue b/ui/src/views/tools/ImportUnmanagedInstance.vue index 50a0d6318081..fae55b025cd5 100644 --- a/ui/src/views/tools/ImportUnmanagedInstance.vue +++ b/ui/src/views/tools/ImportUnmanagedInstance.vue @@ -944,6 +944,12 @@ export default { } else { host.name = host.name + ' (' + this.$t('label.not.supported') + ')' } + if (host.details['kvm.host.virtv2v.version']) { + host.name = host.name + ' (virt-v2v=' + host.details['kvm.host.virtv2v.version'] + ')' + } + if (host.details['kvm.host.ovftool.version']) { + host.name = host.name + ' (ovftool=' + host.details['kvm.host.virtv2v.version'] + ')' + } }) }) }, From 2a6fbbe4ebe8784dbc99a07c4608d49958ee3208 Mon Sep 17 00:00:00 2001 From: nvazquez Date: Thu, 12 Jun 2025 16:39:19 -0300 Subject: [PATCH 2/4] Fix UI display --- ui/src/views/tools/ImportUnmanagedInstance.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/views/tools/ImportUnmanagedInstance.vue b/ui/src/views/tools/ImportUnmanagedInstance.vue index fae55b025cd5..bf8b82875aff 100644 --- a/ui/src/views/tools/ImportUnmanagedInstance.vue +++ b/ui/src/views/tools/ImportUnmanagedInstance.vue @@ -948,7 +948,7 @@ export default { host.name = host.name + ' (virt-v2v=' + host.details['kvm.host.virtv2v.version'] + ')' } if (host.details['kvm.host.ovftool.version']) { - host.name = host.name + ' (ovftool=' + host.details['kvm.host.virtv2v.version'] + ')' + host.name = host.name + ' (ovftool=' + host.details['kvm.host.ovftool.version'] + ')' } }) }) From d3d271647f23fdb53f66d28b5a93f51ae39ca367 Mon Sep 17 00:00:00 2001 From: nvazquez Date: Mon, 16 Jun 2025 09:38:08 -0300 Subject: [PATCH 3/4] Address review comments --- api/src/main/java/com/cloud/host/Host.java | 11 +++++------ .../com/cloud/agent/manager/AgentManagerImpl.java | 12 ++++++------ .../kvm/resource/LibvirtComputingResource.java | 9 ++++++++- .../resource/wrapper/LibvirtReadyCommandWrapper.java | 4 ++-- ui/src/views/tools/ImportUnmanagedInstance.vue | 8 ++++---- 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/api/src/main/java/com/cloud/host/Host.java b/api/src/main/java/com/cloud/host/Host.java index ecd7d419bfe7..a3b6ccadc01c 100644 --- a/api/src/main/java/com/cloud/host/Host.java +++ b/api/src/main/java/com/cloud/host/Host.java @@ -53,13 +53,12 @@ public static String[] toStrings(Host.Type... types) { return strs; } } - public static final String HOST_UEFI_ENABLE = "host.uefi.enable"; - public static final String HOST_VOLUME_ENCRYPTION = "host.volume.encryption"; - public static final String HOST_INSTANCE_CONVERSION = "host.instance.conversion"; - // Vmware to KVM Migration - String KVM_HOST_OVFTOOL_VERSION = "kvm.host.ovftool.version"; - String KVM_HOST_VIRTV2V_VERSION = "kvm.host.virtv2v.version"; + String HOST_UEFI_ENABLE = "host.uefi.enable"; + String HOST_VOLUME_ENCRYPTION = "host.volume.encryption"; + String HOST_INSTANCE_CONVERSION = "host.instance.conversion"; + String HOST_OVFTOOL_VERSION = "host.ovftool.version"; + String HOST_VIRTV2V_VERSION = "host.virtv2v.version"; /** * @return name of the machine. diff --git a/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java index 81e7aa19d230..aff528efede2 100644 --- a/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java @@ -704,8 +704,8 @@ protected AgentAttache notifyMonitorsOfConnection(final AgentAttache attache, fi Map detailsMap = readyAnswer.getDetailsMap(); if (detailsMap != null) { String uefiEnabled = detailsMap.get(Host.HOST_UEFI_ENABLE); - String virtv2vVersion = detailsMap.get(Host.KVM_HOST_VIRTV2V_VERSION); - String ovftoolVersion = detailsMap.get(Host.KVM_HOST_OVFTOOL_VERSION); + String virtv2vVersion = detailsMap.get(Host.HOST_VIRTV2V_VERSION); + String ovftoolVersion = detailsMap.get(Host.HOST_OVFTOOL_VERSION); logger.debug("Got HOST_UEFI_ENABLE [{}] for host [{}]:", uefiEnabled, host); if (ObjectUtils.anyNotNull(uefiEnabled, virtv2vVersion, ovftoolVersion)) { _hostDao.loadDetails(host); @@ -714,12 +714,12 @@ protected AgentAttache notifyMonitorsOfConnection(final AgentAttache attache, fi host.getDetails().put(Host.HOST_UEFI_ENABLE, uefiEnabled); updateNeeded = true; } - if (StringUtils.isNotBlank(virtv2vVersion) && !virtv2vVersion.equals(host.getDetails().get(Host.KVM_HOST_VIRTV2V_VERSION))) { - host.getDetails().put(Host.KVM_HOST_VIRTV2V_VERSION, virtv2vVersion); + if (StringUtils.isNotBlank(virtv2vVersion) && !virtv2vVersion.equals(host.getDetails().get(Host.HOST_VIRTV2V_VERSION))) { + host.getDetails().put(Host.HOST_VIRTV2V_VERSION, virtv2vVersion); updateNeeded = true; } - if (StringUtils.isNotBlank(ovftoolVersion) && !ovftoolVersion.equals(host.getDetails().get(Host.KVM_HOST_OVFTOOL_VERSION))) { - host.getDetails().put(Host.KVM_HOST_OVFTOOL_VERSION, ovftoolVersion); + if (StringUtils.isNotBlank(ovftoolVersion) && !ovftoolVersion.equals(host.getDetails().get(Host.HOST_OVFTOOL_VERSION))) { + host.getDetails().put(Host.HOST_OVFTOOL_VERSION, ovftoolVersion); updateNeeded = true; } if (updateNeeded) { diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index 657bfadb03d2..bb2bc6b4ab6e 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -17,6 +17,8 @@ package com.cloud.hypervisor.kvm.resource; import static com.cloud.host.Host.HOST_INSTANCE_CONVERSION; +import static com.cloud.host.Host.HOST_OVFTOOL_VERSION; +import static com.cloud.host.Host.HOST_VIRTV2V_VERSION; import static com.cloud.host.Host.HOST_VOLUME_ENCRYPTION; import java.io.BufferedReader; @@ -3766,7 +3768,12 @@ public StartupCommand[] initialize() { cmd.setIqn(getIqn()); cmd.getHostDetails().put(HOST_VOLUME_ENCRYPTION, String.valueOf(hostSupportsVolumeEncryption())); cmd.setHostTags(getHostTags()); - cmd.getHostDetails().put(HOST_INSTANCE_CONVERSION, String.valueOf(hostSupportsInstanceConversion())); + boolean instanceConversionSupported = hostSupportsInstanceConversion(); + cmd.getHostDetails().put(HOST_INSTANCE_CONVERSION, String.valueOf(instanceConversionSupported)); + if (instanceConversionSupported) { + cmd.getHostDetails().put(HOST_VIRTV2V_VERSION, getHostVirtV2vVersion()); + cmd.getHostDetails().put(HOST_OVFTOOL_VERSION, getHostOvfToolVersion()); + } HealthCheckResult healthCheckResult = getHostHealthCheckResult(); if (healthCheckResult != HealthCheckResult.IGNORE) { cmd.setHostHealthCheckResult(healthCheckResult == HealthCheckResult.SUCCESS); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReadyCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReadyCommandWrapper.java index 5739da9a5d78..485254c6bb94 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReadyCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReadyCommandWrapper.java @@ -48,11 +48,11 @@ public Answer execute(final ReadyCommand command, final LibvirtComputingResource } if (libvirtComputingResource.hostSupportsInstanceConversion()) { - hostDetails.put(Host.KVM_HOST_VIRTV2V_VERSION, libvirtComputingResource.getHostVirtV2vVersion()); + hostDetails.put(Host.HOST_VIRTV2V_VERSION, libvirtComputingResource.getHostVirtV2vVersion()); } if (libvirtComputingResource.hostSupportsOvfExport()) { - hostDetails.put(Host.KVM_HOST_OVFTOOL_VERSION, libvirtComputingResource.getHostOvfToolVersion()); + hostDetails.put(Host.HOST_OVFTOOL_VERSION, libvirtComputingResource.getHostOvfToolVersion()); } return new ReadyAnswer(command, hostDetails); diff --git a/ui/src/views/tools/ImportUnmanagedInstance.vue b/ui/src/views/tools/ImportUnmanagedInstance.vue index bf8b82875aff..95c14f141d20 100644 --- a/ui/src/views/tools/ImportUnmanagedInstance.vue +++ b/ui/src/views/tools/ImportUnmanagedInstance.vue @@ -944,11 +944,11 @@ export default { } else { host.name = host.name + ' (' + this.$t('label.not.supported') + ')' } - if (host.details['kvm.host.virtv2v.version']) { - host.name = host.name + ' (virt-v2v=' + host.details['kvm.host.virtv2v.version'] + ')' + if (host.details['host.virtv2v.version']) { + host.name = host.name + ' (virt-v2v=' + host.details['host.virtv2v.version'] + ')' } - if (host.details['kvm.host.ovftool.version']) { - host.name = host.name + ' (ovftool=' + host.details['kvm.host.ovftool.version'] + ')' + if (host.details['host.ovftool.version']) { + host.name = host.name + ' (ovftool=' + host.details['host.ovftool.version'] + ')' } }) }) From 9d5cff2f8e7038c1ddc6df5574872bb1c83294f8 Mon Sep 17 00:00:00 2001 From: nvazquez Date: Tue, 17 Jun 2025 23:43:44 -0300 Subject: [PATCH 4/4] Fix ovftool and version display - also display versions on host details view --- .../kvm/resource/LibvirtComputingResource.java | 11 ++++++++++- ui/public/locales/en.json | 2 ++ ui/src/views/infra/HostInfo.vue | 16 ++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index bb2bc6b4ab6e..7fb3839860f7 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -3772,6 +3772,8 @@ public StartupCommand[] initialize() { cmd.getHostDetails().put(HOST_INSTANCE_CONVERSION, String.valueOf(instanceConversionSupported)); if (instanceConversionSupported) { cmd.getHostDetails().put(HOST_VIRTV2V_VERSION, getHostVirtV2vVersion()); + } + if (hostSupportsOvfExport()) { cmd.getHostDetails().put(HOST_OVFTOOL_VERSION, getHostOvfToolVersion()); } HealthCheckResult healthCheckResult = getHostHealthCheckResult(); @@ -5376,11 +5378,18 @@ public boolean hostSupportsOvfExport() { } public String getHostVirtV2vVersion() { + if (!hostSupportsInstanceConversion()) { + return ""; + } String cmd = String.format("%s | awk '{print $2}'", INSTANCE_CONVERSION_SUPPORTED_CHECK_CMD); - return Script.runSimpleBashScript(cmd); + String version = Script.runSimpleBashScript(cmd); + return StringUtils.isNotBlank(version) ? version.split(",")[0] : ""; } public String getHostOvfToolVersion() { + if (!hostSupportsOvfExport()) { + return ""; + } return Script.runSimpleBashScript(OVF_EXPORT_TOOl_GET_VERSION_CMD); } diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 027bbbd123f4..fa165679f4f7 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -1089,7 +1089,9 @@ "label.host": "IP address", "label.host.alerts": "Hosts in alert state", "label.host.name": "Host name", +"label.host.ovftool.version": "OVFTool Version", "label.host.tag": "Host tag", +"label.host.virtv2v.version": "Virt-v2v Version", "label.hostcontrolstate": "Compute Resource Status", "label.hostid": "Host", "label.hostname": "Host", diff --git a/ui/src/views/infra/HostInfo.vue b/ui/src/views/infra/HostInfo.vue index 259445154a01..a6d8fe8595e2 100644 --- a/ui/src/views/infra/HostInfo.vue +++ b/ui/src/views/infra/HostInfo.vue @@ -56,6 +56,22 @@ + +
+ {{ $t('label.host.virtv2v.version') }} +
+ {{ host.details['host.virtv2v.version'] }} +
+
+
+ +
+ {{ $t('label.host.ovftool.version') }} +
+ {{ host.details['host.ovftool.version'] }} +
+
+
{{ $t('label.hosttags') }}