From 40dec996591a99d40b51313fa23c8d937bed780f Mon Sep 17 00:00:00 2001 From: Suresh Kumar Anaparti Date: Tue, 23 Sep 2025 12:07:10 +0530 Subject: [PATCH 1/5] server: Cleanup allocated snapshots / vm snapshots, and update pending ones to Error on MS start (#8452) * Remove allocated snapshots / vm snapshots on start * Check and Cleanup snapshots / vm snapshots on MS start * rebase fixes * Update volume state (from Snapshotting) on MS start when its snapshot job not finished and snapshot in Creating state --- .../cloud/vm/snapshot/VMSnapshotService.java | 3 + .../api/storage/SnapshotDataFactory.java | 3 + .../api/storage/VMSnapshotStrategy.java | 3 + .../cloud/vm/snapshot/VMSnapshotManager.java | 1 - .../cloud/vm/snapshot/dao/VMSnapshotDao.java | 2 + .../snapshot/SnapshotDataFactoryImpl.java | 22 +++++++- .../vmsnapshot/DefaultVMSnapshotStrategy.java | 10 ++++ .../vmsnapshot/ScaleIOVMSnapshotStrategy.java | 10 ++++ .../jobs/impl/AsyncJobManagerImpl.java | 55 ++++++++++++++++++- .../vm/snapshot/VMSnapshotManagerImpl.java | 7 +++ 10 files changed, 111 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/com/cloud/vm/snapshot/VMSnapshotService.java b/api/src/main/java/com/cloud/vm/snapshot/VMSnapshotService.java index 84a56aaedd3..754e463e710 100644 --- a/api/src/main/java/com/cloud/vm/snapshot/VMSnapshotService.java +++ b/api/src/main/java/com/cloud/vm/snapshot/VMSnapshotService.java @@ -19,6 +19,7 @@ package com.cloud.vm.snapshot; import java.util.List; +import com.cloud.utils.fsm.NoTransitionException; import org.apache.cloudstack.api.command.user.vmsnapshot.ListVMSnapshotCmd; import com.cloud.exception.ConcurrentOperationException; @@ -53,4 +54,6 @@ public interface VMSnapshotService { * @param id vm id */ boolean deleteVMSnapshotsFromDB(Long vmId, boolean unmanage); + + void updateOperationFailed(VMSnapshot vmSnapshot) throws NoTransitionException; } diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotDataFactory.java b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotDataFactory.java index 2a2db4af3e5..d318707a29a 100644 --- a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotDataFactory.java +++ b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotDataFactory.java @@ -21,6 +21,7 @@ package org.apache.cloudstack.engine.subsystem.api.storage; import java.util.List; import com.cloud.storage.DataStoreRole; +import com.cloud.utils.fsm.NoTransitionException; public interface SnapshotDataFactory { SnapshotInfo getSnapshot(long snapshotId, DataStore store); @@ -42,4 +43,6 @@ public interface SnapshotDataFactory { List listSnapshotOnCache(long snapshotId); SnapshotInfo getReadySnapshotOnCache(long snapshotId); + + void updateOperationFailed(long snapshotId) throws NoTransitionException; } diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/VMSnapshotStrategy.java b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/VMSnapshotStrategy.java index 6372aa3bd94..2939342ec27 100644 --- a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/VMSnapshotStrategy.java +++ b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/VMSnapshotStrategy.java @@ -18,6 +18,7 @@ */ package org.apache.cloudstack.engine.subsystem.api.storage; +import com.cloud.utils.fsm.NoTransitionException; import com.cloud.vm.snapshot.VMSnapshot; public interface VMSnapshotStrategy { @@ -44,4 +45,6 @@ public interface VMSnapshotStrategy { * @return true if vm snapshot removed from DB, false if not. */ boolean deleteVMSnapshotFromDB(VMSnapshot vmSnapshot, boolean unmanage); + + void updateOperationFailed(VMSnapshot vmSnapshot) throws NoTransitionException; } diff --git a/engine/components-api/src/main/java/com/cloud/vm/snapshot/VMSnapshotManager.java b/engine/components-api/src/main/java/com/cloud/vm/snapshot/VMSnapshotManager.java index a01d4ee5cae..997b413c099 100644 --- a/engine/components-api/src/main/java/com/cloud/vm/snapshot/VMSnapshotManager.java +++ b/engine/components-api/src/main/java/com/cloud/vm/snapshot/VMSnapshotManager.java @@ -54,5 +54,4 @@ public interface VMSnapshotManager extends VMSnapshotService, Manager { boolean hasActiveVMSnapshotTasks(Long vmId); RestoreVMSnapshotCommand createRestoreCommand(UserVmVO userVm, List vmSnapshotVOs); - } diff --git a/engine/schema/src/main/java/com/cloud/vm/snapshot/dao/VMSnapshotDao.java b/engine/schema/src/main/java/com/cloud/vm/snapshot/dao/VMSnapshotDao.java index 0143aaa1e73..bbdbfb5b520 100644 --- a/engine/schema/src/main/java/com/cloud/vm/snapshot/dao/VMSnapshotDao.java +++ b/engine/schema/src/main/java/com/cloud/vm/snapshot/dao/VMSnapshotDao.java @@ -38,6 +38,8 @@ public interface VMSnapshotDao extends GenericDao, StateDao< VMSnapshotVO findByName(Long vmId, String name); List listByAccountId(Long accountId); + List searchByVms(List vmIds); + List searchRemovedByVms(List vmIds, Long batchSize); } diff --git a/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java b/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java index 4d8919ccc48..cd314b0be63 100644 --- a/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java +++ b/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java @@ -23,11 +23,16 @@ import java.util.List; import javax.inject.Inject; +import com.cloud.storage.Snapshot; +import com.cloud.storage.Volume; +import com.cloud.utils.fsm.NoTransitionException; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; import org.apache.commons.collections.CollectionUtils; @@ -73,7 +78,7 @@ public class SnapshotDataFactoryImpl implements SnapshotDataFactory { for (SnapshotDataStoreVO snapshotDataStoreVO : allSnapshotsFromVolumeAndDataStore) { DataStore store = storeMgr.getDataStore(snapshotDataStoreVO.getDataStoreId(), role); SnapshotVO snapshot = snapshotDao.findById(snapshotDataStoreVO.getSnapshotId()); - if (snapshot == null){ //snapshot may have been removed; + if (snapshot == null) { //snapshot may have been removed; continue; } SnapshotObject info = SnapshotObject.getSnapshotObject(snapshot, store); @@ -107,8 +112,6 @@ public class SnapshotDataFactoryImpl implements SnapshotDataFactory { return infos; } - - @Override public SnapshotInfo getSnapshot(long snapshotId, long storeId, DataStoreRole role) { SnapshotVO snapshot = snapshotDao.findById(snapshotId); @@ -202,4 +205,17 @@ public class SnapshotDataFactoryImpl implements SnapshotDataFactory { return snapObjs; } + @Override + public void updateOperationFailed(long snapshotId) throws NoTransitionException { + List snapshotStoreRefs = snapshotStoreDao.findBySnapshotId(snapshotId); + for (SnapshotDataStoreVO snapshotStoreRef : snapshotStoreRefs) { + SnapshotInfo snapshotInfo = getSnapshot(snapshotStoreRef.getSnapshotId(), snapshotStoreRef.getDataStoreId(), snapshotStoreRef.getRole()); + if (snapshotInfo != null) { + VolumeInfo volumeInfo = snapshotInfo.getBaseVolume(); + volumeInfo.stateTransit(Volume.Event.OperationFailed); + ((SnapshotObject)snapshotInfo).processEvent(Snapshot.Event.OperationFailed); + snapshotInfo.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed); + } + } + } } diff --git a/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java b/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java index 09f569e6f19..1801c877893 100644 --- a/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java +++ b/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java @@ -481,4 +481,14 @@ public class DefaultVMSnapshotStrategy extends ManagerBase implements VMSnapshot } return StrategyPriority.DEFAULT; } + + @Override + public void updateOperationFailed(VMSnapshot vmSnapshot) throws NoTransitionException { + try { + vmSnapshotHelper.vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationFailed); + } catch (NoTransitionException e) { + logger.debug("Failed to change vm snapshot state with event OperationFailed"); + throw e; + } + } } diff --git a/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/vmsnapshot/ScaleIOVMSnapshotStrategy.java b/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/vmsnapshot/ScaleIOVMSnapshotStrategy.java index 1ec6e20fc9e..8afbcab9b4b 100644 --- a/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/vmsnapshot/ScaleIOVMSnapshotStrategy.java +++ b/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/vmsnapshot/ScaleIOVMSnapshotStrategy.java @@ -479,6 +479,16 @@ public class ScaleIOVMSnapshotStrategy extends ManagerBase implements VMSnapshot return vmSnapshotDao.remove(vmSnapshot.getId()); } + @Override + public void updateOperationFailed(VMSnapshot vmSnapshot) throws NoTransitionException { + try { + vmSnapshotHelper.vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationFailed); + } catch (NoTransitionException e) { + logger.debug("Failed to change vm snapshot state with event OperationFailed"); + throw e; + } + } + private void publishUsageEvent(String type, VMSnapshot vmSnapshot, UserVm userVm, VolumeObjectTO volumeTo) { VolumeVO volume = volumeDao.findById(volumeTo.getId()); Long diskOfferingId = volume.getDiskOfferingId(); diff --git a/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java b/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java index 47bf27bd6c4..80140b0d950 100644 --- a/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java +++ b/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java @@ -35,6 +35,11 @@ import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.storage.SnapshotVO; +import com.cloud.vm.snapshot.VMSnapshot; +import com.cloud.vm.snapshot.VMSnapshotService; +import com.cloud.vm.snapshot.VMSnapshotVO; +import com.cloud.vm.snapshot.dao.VMSnapshotDao; import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.context.CallContext; @@ -153,11 +158,15 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager, @Inject private SnapshotDao _snapshotDao; @Inject + private VMSnapshotDao _vmSnapshotDao; + @Inject private SnapshotService snapshotSrv; @Inject private SnapshotDataFactory snapshotFactory; @Inject private SnapshotDetailsDao _snapshotDetailsDao; + @Inject + private VMSnapshotService _vmSnapshotService; @Inject private VolumeDataFactory volFactory; @@ -1149,6 +1158,10 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager, return cleanupVirtualMachine(job.getInstanceId()); case Network: return cleanupNetwork(job.getInstanceId()); + case Snapshot: + return cleanupSnapshot(job.getInstanceId()); + case VmSnapshot: + return cleanupVmSnapshot(job.getInstanceId()); } } catch (Exception e) { logger.warn("Error while cleaning up resource: [" + job.getInstanceType().toString() + "] with Id: " + job.getInstanceId(), e); @@ -1187,7 +1200,7 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager, return true; } - private boolean cleanupNetwork(final long networkId) throws Exception { + private boolean cleanupNetwork(final long networkId) { NetworkVO networkVO = networkDao.findById(networkId); if (networkVO == null) { logger.warn("Network not found. Skip Cleanup. NetworkId: " + networkId); @@ -1206,6 +1219,46 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager, return true; } + private boolean cleanupSnapshot(final long snapshotId) { + SnapshotVO snapshotVO = _snapshotDao.findById(snapshotId); + if (snapshotVO == null) { + logger.warn("Snapshot not found. Skip Cleanup. SnapshotId: " + snapshotId); + return true; + } + if (Snapshot.State.Allocated.equals(snapshotVO.getState())) { + _snapshotDao.remove(snapshotId); + } + if (Snapshot.State.Creating.equals(snapshotVO.getState())) { + try { + snapshotFactory.updateOperationFailed(snapshotId); + } catch (NoTransitionException e) { + snapshotVO.setState(Snapshot.State.Error); + _snapshotDao.update(snapshotVO.getId(), snapshotVO); + } + } + return true; + } + + private boolean cleanupVmSnapshot(final long vmSnapshotId) { + VMSnapshotVO vmSnapshotVO = _vmSnapshotDao.findById(vmSnapshotId); + if (vmSnapshotVO == null) { + logger.warn("VM Snapshot not found. Skip Cleanup. VMSnapshotId: " + vmSnapshotId); + return true; + } + if (VMSnapshot.State.Allocated.equals(vmSnapshotVO.getState())) { + _vmSnapshotDao.remove(vmSnapshotId); + } + if (VMSnapshot.State.Creating.equals(vmSnapshotVO.getState())) { + try { + _vmSnapshotService.updateOperationFailed(vmSnapshotVO); + } catch (NoTransitionException e) { + vmSnapshotVO.setState(VMSnapshot.State.Error); + _vmSnapshotDao.update(vmSnapshotVO.getId(), vmSnapshotVO); + } + } + return true; + } + private void cleanupFailedVolumesCreatedFromSnapshots(final long volumeId) { try { VolumeDetailVO volumeDetail = _volumeDetailsDao.findDetail(volumeId, VolumeService.SNAPSHOT_ID); diff --git a/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java b/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java index 907182edc2a..26f7603240f 100644 --- a/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java @@ -28,6 +28,7 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; import com.cloud.storage.snapshot.SnapshotManager; +import com.cloud.utils.fsm.NoTransitionException; import org.apache.cloudstack.annotation.AnnotationService; import org.apache.cloudstack.annotation.dao.AnnotationDao; import org.apache.cloudstack.api.ApiConstants; @@ -1387,6 +1388,12 @@ public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase impleme return true; } + @Override + public void updateOperationFailed(VMSnapshot vmSnapshot) throws NoTransitionException { + VMSnapshotStrategy strategy = findVMSnapshotStrategy(vmSnapshot); + strategy.updateOperationFailed(vmSnapshot); + } + @Override public String getConfigComponentName() { return VMSnapshotManager.class.getSimpleName(); From 1a223fd2bac9ede56f07cb60421566472760a894 Mon Sep 17 00:00:00 2001 From: Nicolas Vazquez Date: Tue, 23 Sep 2025 03:48:18 -0300 Subject: [PATCH 2/5] 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 --- .../main/java/com/cloud/vm/UserVmService.java | 26 ++++++- .../java/com/cloud/vm/UserVmManagerImpl.java | 53 +++++++++------ .../vm/UnmanagedVMsManagerImpl.java | 68 ++++++------------- .../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 customParameters, final VirtualMachine.PowerState powerState, final LinkedHashMap> 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 customParameters, final VirtualMachine.PowerState powerState, final LinkedHashMap> 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) 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 dataDiskOfferingMap, final Map nicNetworkMap, final Map callerNicIpAddressMap, final Map 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 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 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> rootAndDataDisksPair = getRootAndDataDisks(unmanagedInstanceDisks, dataDiskOfferingMap); final UnmanagedInstanceTO.Disk rootDisk = rootAndDataDisksPair.first(); final List 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> 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 nicNetworkMap, Map 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); From a749206eb8e992f8cbc0d82495c7bbc713ff470e Mon Sep 17 00:00:00 2001 From: Suresh Kumar Anaparti Date: Wed, 24 Sep 2025 11:52:49 +0530 Subject: [PATCH 3/5] storage: Mount disabled pools by default when host is booted (#11666) --- .../src/main/java/com/cloud/storage/StorageManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java b/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java index 7b31ec6a81b..529e506e8a0 100644 --- a/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java +++ b/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java @@ -182,7 +182,7 @@ public interface StorageManager extends StorageService { ConfigKey MountDisabledStoragePool = new ConfigKey<>(Boolean.class, "mount.disabled.storage.pool", "Storage", - "false", + Boolean.TRUE.toString(), "Mount all zone-wide or cluster-wide disabled storage pools after node reboot", true, ConfigKey.Scope.Cluster, From a18b5514e67a248f57f6e212822a4a44e0b6195c Mon Sep 17 00:00:00 2001 From: Manoj Kumar Date: Wed, 24 Sep 2025 12:04:18 +0530 Subject: [PATCH 4/5] kvm: honor templateId passed in importVM API (#11640) --- .../apache/cloudstack/vm/UnmanagedVMsManagerImpl.java | 11 ++--------- .../cloudstack/vm/UnmanagedVMsManagerImplTest.java | 4 ---- 2 files changed, 2 insertions(+), 13 deletions(-) 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 981f83936d2..30cf4ad76a7 100644 --- a/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java @@ -1493,7 +1493,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { if (templateId == null) { template = templateDao.findByName(VM_IMPORT_DEFAULT_TEMPLATE_NAME); if (template == null) { - template = createDefaultDummyVmImportTemplate(false); + template = createDefaultDummyVmImportTemplate(Hypervisor.HypervisorType.KVM == hypervisorType); if (template == null) { throw new InvalidParameterValueException(String.format("Default VM import template with unique name: %s for hypervisor: %s cannot be created. Please use templateid parameter for import", VM_IMPORT_DEFAULT_TEMPLATE_NAME, hypervisorType.toString())); } @@ -2331,14 +2331,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { if (CollectionUtils.isNotEmpty(userVOs)) { userId = userVOs.get(0).getId(); } - VMTemplateVO template = templateDao.findByName(KVM_VM_IMPORT_DEFAULT_TEMPLATE_NAME); - if (template == null) { - template = createDefaultDummyVmImportTemplate(true); - if (template == null) { - throw new InvalidParameterValueException("Error while creating default Import Vm Template"); - } - } - + VMTemplateVO template = getTemplateForImportInstance(cmd.getTemplateId(), Hypervisor.HypervisorType.KVM); final Long serviceOfferingId = cmd.getServiceOfferingId(); if (serviceOfferingId == null) { throw new InvalidParameterValueException(String.format("Service offering ID cannot be null")); 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 4aa5df9d411..09f62f7a049 100644 --- a/server/src/test/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImplTest.java +++ b/server/src/test/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImplTest.java @@ -504,8 +504,6 @@ public class UnmanagedVMsManagerImplTest { when(cmd.getPassword()).thenReturn("pass"); when(cmd.getImportSource()).thenReturn("external"); when(cmd.getDomainId()).thenReturn(null); - VMTemplateVO template = Mockito.mock(VMTemplateVO.class); - when(templateDao.findByName(anyString())).thenReturn(template); HostVO host = Mockito.mock(HostVO.class); DeployDestination mockDest = Mockito.mock(DeployDestination.class); when(deploymentPlanningManager.planDeployment(any(), any(), any(), any())).thenReturn(mockDest); @@ -736,8 +734,6 @@ public class UnmanagedVMsManagerImplTest { when(cmd.getImportSource()).thenReturn(source); when(cmd.getDiskPath()).thenReturn("/var/lib/libvirt/images/test.qcow2"); when(cmd.getDomainId()).thenReturn(null); - VMTemplateVO template = Mockito.mock(VMTemplateVO.class); - when(templateDao.findByName(anyString())).thenReturn(template); HostVO host = Mockito.mock(HostVO.class); when(hostDao.findById(anyLong())).thenReturn(host); NetworkOffering netOffering = Mockito.mock(NetworkOffering.class); From 98b9af29040533089a7f8153c74f95f9c324d66b Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Wed, 24 Sep 2025 12:51:40 +0530 Subject: [PATCH 5/5] server: set VirtualMachineTO arch from template if present (#11530) * server: set VirtualMachineTO arch from template if present Fixes #11529 Signed-off-by: Abhishek Kumar * refactor Signed-off-by: Abhishek Kumar --------- Signed-off-by: Abhishek Kumar --- .../com/cloud/hypervisor/HypervisorGuruBase.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java index c510502f5f9..4f14fe20dac 100644 --- a/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java +++ b/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java @@ -23,6 +23,7 @@ import java.util.UUID; import javax.inject.Inject; +import com.cloud.cpu.CPU; import com.cloud.dc.DataCenter; import com.cloud.dc.dao.DataCenterDao; import com.cloud.domain.Domain; @@ -307,10 +308,15 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis to.setNics(nics); to.setDisks(vmProfile.getDisks().toArray(new DiskTO[vmProfile.getDisks().size()])); - if (vmProfile.getTemplate().getBits() == 32) { - to.setArch("i686"); + CPU.CPUArch templateArch = vmProfile.getTemplate().getArch(); + if (templateArch != null) { + to.setArch(templateArch.getType()); } else { - to.setArch("x86_64"); + if (vmProfile.getTemplate().getBits() == 32) { + to.setArch(CPU.CPUArch.x86.getType()); + } else { + to.setArch(CPU.CPUArch.amd64.getType()); + } } Map detailsInVm = _userVmDetailsDao.listDetailsKeyPairs(vm.getId());