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
|
* Destroys one virtual machine
|
||||||
*
|
*
|
||||||
* @param userId
|
|
||||||
* the id of the user performing the action
|
|
||||||
* @param vmId
|
* @param vmId
|
||||||
* the id of the virtual machine.
|
* the id of the virtual machine.
|
||||||
|
* @param expunge
|
||||||
|
* indicates if vm should be expunged
|
||||||
* @throws ConcurrentOperationException
|
* @throws ConcurrentOperationException
|
||||||
* @throws ResourceUnavailableException
|
* @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.
|
* Resets the password of a virtual machine.
|
||||||
|
|||||||
@ -46,4 +46,11 @@ public interface VMSnapshotService {
|
|||||||
ConcurrentOperationException;
|
ConcurrentOperationException;
|
||||||
|
|
||||||
VirtualMachine getVMBySnapshotId(Long id);
|
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 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;
|
void migrateAway(String vmUuid, long hostId) throws InsufficientServerCapacityException;
|
||||||
|
|
||||||
|
|||||||
@ -129,8 +129,9 @@ public interface VirtualMachineEntity extends CloudStackEntity {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroys the VM.
|
* 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
|
* Duplicate this VM in the database so that it will start new
|
||||||
|
|||||||
@ -28,4 +28,12 @@ public interface VMSnapshotStrategy {
|
|||||||
boolean revertVMSnapshot(VMSnapshot vmSnapshot);
|
boolean revertVMSnapshot(VMSnapshot vmSnapshot);
|
||||||
|
|
||||||
StrategyPriority canHandle(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
|
@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);
|
VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
|
||||||
if (vm == null || vm.getState() == State.Destroyed || vm.getState() == State.Expunging || vm.getRemoved() != null) {
|
if (vm == null || vm.getState() == State.Destroyed || vm.getState() == State.Expunging || vm.getRemoved() != null) {
|
||||||
if (s_logger.isDebugEnabled()) {
|
if (s_logger.isDebugEnabled()) {
|
||||||
@ -1689,15 +1689,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (s_logger.isDebugEnabled()) {
|
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());
|
advanceStop(vmUuid, VmDestroyForcestop.value());
|
||||||
|
|
||||||
if (!_vmSnapshotMgr.deleteAllVMSnapshots(vm.getId(), null)) {
|
deleteVMSnapshots(vm, expunge);
|
||||||
s_logger.debug("Unable to delete all snapshots for " + vm);
|
|
||||||
throw new CloudRuntimeException("Unable to delete vm snapshots for " + vm);
|
|
||||||
}
|
|
||||||
|
|
||||||
// reload the vm object from db
|
// reload the vm object from db
|
||||||
vm = _vmDao.findByUuid(vmUuid);
|
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 {
|
protected boolean checkVmOnHost(final VirtualMachine vm, final long hostId) throws AgentUnavailableException, OperationTimedoutException {
|
||||||
final Answer answer = _agentMgr.send(hostId, new CheckVirtualMachineCommand(vm.getInstanceName()));
|
final Answer answer = _agentMgr.send(hostId, new CheckVirtualMachineCommand(vm.getInstanceName()));
|
||||||
if (answer == null || !answer.getResult()) {
|
if (answer == null || !answer.getResult()) {
|
||||||
|
|||||||
@ -46,5 +46,5 @@ public interface VMEntityManager {
|
|||||||
|
|
||||||
boolean stopvirtualmachineforced(VMEntityVO vmEntityVO, String caller) throws ResourceUnavailableException;
|
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
|
@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());
|
VMInstanceVO vm = _vmDao.findByUuid(vmEntityVO.getUuid());
|
||||||
_itMgr.destroy(vm.getUuid());
|
_itMgr.destroy(vm.getUuid(), expunge);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -229,8 +229,8 @@ public class VirtualMachineEntityImpl implements VirtualMachineEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean destroy(String caller) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException {
|
public boolean destroy(String caller, boolean expunge) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException {
|
||||||
return manager.destroyVirtualMachine(this.vmEntityVO, caller);
|
return manager.destroyVirtualMachine(this.vmEntityVO, caller, expunge);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -392,4 +392,15 @@ public class DefaultVMSnapshotStrategy extends ManagerBase implements VMSnapshot
|
|||||||
public StrategyPriority canHandle(VMSnapshot vmSnapshot) {
|
public StrategyPriority canHandle(VMSnapshot vmSnapshot) {
|
||||||
return StrategyPriority.DEFAULT;
|
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);
|
s_logger.info("Destroy root volume and VM itself. vmName " + vmName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all snapshots to consolidate disks for removal
|
|
||||||
vmMo.removeAllSnapshots();
|
|
||||||
|
|
||||||
VirtualMachineDiskInfo diskInfo = null;
|
VirtualMachineDiskInfo diskInfo = null;
|
||||||
if (vol.getChainInfo() != null)
|
if (vol.getChainInfo() != null)
|
||||||
diskInfo = _gson.fromJson(vol.getChainInfo(), VirtualMachineDiskInfo.class);
|
diskInfo = _gson.fromJson(vol.getChainInfo(), VirtualMachineDiskInfo.class);
|
||||||
|
|||||||
@ -674,7 +674,7 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements HighAvai
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (vm.getHostId() != null) {
|
if (vm.getHostId() != null) {
|
||||||
_itMgr.destroy(vm.getUuid());
|
_itMgr.destroy(vm.getUuid(), false);
|
||||||
s_logger.info("Successfully destroy " + vm);
|
s_logger.info("Successfully destroy " + vm);
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -1514,7 +1514,7 @@ public class AutoScaleManagerImpl<Type> extends ManagerBase implements AutoScale
|
|||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
_userVmManager.destroyVm(vmId);
|
_userVmManager.destroyVm(vmId, false);
|
||||||
|
|
||||||
} catch (ResourceUnavailableException e) {
|
} catch (ResourceUnavailableException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|||||||
@ -2165,7 +2165,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
|
|||||||
final List<VMInstanceVO> vmsOnLocalStorage = _storageMgr.listByStoragePool(storagePool.getId());
|
final List<VMInstanceVO> vmsOnLocalStorage = _storageMgr.listByStoragePool(storagePool.getId());
|
||||||
for (final VMInstanceVO vm : vmsOnLocalStorage) {
|
for (final VMInstanceVO vm : vmsOnLocalStorage) {
|
||||||
try {
|
try {
|
||||||
_vmMgr.destroy(vm.getUuid());
|
_vmMgr.destroy(vm.getUuid(), false);
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
final String errorMsg = "There was an error Destory the vm: " + vm + " as a part of hostDelete id=" + host.getId();
|
final String errorMsg = "There was an error Destory the vm: " + vm + " as a part of hostDelete id=" + host.getId();
|
||||||
s_logger.debug(errorMsg, e);
|
s_logger.debug(errorMsg, e);
|
||||||
|
|||||||
@ -759,7 +759,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
|
|||||||
for (UserVmVO vm : vms) {
|
for (UserVmVO vm : vms) {
|
||||||
if (vm.getState() != VirtualMachine.State.Destroyed && vm.getState() != VirtualMachine.State.Expunging) {
|
if (vm.getState() != VirtualMachine.State.Destroyed && vm.getState() != VirtualMachine.State.Expunging) {
|
||||||
try {
|
try {
|
||||||
_vmMgr.destroyVm(vm.getId());
|
_vmMgr.destroyVm(vm.getId(), false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
s_logger.warn("Failed destroying instance " + vm.getUuid() + " as part of account deletion.");
|
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.");
|
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) {
|
if (expunge) {
|
||||||
UserVmVO vm = _vmDao.findById(vmId);
|
UserVmVO vm = _vmDao.findById(vmId);
|
||||||
if (!expunge(vm, ctx.getCallingUserId(), ctx.getCallingAccount())) {
|
if (!expunge(vm, ctx.getCallingUserId(), ctx.getCallingAccount())) {
|
||||||
@ -4114,7 +4114,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserVm destroyVm(long vmId) throws ResourceUnavailableException, ConcurrentOperationException {
|
public UserVm destroyVm(long vmId, boolean expunge) throws ResourceUnavailableException, ConcurrentOperationException {
|
||||||
// Account caller = CallContext.current().getCallingAccount();
|
// Account caller = CallContext.current().getCallingAccount();
|
||||||
// Long userId = CallContext.current().getCallingUserId();
|
// Long userId = CallContext.current().getCallingUserId();
|
||||||
Long userId = 2L;
|
Long userId = 2L;
|
||||||
@ -4136,7 +4136,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
VirtualMachineEntity vmEntity = _orchSrvc.getVirtualMachine(vm.getUuid());
|
VirtualMachineEntity vmEntity = _orchSrvc.getVirtualMachine(vm.getUuid());
|
||||||
status = vmEntity.destroy(Long.toString(userId));
|
status = vmEntity.destroy(Long.toString(userId), expunge);
|
||||||
} catch (CloudException e) {
|
} catch (CloudException e) {
|
||||||
CloudRuntimeException ex = new CloudRuntimeException("Unable to destroy with specified vmId", e);
|
CloudRuntimeException ex = new CloudRuntimeException("Unable to destroy with specified vmId", e);
|
||||||
ex.addProxyObject(vm.getUuid(), "vmId");
|
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.");
|
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;
|
boolean status;
|
||||||
|
|
||||||
status = expunge(vm, userId, caller);
|
status = expunge(vm, userId, caller);
|
||||||
|
|||||||
@ -1133,4 +1133,25 @@ public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase impleme
|
|||||||
}
|
}
|
||||||
return result;
|
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.any;
|
||||||
import static org.mockito.Mockito.anyLong;
|
import static org.mockito.Mockito.anyLong;
|
||||||
import static org.mockito.Mockito.anyString;
|
import static org.mockito.Mockito.anyString;
|
||||||
|
import static org.mockito.Mockito.anyBoolean;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
@ -118,7 +119,7 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
|
|||||||
VirtualMachineEntity vmEntity = mock(VirtualMachineEntity.class);
|
VirtualMachineEntity vmEntity = mock(VirtualMachineEntity.class);
|
||||||
|
|
||||||
when(_orchSrvc.getVirtualMachine(anyString())).thenReturn(vmEntity);
|
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());
|
Mockito.doReturn(vm).when(_vmDao).findById(anyLong());
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user