mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
CLOUDSTACK-9738: [Vmware] Optimize vm expunge process for instances with vm snapshots
This commit is contained in:
parent
8e069ed132
commit
6ce6cf67f0
@ -75,14 +75,14 @@ public interface UserVmService {
|
||||
/**
|
||||
* Destroys one virtual machine
|
||||
*
|
||||
* @param userId
|
||||
* the id of the user performing the action
|
||||
* @param vmId
|
||||
* the id of the virtual machine.
|
||||
* @param expunge
|
||||
* indicates if vm should be expunged
|
||||
* @throws ConcurrentOperationException
|
||||
* @throws ResourceUnavailableException
|
||||
*/
|
||||
UserVm destroyVm(long vmId) throws ResourceUnavailableException, ConcurrentOperationException;
|
||||
UserVm destroyVm(long vmId, boolean expunge) throws ResourceUnavailableException, ConcurrentOperationException;
|
||||
|
||||
/**
|
||||
* Resets the password of a virtual machine.
|
||||
|
||||
@ -46,4 +46,11 @@ public interface VMSnapshotService {
|
||||
ConcurrentOperationException;
|
||||
|
||||
VirtualMachine getVMBySnapshotId(Long id);
|
||||
|
||||
/**
|
||||
* Delete vm snapshots only from database. Introduced as a Vmware optimization in which vm snapshots are deleted when
|
||||
* the vm gets deleted on hypervisor (no need to delete each vm snapshot before deleting vm, just mark them as deleted on DB)
|
||||
* @param id vm id
|
||||
*/
|
||||
boolean deleteVMSnapshotsFromDB(Long vmId);
|
||||
}
|
||||
|
||||
@ -110,7 +110,7 @@ public interface VirtualMachineManager extends Manager {
|
||||
|
||||
void advanceExpunge(String vmUuid) throws ResourceUnavailableException, OperationTimedoutException, ConcurrentOperationException;
|
||||
|
||||
void destroy(String vmUuid) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException;
|
||||
void destroy(String vmUuid, boolean expunge) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException;
|
||||
|
||||
void migrateAway(String vmUuid, long hostId) throws InsufficientServerCapacityException;
|
||||
|
||||
|
||||
@ -129,8 +129,9 @@ public interface VirtualMachineEntity extends CloudStackEntity {
|
||||
|
||||
/**
|
||||
* Destroys the VM.
|
||||
* @param expunge indicates if vm should be expunged
|
||||
*/
|
||||
boolean destroy(String caller) throws AgentUnavailableException, CloudException, ConcurrentOperationException;
|
||||
boolean destroy(String caller, boolean expunge) throws AgentUnavailableException, CloudException, ConcurrentOperationException;
|
||||
|
||||
/**
|
||||
* Duplicate this VM in the database so that it will start new
|
||||
|
||||
@ -28,4 +28,12 @@ public interface VMSnapshotStrategy {
|
||||
boolean revertVMSnapshot(VMSnapshot vmSnapshot);
|
||||
|
||||
StrategyPriority canHandle(VMSnapshot vmSnapshot);
|
||||
|
||||
/**
|
||||
* Delete vm snapshot only from database. Introduced as a Vmware optimization in which vm snapshots are deleted when
|
||||
* the vm gets deleted on hypervisor (no need to delete each vm snapshot before deleting vm, just mark them as deleted on DB)
|
||||
* @param vmSnapshot vm snapshot to be marked as deleted.
|
||||
* @return true if vm snapshot removed from DB, false if not.
|
||||
*/
|
||||
boolean deleteVMSnapshotFromDB(VMSnapshot vmSnapshot);
|
||||
}
|
||||
|
||||
30
engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
Normal file → Executable file
30
engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
Normal file → Executable file
@ -1679,7 +1679,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy(final String vmUuid) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException {
|
||||
public void destroy(final String vmUuid, final boolean expunge) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException {
|
||||
VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
|
||||
if (vm == null || vm.getState() == State.Destroyed || vm.getState() == State.Expunging || vm.getRemoved() != null) {
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
@ -1689,15 +1689,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
||||
}
|
||||
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Destroying vm " + vm);
|
||||
s_logger.debug("Destroying vm " + vm + ", expunge flag " + (expunge ? "on" : "off"));
|
||||
}
|
||||
|
||||
advanceStop(vmUuid, VmDestroyForcestop.value());
|
||||
|
||||
if (!_vmSnapshotMgr.deleteAllVMSnapshots(vm.getId(), null)) {
|
||||
s_logger.debug("Unable to delete all snapshots for " + vm);
|
||||
throw new CloudRuntimeException("Unable to delete vm snapshots for " + vm);
|
||||
}
|
||||
deleteVMSnapshots(vm, expunge);
|
||||
|
||||
// reload the vm object from db
|
||||
vm = _vmDao.findByUuid(vmUuid);
|
||||
@ -1712,6 +1709,27 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete vm snapshots depending on vm's hypervisor type. For Vmware, vm snapshots removal is delegated to vm cleanup thread
|
||||
* to reduce tasks sent to hypervisor (one tasks to delete vm snapshots and vm itself
|
||||
* instead of one task for each vm snapshot plus another for the vm)
|
||||
* @param vm vm
|
||||
* @param expunge indicates if vm should be expunged
|
||||
*/
|
||||
private void deleteVMSnapshots(VMInstanceVO vm, boolean expunge) {
|
||||
if (! vm.getHypervisorType().equals(HypervisorType.VMware)) {
|
||||
if (!_vmSnapshotMgr.deleteAllVMSnapshots(vm.getId(), null)) {
|
||||
s_logger.debug("Unable to delete all snapshots for " + vm);
|
||||
throw new CloudRuntimeException("Unable to delete vm snapshots for " + vm);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (expunge) {
|
||||
_vmSnapshotMgr.deleteVMSnapshotsFromDB(vm.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean checkVmOnHost(final VirtualMachine vm, final long hostId) throws AgentUnavailableException, OperationTimedoutException {
|
||||
final Answer answer = _agentMgr.send(hostId, new CheckVirtualMachineCommand(vm.getInstanceName()));
|
||||
if (answer == null || !answer.getResult()) {
|
||||
|
||||
@ -46,5 +46,5 @@ public interface VMEntityManager {
|
||||
|
||||
boolean stopvirtualmachineforced(VMEntityVO vmEntityVO, String caller) throws ResourceUnavailableException;
|
||||
|
||||
boolean destroyVirtualMachine(VMEntityVO vmEntityVO, String caller) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException;
|
||||
boolean destroyVirtualMachine(VMEntityVO vmEntityVO, String caller, boolean expunge) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException;
|
||||
}
|
||||
|
||||
@ -261,10 +261,10 @@ public class VMEntityManagerImpl implements VMEntityManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean destroyVirtualMachine(VMEntityVO vmEntityVO, String caller) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException {
|
||||
public boolean destroyVirtualMachine(VMEntityVO vmEntityVO, String caller, boolean expunge) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException {
|
||||
|
||||
VMInstanceVO vm = _vmDao.findByUuid(vmEntityVO.getUuid());
|
||||
_itMgr.destroy(vm.getUuid());
|
||||
_itMgr.destroy(vm.getUuid(), expunge);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -229,8 +229,8 @@ public class VirtualMachineEntityImpl implements VirtualMachineEntity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean destroy(String caller) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException {
|
||||
return manager.destroyVirtualMachine(this.vmEntityVO, caller);
|
||||
public boolean destroy(String caller, boolean expunge) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException {
|
||||
return manager.destroyVirtualMachine(this.vmEntityVO, caller, expunge);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -392,4 +392,15 @@ public class DefaultVMSnapshotStrategy extends ManagerBase implements VMSnapshot
|
||||
public StrategyPriority canHandle(VMSnapshot vmSnapshot) {
|
||||
return StrategyPriority.DEFAULT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteVMSnapshotFromDB(VMSnapshot vmSnapshot) {
|
||||
try {
|
||||
vmSnapshotHelper.vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.ExpungeRequested);
|
||||
} catch (NoTransitionException e) {
|
||||
s_logger.debug("Failed to change vm snapshot state with event ExpungeRequested");
|
||||
throw new CloudRuntimeException("Failed to change vm snapshot state with event ExpungeRequested: " + e.getMessage());
|
||||
}
|
||||
return vmSnapshotDao.remove(vmSnapshot.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1679,9 +1679,6 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
||||
s_logger.info("Destroy root volume and VM itself. vmName " + vmName);
|
||||
}
|
||||
|
||||
// Remove all snapshots to consolidate disks for removal
|
||||
vmMo.removeAllSnapshots();
|
||||
|
||||
VirtualMachineDiskInfo diskInfo = null;
|
||||
if (vol.getChainInfo() != null)
|
||||
diskInfo = _gson.fromJson(vol.getChainInfo(), VirtualMachineDiskInfo.class);
|
||||
|
||||
@ -674,7 +674,7 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements HighAvai
|
||||
}
|
||||
|
||||
if (vm.getHostId() != null) {
|
||||
_itMgr.destroy(vm.getUuid());
|
||||
_itMgr.destroy(vm.getUuid(), false);
|
||||
s_logger.info("Successfully destroy " + vm);
|
||||
return null;
|
||||
} else {
|
||||
|
||||
@ -1514,7 +1514,7 @@ public class AutoScaleManagerImpl<Type> extends ManagerBase implements AutoScale
|
||||
public void run() {
|
||||
try {
|
||||
|
||||
_userVmManager.destroyVm(vmId);
|
||||
_userVmManager.destroyVm(vmId, false);
|
||||
|
||||
} catch (ResourceUnavailableException e) {
|
||||
e.printStackTrace();
|
||||
|
||||
@ -2165,7 +2165,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
|
||||
final List<VMInstanceVO> vmsOnLocalStorage = _storageMgr.listByStoragePool(storagePool.getId());
|
||||
for (final VMInstanceVO vm : vmsOnLocalStorage) {
|
||||
try {
|
||||
_vmMgr.destroy(vm.getUuid());
|
||||
_vmMgr.destroy(vm.getUuid(), false);
|
||||
} catch (final Exception e) {
|
||||
final String errorMsg = "There was an error Destory the vm: " + vm + " as a part of hostDelete id=" + host.getId();
|
||||
s_logger.debug(errorMsg, e);
|
||||
|
||||
@ -759,7 +759,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
|
||||
for (UserVmVO vm : vms) {
|
||||
if (vm.getState() != VirtualMachine.State.Destroyed && vm.getState() != VirtualMachine.State.Expunging) {
|
||||
try {
|
||||
_vmMgr.destroyVm(vm.getId());
|
||||
_vmMgr.destroyVm(vm.getId(), false);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
s_logger.warn("Failed destroying instance " + vm.getUuid() + " as part of account deletion.");
|
||||
|
||||
8
server/src/com/cloud/vm/UserVmManagerImpl.java
Normal file → Executable file
8
server/src/com/cloud/vm/UserVmManagerImpl.java
Normal file → Executable file
@ -2627,7 +2627,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
throw new PermissionDeniedException("Parameter " + ApiConstants.EXPUNGE + " can be passed by Admin only. Or when the allow.user.expunge.recover.vm key is set.");
|
||||
}
|
||||
|
||||
UserVm destroyedVm = destroyVm(vmId);
|
||||
UserVm destroyedVm = destroyVm(vmId, expunge);
|
||||
if (expunge) {
|
||||
UserVmVO vm = _vmDao.findById(vmId);
|
||||
if (!expunge(vm, ctx.getCallingUserId(), ctx.getCallingAccount())) {
|
||||
@ -4114,7 +4114,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserVm destroyVm(long vmId) throws ResourceUnavailableException, ConcurrentOperationException {
|
||||
public UserVm destroyVm(long vmId, boolean expunge) throws ResourceUnavailableException, ConcurrentOperationException {
|
||||
// Account caller = CallContext.current().getCallingAccount();
|
||||
// Long userId = CallContext.current().getCallingUserId();
|
||||
Long userId = 2L;
|
||||
@ -4136,7 +4136,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
|
||||
try {
|
||||
VirtualMachineEntity vmEntity = _orchSrvc.getVirtualMachine(vm.getUuid());
|
||||
status = vmEntity.destroy(Long.toString(userId));
|
||||
status = vmEntity.destroy(Long.toString(userId), expunge);
|
||||
} catch (CloudException e) {
|
||||
CloudRuntimeException ex = new CloudRuntimeException("Unable to destroy with specified vmId", e);
|
||||
ex.addProxyObject(vm.getUuid(), "vmId");
|
||||
@ -4318,6 +4318,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
throw new PermissionDeniedException("Expunging a vm can only be done by an Admin. Or when the allow.user.expunge.recover.vm key is set.");
|
||||
}
|
||||
|
||||
_vmSnapshotMgr.deleteVMSnapshotsFromDB(vmId);
|
||||
|
||||
boolean status;
|
||||
|
||||
status = expunge(vm, userId, caller);
|
||||
|
||||
@ -1133,4 +1133,25 @@ public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase impleme
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteVMSnapshotsFromDB(Long vmId) {
|
||||
List<VMSnapshotVO> listVmSnapshots = _vmSnapshotDao.findByVm(vmId);
|
||||
if (listVmSnapshots == null || listVmSnapshots.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
for (VMSnapshotVO snapshot : listVmSnapshots) {
|
||||
try {
|
||||
VMSnapshotStrategy strategy = findVMSnapshotStrategy(snapshot);
|
||||
if (! strategy.deleteVMSnapshotFromDB(snapshot)) {
|
||||
s_logger.error("Couldn't delete vm snapshot with id " + snapshot.getId());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (CloudRuntimeException e) {
|
||||
s_logger.error("Couldn't delete vm snapshot due to: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.anyLong;
|
||||
import static org.mockito.Mockito.anyString;
|
||||
import static org.mockito.Mockito.anyBoolean;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
@ -118,7 +119,7 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
|
||||
VirtualMachineEntity vmEntity = mock(VirtualMachineEntity.class);
|
||||
|
||||
when(_orchSrvc.getVirtualMachine(anyString())).thenReturn(vmEntity);
|
||||
when(vmEntity.destroy(anyString())).thenReturn(true);
|
||||
when(vmEntity.destroy(anyString(), anyBoolean())).thenReturn(true);
|
||||
|
||||
Mockito.doReturn(vm).when(_vmDao).findById(anyLong());
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user