This is an automated email from the ASF dual-hosted git repository. weizhou pushed a commit to branch 4.20 in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/4.20 by this push: new 1a223fd2bac server: Fix VM import DB sequence issue on import failure (#11659) 1a223fd2bac is described below commit 1a223fd2bac9ede56f07cb60421566472760a894 Author: Nicolas Vazquez <nicovazque...@gmail.com> AuthorDate: Tue Sep 23 03:48:18 2025 -0300 server: Fix VM import DB sequence issue on import failure (#11659) * Fix VM import DB sequence issue on import failure * Remove ununsed imports * Refactor to avoid duplicating the next ID for VM sequence --- api/src/main/java/com/cloud/vm/UserVmService.java | 26 ++++++++- .../main/java/com/cloud/vm/UserVmManagerImpl.java | 53 ++++++++++------- .../cloudstack/vm/UnmanagedVMsManagerImpl.java | 68 +++++++--------------- .../cloudstack/vm/UnmanagedVMsManagerImplTest.java | 3 - 4 files changed, 80 insertions(+), 70 deletions(-) diff --git a/api/src/main/java/com/cloud/vm/UserVmService.java b/api/src/main/java/com/cloud/vm/UserVmService.java index 72b18b70e18..dc9e8c1f0d8 100644 --- a/api/src/main/java/com/cloud/vm/UserVmService.java +++ b/api/src/main/java/com/cloud/vm/UserVmService.java @@ -503,7 +503,31 @@ public interface UserVmService { void collectVmNetworkStatistics (UserVm userVm); - UserVm importVM(final DataCenter zone, final Host host, final VirtualMachineTemplate template, final String instanceName, final String displayName, final Account owner, final String userData, final Account caller, final Boolean isDisplayVm, final String keyboard, + /** + * Import VM into CloudStack + * @param zone importing zone + * @param host importing host + * @param template template for the imported VM + * @param instanceNameInternal set to null to CloudStack to autogenerate from the next available VM ID on database + * @param displayName display name for the imported VM + * @param owner owner of the imported VM + * @param userData user data for the imported VM + * @param caller caller account + * @param isDisplayVm true to display the imported VM + * @param keyboard keyboard distribution for the imported VM + * @param accountId account ID + * @param userId user ID + * @param serviceOffering service offering for the imported VM + * @param sshPublicKey ssh key for the imported VM + * @param hostName the name for the imported VM + * @param hypervisorType hypervisor type for the imported VM + * @param customParameters details for the imported VM + * @param powerState power state of the imported VM + * @param networkNicMap network to nic mapping + * @return the imported VM + * @throws InsufficientCapacityException in case of errors + */ + UserVm importVM(final DataCenter zone, final Host host, final VirtualMachineTemplate template, final String instanceNameInternal, final String displayName, final Account owner, final String userData, final Account caller, final Boolean isDisplayVm, final String keyboard, final long accountId, final long userId, final ServiceOffering serviceOffering, final String sshPublicKey, final String hostName, final HypervisorType hypervisorType, final Map<String, String> customParameters, final VirtualMachine.PowerState powerState, final LinkedHashMap<String, List<NicProfile>> networkNicMap) throws InsufficientCapacityException; diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 794d28c7adc..5b3284c2c1e 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -8989,34 +8989,47 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir } } + private String getInternalName(long accountId, long vmId) { + String instanceSuffix = _configDao.getValue(Config.InstanceName.key()); + if (instanceSuffix == null) { + instanceSuffix = "DEFAULT"; + } + return VirtualMachineName.getVmName(vmId, accountId, instanceSuffix); + } + @Override - public UserVm importVM(final DataCenter zone, final Host host, final VirtualMachineTemplate template, final String instanceName, final String displayName, + public UserVm importVM(final DataCenter zone, final Host host, final VirtualMachineTemplate template, final String instanceNameInternal, final String displayName, final Account owner, final String userData, final Account caller, final Boolean isDisplayVm, final String keyboard, final long accountId, final long userId, final ServiceOffering serviceOffering, final String sshPublicKeys, final String hostName, final HypervisorType hypervisorType, final Map<String, String> customParameters, final VirtualMachine.PowerState powerState, final LinkedHashMap<String, List<NicProfile>> networkNicMap) throws InsufficientCapacityException { - if (zone == null) { - throw new InvalidParameterValueException("Unable to import virtual machine with invalid zone"); - } - if (host == null && hypervisorType == HypervisorType.VMware) { - throw new InvalidParameterValueException("Unable to import virtual machine with invalid host"); - } + return Transaction.execute((TransactionCallbackWithException<UserVm, InsufficientCapacityException>) status -> { + if (zone == null) { + throw new InvalidParameterValueException("Unable to import virtual machine with invalid zone"); + } + if (host == null && hypervisorType == HypervisorType.VMware) { + throw new InvalidParameterValueException("Unable to import virtual machine with invalid host"); + } - final long id = _vmDao.getNextInSequence(Long.class, "id"); + final long id = _vmDao.getNextInSequence(Long.class, "id"); + String instanceName = StringUtils.isBlank(instanceNameInternal) ? + getInternalName(owner.getAccountId(), id) : + instanceNameInternal; - if (hostName != null) { - // Check is hostName is RFC compliant - checkNameForRFCCompliance(hostName); - } + if (hostName != null) { + // Check is hostName is RFC compliant + checkNameForRFCCompliance(hostName); + } - final String uuidName = _uuidMgr.generateUuid(UserVm.class, null); - final Host lastHost = powerState != VirtualMachine.PowerState.PowerOn ? host : null; - final Boolean dynamicScalingEnabled = checkIfDynamicScalingCanBeEnabled(null, serviceOffering, template, zone.getId()); - return commitUserVm(true, zone, host, lastHost, template, hostName, displayName, owner, - null, null, userData, null, null, isDisplayVm, keyboard, - accountId, userId, serviceOffering, template.getFormat().equals(ImageFormat.ISO), sshPublicKeys, networkNicMap, - id, instanceName, uuidName, hypervisorType, customParameters, - null, null, null, powerState, dynamicScalingEnabled, null, serviceOffering.getDiskOfferingId(), null); + final String uuidName = _uuidMgr.generateUuid(UserVm.class, null); + final Host lastHost = powerState != VirtualMachine.PowerState.PowerOn ? host : null; + final Boolean dynamicScalingEnabled = checkIfDynamicScalingCanBeEnabled(null, serviceOffering, template, zone.getId()); + return commitUserVm(true, zone, host, lastHost, template, hostName, displayName, owner, + null, null, userData, null, null, isDisplayVm, keyboard, + accountId, userId, serviceOffering, template.getFormat().equals(ImageFormat.ISO), sshPublicKeys, networkNicMap, + id, instanceName, uuidName, hypervisorType, customParameters, + null, null, null, powerState, dynamicScalingEnabled, null, serviceOffering.getDiskOfferingId(), null); + }); } @Override diff --git a/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java b/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java index 865884c2538..981f83936d2 100644 --- a/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java @@ -133,7 +133,6 @@ import com.cloud.vm.UserVmVO; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineManager; -import com.cloud.vm.VirtualMachineName; import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.VirtualMachineProfileImpl; import com.cloud.vm.VmDetailConstants; @@ -1111,13 +1110,13 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { } } - private UserVm importVirtualMachineInternal(final UnmanagedInstanceTO unmanagedInstance, final String instanceName, final DataCenter zone, final Cluster cluster, final HostVO host, + private UserVm importVirtualMachineInternal(final UnmanagedInstanceTO unmanagedInstance, final String instanceNameInternal, final DataCenter zone, final Cluster cluster, final HostVO host, final VirtualMachineTemplate template, final String displayName, final String hostName, final Account caller, final Account owner, final Long userId, final ServiceOfferingVO serviceOffering, final Map<String, Long> dataDiskOfferingMap, final Map<String, Long> nicNetworkMap, final Map<String, Network.IpAddresses> callerNicIpAddressMap, final Map<String, String> details, final boolean migrateAllowed, final boolean forced, final boolean isImportUnmanagedFromSameHypervisor) { logger.debug(LogUtils.logGsonWithoutException("Trying to import VM [%s] with name [%s], in zone [%s], cluster [%s], and host [%s], using template [%s], service offering [%s], disks map [%s], NICs map [%s] and details [%s].", - unmanagedInstance, instanceName, zone, cluster, host, template, serviceOffering, dataDiskOfferingMap, nicNetworkMap, details)); + unmanagedInstance, displayName, zone, cluster, host, template, serviceOffering, dataDiskOfferingMap, nicNetworkMap, details)); UserVm userVm = null; ServiceOfferingVO validatedServiceOffering = null; try { @@ -1129,8 +1128,8 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { } String internalCSName = unmanagedInstance.getInternalCSName(); - if (StringUtils.isEmpty(internalCSName)) { - internalCSName = instanceName; + if (StringUtils.isEmpty(instanceNameInternal)) { + internalCSName = instanceNameInternal; } Map<String, String> allDetails = new HashMap<>(details); if (validatedServiceOffering.isDynamic()) { @@ -1142,18 +1141,18 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { } if (!migrateAllowed && host != null && !hostSupportsServiceOfferingAndTemplate(host, validatedServiceOffering, template)) { - throw new InvalidParameterValueException(String.format("Service offering: %s or template: %s is not compatible with host: %s of unmanaged VM: %s", serviceOffering.getUuid(), template.getUuid(), host.getUuid(), instanceName)); + throw new InvalidParameterValueException(String.format("Service offering: %s or template: %s is not compatible with host: %s of unmanaged VM: %s", serviceOffering.getUuid(), template.getUuid(), host.getUuid(), displayName)); } // Check disks and supplied disk offerings List<UnmanagedInstanceTO.Disk> unmanagedInstanceDisks = unmanagedInstance.getDisks(); if (CollectionUtils.isEmpty(unmanagedInstanceDisks)) { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("No attached disks found for the unmanaged VM: %s", instanceName)); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("No attached disks found for the unmanaged VM: %s", displayName)); } Pair<UnmanagedInstanceTO.Disk, List<UnmanagedInstanceTO.Disk>> rootAndDataDisksPair = getRootAndDataDisks(unmanagedInstanceDisks, dataDiskOfferingMap); final UnmanagedInstanceTO.Disk rootDisk = rootAndDataDisksPair.first(); final List<UnmanagedInstanceTO.Disk> dataDisks = rootAndDataDisksPair.second(); if (rootDisk == null || StringUtils.isEmpty(rootDisk.getController())) { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VM import failed. Unable to retrieve root disk details for VM: %s ", instanceName)); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VM import failed. Unable to retrieve root disk details for VM: %s ", displayName)); } if (cluster.getHypervisorType() == Hypervisor.HypervisorType.KVM) { Long rootDiskOfferingId = validatedServiceOffering.getDiskOfferingId(); @@ -1203,13 +1202,13 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { validatedServiceOffering, null, hostName, cluster.getHypervisorType(), allDetails, powerState, null); } catch (InsufficientCapacityException ice) { - String errorMsg = String.format("Failed to import VM [%s] due to [%s].", instanceName, ice.getMessage()); + String errorMsg = String.format("Failed to import VM [%s] due to [%s].", displayName, ice.getMessage()); logger.error(errorMsg, ice); throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, errorMsg); } if (userVm == null) { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import vm name: %s", instanceName)); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import vm name: %s", displayName)); } List<Pair<DiskProfile, StoragePool>> diskProfileStoragePoolList = new ArrayList<>(); try { @@ -1239,9 +1238,9 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { deviceId++; } } catch (Exception e) { - logger.error(String.format("Failed to import volumes while importing vm: %s", instanceName), e); + logger.error(String.format("Failed to import volumes while importing vm: %s", displayName), e); cleanupFailedImportVM(userVm); - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import volumes while importing vm: %s. %s", instanceName, StringUtils.defaultString(e.getMessage()))); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import volumes while importing vm: %s. %s", displayName, StringUtils.defaultString(e.getMessage()))); } try { int nicIndex = 0; @@ -1252,9 +1251,9 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { nicIndex++; } } catch (Exception e) { - logger.error(String.format("Failed to import NICs while importing vm: %s", instanceName), e); + logger.error(String.format("Failed to import NICs while importing vm: %s", displayName), e); cleanupFailedImportVM(userVm); - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import NICs while importing vm: %s. %s", instanceName, StringUtils.defaultString(e.getMessage()))); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import NICs while importing vm: %s. %s", displayName, StringUtils.defaultString(e.getMessage()))); } if (migrateAllowed) { userVm = migrateImportedVM(host, template, validatedServiceOffering, userVm, owner, diskProfileStoragePoolList); @@ -1668,8 +1667,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { checkConversionSupportOnHost(convertHost, sourceVMName, true); } - String instanceName = getGeneratedInstanceName(owner); - checkNetworkingBeforeConvertingVmwareInstance(zone, owner, instanceName, hostName, sourceVMwareInstance, nicNetworkMap, nicIpAddressMap, forced); + checkNetworkingBeforeConvertingVmwareInstance(zone, owner, displayName, hostName, sourceVMwareInstance, nicNetworkMap, nicIpAddressMap, forced); UnmanagedInstanceTO convertedInstance; if (cmd.getForceMsToImportVmFiles() || !conversionSupportAnswer.isOvfExportSupported()) { // Uses MS for OVF export to temporary conversion location @@ -1690,14 +1688,14 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { } sanitizeConvertedInstance(convertedInstance, sourceVMwareInstance); - UserVm userVm = importVirtualMachineInternal(convertedInstance, instanceName, zone, destinationCluster, null, + UserVm userVm = importVirtualMachineInternal(convertedInstance, null, zone, destinationCluster, null, template, displayName, hostName, caller, owner, userId, serviceOffering, dataDiskOfferingMap, nicNetworkMap, nicIpAddressMap, details, false, forced, false); long timeElapsedInSecs = (System.currentTimeMillis() - importStartTime) / 1000; logger.debug(String.format("VMware VM %s imported successfully to CloudStack instance %s (%s), Time taken: %d secs, OVF files imported from %s, Source VMware VM details - OS: %s, PowerState: %s, Disks: %s, NICs: %s", - sourceVMName, instanceName, displayName, timeElapsedInSecs, (ovfTemplateOnConvertLocation != null)? "MS" : "KVM Host", sourceVMwareInstance.getOperatingSystem(), sourceVMwareInstance.getPowerState(), sourceVMwareInstance.getDisks(), sourceVMwareInstance.getNics())); + sourceVMName, displayName, displayName, timeElapsedInSecs, (ovfTemplateOnConvertLocation != null)? "MS" : "KVM Host", sourceVMwareInstance.getOperatingSystem(), sourceVMwareInstance.getPowerState(), sourceVMwareInstance.getDisks(), sourceVMwareInstance.getNics())); return userVm; } catch (CloudRuntimeException e) { logger.error(String.format("Error importing VM: %s", e.getMessage()), e); @@ -1714,7 +1712,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { } } - private void checkNetworkingBeforeConvertingVmwareInstance(DataCenter zone, Account owner, String instanceName, + private void checkNetworkingBeforeConvertingVmwareInstance(DataCenter zone, Account owner, String displayName, String hostName, UnmanagedInstanceTO sourceVMwareInstance, Map<String, Long> nicNetworkMap, Map<String, Network.IpAddresses> nicIpAddressMap, @@ -1742,9 +1740,9 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { } boolean autoImport = ipAddresses != null && ipAddresses.getIp4Address() != null && ipAddresses.getIp4Address().equalsIgnoreCase("auto"); checkUnmanagedNicAndNetworkMacAddressForImport(network, nic, forced); - checkUnmanagedNicAndNetworkForImport(instanceName, nic, network, zone, owner, autoImport, Hypervisor.HypervisorType.KVM); - checkUnmanagedNicAndNetworkHostnameForImport(instanceName, nic, network, hostName); - checkUnmanagedNicIpAndNetworkForImport(instanceName, nic, network, ipAddresses); + checkUnmanagedNicAndNetworkForImport(displayName, nic, network, zone, owner, autoImport, Hypervisor.HypervisorType.KVM); + checkUnmanagedNicAndNetworkHostnameForImport(displayName, nic, network, hostName); + checkUnmanagedNicIpAndNetworkForImport(displayName, nic, network, ipAddresses); } } @@ -1758,15 +1756,6 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { } } - private String getGeneratedInstanceName(Account owner) { - long id = vmDao.getNextInSequence(Long.class, "id"); - String instanceSuffix = configurationDao.getValue(Config.InstanceName.key()); - if (instanceSuffix == null) { - instanceSuffix = "DEFAULT"; - } - return VirtualMachineName.getVmName(id, owner.getId(), instanceSuffix); - } - private void sanitizeConvertedInstance(UnmanagedInstanceTO convertedInstance, UnmanagedInstanceTO sourceVMwareInstance) { convertedInstance.setCpuCores(sourceVMwareInstance.getCpuCores()); convertedInstance.setCpuSpeed(sourceVMwareInstance.getCpuSpeed()); @@ -2512,10 +2501,8 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { } VirtualMachine.PowerState powerState = VirtualMachine.PowerState.PowerOff; - String internalName = getInternalName(owner.getAccountId()); - try { - userVm = userVmManager.importVM(zone, null, template, internalName, displayName, owner, + userVm = userVmManager.importVM(zone, null, template, null, displayName, owner, null, caller, true, null, owner.getAccountId(), userId, serviceOffering, null, hostName, Hypervisor.HypervisorType.KVM, allDetails, powerState, null); @@ -2654,10 +2641,8 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { profiles.add(nicProfile); networkNicMap.put(network.getUuid(), profiles); - String internalName = getInternalName(owner.getAccountId()); - try { - userVm = userVmManager.importVM(zone, null, template, internalName, displayName, owner, + userVm = userVmManager.importVM(zone, null, template, null, displayName, owner, null, caller, true, null, owner.getAccountId(), userId, serviceOffering, null, hostName, Hypervisor.HypervisorType.KVM, allDetails, powerState, networkNicMap); @@ -2868,15 +2853,6 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { return getRemoteVmsAnswer.getUnmanagedInstances(); } - private String getInternalName(long accounId) { - String instanceSuffix = configurationDao.getValue(Config.InstanceName.key()); - if (instanceSuffix == null) { - instanceSuffix = "DEFAULT"; - } - long vmId = userVmDao.getNextInSequence(Long.class, "id"); - return VirtualMachineName.getVmName(vmId, accounId, instanceSuffix); - } - @Override public String getConfigComponentName() { return UnmanagedVMsManagerImpl.class.getSimpleName(); diff --git a/server/src/test/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImplTest.java b/server/src/test/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImplTest.java index 4ea6af7c6f4..4aa5df9d411 100644 --- a/server/src/test/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImplTest.java +++ b/server/src/test/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImplTest.java @@ -507,7 +507,6 @@ public class UnmanagedVMsManagerImplTest { VMTemplateVO template = Mockito.mock(VMTemplateVO.class); when(templateDao.findByName(anyString())).thenReturn(template); HostVO host = Mockito.mock(HostVO.class); - when(userVmDao.getNextInSequence(Long.class, "id")).thenReturn(1L); DeployDestination mockDest = Mockito.mock(DeployDestination.class); when(deploymentPlanningManager.planDeployment(any(), any(), any(), any())).thenReturn(mockDest); DiskProfile diskProfile = Mockito.mock(DiskProfile.class); @@ -593,7 +592,6 @@ public class UnmanagedVMsManagerImplTest { String tmplFileName = "5b8d689a-e61a-4ac3-9b76-e121ff90fbd3"; long newVmId = 2L; long networkId = 1L; - when(vmDao.getNextInSequence(Long.class, "id")).thenReturn(newVmId); ClusterVO cluster = mock(ClusterVO.class); when(cluster.getId()).thenReturn(clusterId); @@ -744,7 +742,6 @@ public class UnmanagedVMsManagerImplTest { when(hostDao.findById(anyLong())).thenReturn(host); NetworkOffering netOffering = Mockito.mock(NetworkOffering.class); when(entityMgr.findById(NetworkOffering.class, 0L)).thenReturn(netOffering); - when(userVmDao.getNextInSequence(Long.class, "id")).thenReturn(1L); DeployDestination mockDest = Mockito.mock(DeployDestination.class); when(deploymentPlanningManager.planDeployment(any(), any(), any(), any())).thenReturn(mockDest); DiskProfile diskProfile = Mockito.mock(DiskProfile.class);