Skip to content

Commit 7c61d8a

Browse files
JoaoJandreJoão Jandre
andauthored
Set root volume as destroyed when destroying a VM (#6868)
* Set root volume as destroyed when destroying a VM * Address review * Address review Co-authored-by: João Jandre <joao@scclouds.com.br>
1 parent a63b2ab commit 7c61d8a

File tree

6 files changed

+71
-3
lines changed

6 files changed

+71
-3
lines changed

engine/schema/src/main/java/com/cloud/storage/dao/VolumeDao.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,4 +146,5 @@ public interface VolumeDao extends GenericDao<VolumeVO, Long>, StateDao<Volume.S
146146
* @return the list of volumes that uses that disk offering.
147147
*/
148148
List<VolumeVO> findByDiskOfferingId(long diskOfferingId);
149+
VolumeVO getInstanceRootVolume(long instanceId);
149150
}

engine/schema/src/main/java/com/cloud/storage/dao/VolumeDaoImpl.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,4 +759,11 @@ public void updateDiskOffering(long volumeId, long diskOfferingId) {
759759
throw new CloudRuntimeException(e);
760760
}
761761
}
762+
@Override
763+
public VolumeVO getInstanceRootVolume(long instanceId) {
764+
SearchCriteria<VolumeVO> sc = RootDiskStateSearch.create();
765+
sc.setParameters("instanceId", instanceId);
766+
sc.setParameters("vType", Volume.Type.ROOT);
767+
return findOneBy(sc);
768+
}
762769
}

server/src/main/java/com/cloud/storage/StorageManagerImpl.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import javax.inject.Inject;
4747

4848
import com.google.common.collect.Sets;
49+
import com.cloud.vm.UserVmManager;
4950
import org.apache.cloudstack.annotation.AnnotationService;
5051
import org.apache.cloudstack.annotation.dao.AnnotationDao;
5152
import org.apache.cloudstack.api.ApiConstants;
@@ -344,6 +345,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
344345
@Inject
345346
private AnnotationDao annotationDao;
346347

348+
@Inject
349+
protected UserVmManager userVmManager;
347350
protected List<StoragePoolDiscoverer> _discoverers;
348351

349352
public List<StoragePoolDiscoverer> getDiscoverers() {
@@ -1325,6 +1328,15 @@ public void cleanupStorage(boolean recurring) {
13251328

13261329
List<VolumeVO> vols = _volsDao.listVolumesToBeDestroyed(new Date(System.currentTimeMillis() - ((long)StorageCleanupDelay.value() << 10)));
13271330
for (VolumeVO vol : vols) {
1331+
if (Type.ROOT.equals(vol.getVolumeType())) {
1332+
VMInstanceVO vmInstanceVO = _vmInstanceDao.findById(vol.getInstanceId());
1333+
if (vmInstanceVO != null && vmInstanceVO.getState() == State.Destroyed) {
1334+
s_logger.debug(String.format("ROOT volume [%s] will not be expunged because the VM is [%s], therefore this volume will be expunged with the VM"
1335+
+ " cleanup job.", vol.getUuid(), vmInstanceVO.getState()));
1336+
continue;
1337+
}
1338+
}
1339+
13281340
try {
13291341
// If this fails, just log a warning. It's ideal if we clean up the host-side clustered file
13301342
// system, but not necessary.

server/src/main/java/com/cloud/vm/UserVmManager.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ public interface UserVmManager extends UserVmService {
5757
ConfigKey<Boolean> DisplayVMOVFProperties = new ConfigKey<Boolean>("Advanced", Boolean.class, "vm.display.ovf.properties", "false",
5858
"Set display of VMs OVF properties as part of VM details", true);
5959

60+
ConfigKey<Boolean> DestroyRootVolumeOnVmDestruction = new ConfigKey<Boolean>("Advanced", Boolean.class, "destroy.root.volume.on.vm.destruction", "false",
61+
"Destroys the VM's root volume when the VM is destroyed.",
62+
true, ConfigKey.Scope.Domain);
63+
6064
static final int MAX_USER_DATA_LENGTH_BYTES = 2048;
6165

6266
public static final String CKS_NODE = "cksnode";
@@ -136,4 +140,6 @@ UserVm updateVirtualMachine(long id, String displayName, String group, Boolean h
136140

137141
boolean checkIfDynamicScalingCanBeEnabled(VirtualMachine vm, ServiceOffering offering, VirtualMachineTemplate template, Long zoneId);
138142

143+
Boolean getDestroyRootVolumeOnVmDestruction(Long domainId);
144+
139145
}

server/src/main/java/com/cloud/vm/UserVmManagerImpl.java

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
596596
private int _scaleRetry;
597597
private Map<Long, VmAndCountDetails> vmIdCountMap = new ConcurrentHashMap<>();
598598

599+
protected static long ROOT_DEVICE_ID = 0;
600+
599601
private static final int MAX_HTTP_GET_LENGTH = 2 * MAX_USER_DATA_LENGTH_BYTES;
600602
private static final int NUM_OF_2K_BLOCKS = 512;
601603
private static final int MAX_HTTP_POST_LENGTH = NUM_OF_2K_BLOCKS * MAX_USER_DATA_LENGTH_BYTES;
@@ -2333,8 +2335,8 @@ public UserVm recoverVirtualMachine(RecoverVMCmd cmd) throws ResourceAllocationE
23332335
List<VolumeVO> volumes = _volsDao.findByInstance(vmId);
23342336
for (VolumeVO volume : volumes) {
23352337
if (volume.getVolumeType().equals(Volume.Type.ROOT)) {
2336-
// Create an event
2337-
_volumeService.publishVolumeCreationUsageEvent(volume);
2338+
recoverRootVolume(volume, vmId);
2339+
break;
23382340
}
23392341
}
23402342

@@ -2346,6 +2348,15 @@ public UserVm recoverVirtualMachine(RecoverVMCmd cmd) throws ResourceAllocationE
23462348
return _vmDao.findById(vmId);
23472349
}
23482350

2351+
protected void recoverRootVolume(VolumeVO volume, Long vmId) {
2352+
if (Volume.State.Destroy.equals(volume.getState())) {
2353+
_volumeService.recoverVolume(volume.getId());
2354+
_volsDao.attachVolume(volume.getId(), vmId, ROOT_DEVICE_ID);
2355+
} else {
2356+
_volumeService.publishVolumeCreationUsageEvent(volume);
2357+
}
2358+
}
2359+
23492360
@Override
23502361
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
23512362
_name = name;
@@ -3330,6 +3341,15 @@ public UserVm destroyVm(DestroyVMCmd cmd) throws ResourceUnavailableException, C
33303341

33313342
deleteVolumesFromVm(volumesToBeDeleted, expunge);
33323343

3344+
if (getDestroyRootVolumeOnVmDestruction(vm.getDomainId())) {
3345+
VolumeVO rootVolume = _volsDao.getInstanceRootVolume(vm.getId());
3346+
if (rootVolume != null) {
3347+
_volService.destroyVolume(rootVolume.getId());
3348+
} else {
3349+
s_logger.warn(String.format("Tried to destroy ROOT volume for VM [%s], but couldn't retrieve it.", vm.getUuid()));
3350+
}
3351+
}
3352+
33333353
return destroyedVm;
33343354
}
33353355

@@ -8004,7 +8024,7 @@ public String getConfigComponentName() {
80048024
public ConfigKey<?>[] getConfigKeys() {
80058025
return new ConfigKey<?>[] {EnableDynamicallyScaleVm, AllowDiskOfferingChangeDuringScaleVm, AllowUserExpungeRecoverVm, VmIpFetchWaitInterval, VmIpFetchTrialMax,
80068026
VmIpFetchThreadPoolMax, VmIpFetchTaskWorkers, AllowDeployVmIfGivenHostFails, EnableAdditionalVmConfig, DisplayVMOVFProperties,
8007-
KvmAdditionalConfigAllowList, XenServerAdditionalConfigAllowList, VmwareAdditionalConfigAllowList};
8027+
KvmAdditionalConfigAllowList, XenServerAdditionalConfigAllowList, VmwareAdditionalConfigAllowList, DestroyRootVolumeOnVmDestruction};
80088028
}
80098029

80108030
@Override
@@ -8334,4 +8354,8 @@ private void collectVmDiskAndNetworkStatistics(UserVm vm, State expectedState) {
83348354
s_logger.warn(String.format("Skip collecting vm %s disk and network statistics as the expected vm state is %s but actual state is %s", vm, expectedState, vm.getState()));
83358355
}
83368356
}
8357+
8358+
public Boolean getDestroyRootVolumeOnVmDestruction(Long domainId){
8359+
return DestroyRootVolumeOnVmDestruction.valueIn(domainId);
8360+
}
83378361
}

server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
// under the License.
1717
package com.cloud.vm;
1818

19+
import com.cloud.storage.Volume;
20+
import com.cloud.storage.dao.VolumeDao;
1921
import static org.junit.Assert.assertEquals;
2022
import static org.junit.Assert.assertFalse;
2123
import static org.junit.Assert.assertTrue;
@@ -166,6 +168,12 @@ public class UserVmManagerImplTest {
166168
@Mock
167169
UserDataDao userDataDao;
168170

171+
@Mock
172+
private VolumeVO volumeVOMock;
173+
174+
@Mock
175+
private VolumeDao volumeDaoMock;
176+
169177
private long vmId = 1l;
170178

171179
private static final long GiB_TO_BYTES = 1024 * 1024 * 1024;
@@ -856,4 +864,14 @@ public void testResetVMUserDataSuccessResetWithUserdataId() {
856864
Assert.assertEquals("testUserdata", userVmVO.getUserData());
857865
Assert.assertEquals(1L, (long)userVmVO.getUserDataId());
858866
}
867+
868+
@Test
869+
public void recoverRootVolumeTestDestroyState() {
870+
Mockito.doReturn(Volume.State.Destroy).when(volumeVOMock).getState();
871+
872+
userVmManagerImpl.recoverRootVolume(volumeVOMock, vmId);
873+
874+
Mockito.verify(volumeApiService).recoverVolume(volumeVOMock.getId());
875+
Mockito.verify(volumeDaoMock).attachVolume(volumeVOMock.getId(), vmId, UserVmManagerImpl.ROOT_DEVICE_ID);
876+
}
859877
}

0 commit comments

Comments
 (0)