mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
server,engine-orchestration: allocate vm without transaction (#7695)
When deploying a VM is failed during the allocation process it may leave the resources that have been already allocated before the failure. They will get removed from the database as the whole code block is wrapped inside a transaction twice but the server would not inform the network or storage plugins to clean up the allocated resources. This PR removes Transactions during VM allocation which results in the allocated VM and its resource records being persisted in DB even during failures. When failure is encountered VM is moved to Error state. This helps VM and its resources to be properly deallocated when it is expunged either by a server task such as ExpungeTask or during manual expunge. Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
This commit is contained in:
parent
c733a23c90
commit
939ee9e153
@ -458,7 +458,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
||||
throws InsufficientCapacityException {
|
||||
|
||||
s_logger.info(String.format("allocating virtual machine from template:%s with hostname:%s and %d networks", template.getUuid(), vmInstanceName, auxiliaryNetworks.size()));
|
||||
|
||||
VMInstanceVO persistedVm = null;
|
||||
try {
|
||||
final VMInstanceVO vm = _vmDao.findVMByInstanceName(vmInstanceName);
|
||||
final Account owner = _entityMgr.findById(Account.class, vm.getAccountId());
|
||||
|
||||
@ -471,9 +472,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
||||
vm.setPodIdToDeployIn(plan.getPodId());
|
||||
}
|
||||
assert plan.getClusterId() == null && plan.getPoolId() == null : "We currently don't support cluster and pool preset yet";
|
||||
final VMInstanceVO vmFinal = _vmDao.persist(vm);
|
||||
persistedVm = _vmDao.persist(vm);
|
||||
|
||||
final VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vmFinal, template, serviceOffering, null, null);
|
||||
final VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(persistedVm, template, serviceOffering, null, null);
|
||||
|
||||
Long rootDiskSize = rootDiskOfferingInfo.getSize();
|
||||
if (vm.getType().isUsedBySystem() && SystemVmRootDiskSize.value() != null && SystemVmRootDiskSize.value() > 0L) {
|
||||
@ -481,11 +482,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
||||
}
|
||||
final Long rootDiskSizeFinal = rootDiskSize;
|
||||
|
||||
Transaction.execute(new TransactionCallbackWithExceptionNoReturn<InsufficientCapacityException>() {
|
||||
@Override
|
||||
public void doInTransactionWithoutResult(final TransactionStatus status) throws InsufficientCapacityException {
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Allocating nics for " + vmFinal);
|
||||
s_logger.debug("Allocating nics for " + persistedVm);
|
||||
}
|
||||
|
||||
try {
|
||||
@ -497,15 +495,15 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
||||
}
|
||||
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Allocating disks for " + vmFinal);
|
||||
s_logger.debug("Allocating disks for " + persistedVm);
|
||||
}
|
||||
|
||||
allocateRootVolume(vmFinal, template, rootDiskOfferingInfo, owner, rootDiskSizeFinal);
|
||||
allocateRootVolume(persistedVm, template, rootDiskOfferingInfo, owner, rootDiskSizeFinal);
|
||||
|
||||
if (dataDiskOfferings != null) {
|
||||
for (final DiskOfferingInfo dataDiskOfferingInfo : dataDiskOfferings) {
|
||||
volumeMgr.allocateRawVolume(Type.DATADISK, "DATA-" + vmFinal.getId(), dataDiskOfferingInfo.getDiskOffering(), dataDiskOfferingInfo.getSize(),
|
||||
dataDiskOfferingInfo.getMinIops(), dataDiskOfferingInfo.getMaxIops(), vmFinal, template, owner, null);
|
||||
volumeMgr.allocateRawVolume(Type.DATADISK, "DATA-" + persistedVm.getId(), dataDiskOfferingInfo.getDiskOffering(), dataDiskOfferingInfo.getSize(),
|
||||
dataDiskOfferingInfo.getMinIops(), dataDiskOfferingInfo.getMaxIops(), persistedVm, template, owner, null);
|
||||
}
|
||||
}
|
||||
if (datadiskTemplateToDiskOfferingMap != null && !datadiskTemplateToDiskOfferingMap.isEmpty()) {
|
||||
@ -514,16 +512,25 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
||||
DiskOffering diskOffering = dataDiskTemplateToDiskOfferingMap.getValue();
|
||||
long diskOfferingSize = diskOffering.getDiskSize() / (1024 * 1024 * 1024);
|
||||
VMTemplateVO dataDiskTemplate = _templateDao.findById(dataDiskTemplateToDiskOfferingMap.getKey());
|
||||
volumeMgr.allocateRawVolume(Type.DATADISK, "DATA-" + vmFinal.getId() + "-" + String.valueOf(diskNumber), diskOffering, diskOfferingSize, null, null,
|
||||
vmFinal, dataDiskTemplate, owner, Long.valueOf(diskNumber));
|
||||
volumeMgr.allocateRawVolume(Type.DATADISK, "DATA-" + persistedVm.getId() + "-" + String.valueOf(diskNumber), diskOffering, diskOfferingSize, null, null,
|
||||
persistedVm, dataDiskTemplate, owner, Long.valueOf(diskNumber));
|
||||
diskNumber++;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Allocation completed for VM: " + vmFinal);
|
||||
s_logger.debug("Allocation completed for VM: " + persistedVm);
|
||||
}
|
||||
} catch (InsufficientCapacityException | CloudRuntimeException e) {
|
||||
// Failed VM will be in Stopped. Transition it to Error, so it can be expunged by ExpungeTask or similar
|
||||
try {
|
||||
if (persistedVm != null) {
|
||||
stateTransitTo(persistedVm, VirtualMachine.Event.OperationFailedToError, null);
|
||||
}
|
||||
} catch (NoTransitionException nte) {
|
||||
s_logger.error(String.format("Failed to transition %s in %s state to Error state", persistedVm, persistedVm.getState().toString()));
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -348,7 +348,6 @@ import com.cloud.utils.db.GlobalLock;
|
||||
import com.cloud.utils.db.SearchCriteria;
|
||||
import com.cloud.utils.db.Transaction;
|
||||
import com.cloud.utils.db.TransactionCallbackNoReturn;
|
||||
import com.cloud.utils.db.TransactionCallbackWithException;
|
||||
import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn;
|
||||
import com.cloud.utils.db.TransactionStatus;
|
||||
import com.cloud.utils.db.UUIDManager;
|
||||
@ -4366,9 +4365,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
final long id, final String instanceName, final String uuidName, final HypervisorType hypervisorType, final Map<String, String> customParameters,
|
||||
final Map<String, Map<Integer, String>> extraDhcpOptionMap, final Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
||||
final Map<String, String> userVmOVFPropertiesMap, final VirtualMachine.PowerState powerState, final boolean dynamicScalingEnabled, String vmType, final Long rootDiskOfferingId, String sshkeypairs) throws InsufficientCapacityException {
|
||||
return Transaction.execute(new TransactionCallbackWithException<UserVmVO, InsufficientCapacityException>() {
|
||||
@Override
|
||||
public UserVmVO doInTransaction(TransactionStatus status) throws InsufficientCapacityException {
|
||||
UserVmVO vm = new UserVmVO(id, instanceName, displayName, template.getId(), hypervisorType, template.getGuestOSId(), offering.isOfferHA(),
|
||||
offering.getLimitCpuUse(), owner.getDomainId(), owner.getId(), userId, offering.getId(), userData, userDataId, userDataDetails, hostName);
|
||||
vm.setUuid(uuidName);
|
||||
@ -4520,8 +4516,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
}
|
||||
return vm;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateVMDiskController(UserVmVO vm, Map<String, String> customParameters, GuestOSVO guestOS) {
|
||||
// If hypervisor is vSphere and OS is OS X, set special settings.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user