Skip to content

Commit 3c7c75b

Browse files
anniejiliAnnie Li
andauthored
Clear pool id if volume allocation fails (#8202)
* clear pool id if volume allocation fails and leave volume state as Allocated with a pool id assigned * clear_pool_id_if_volume_allocation_fails --------- Co-authored-by: Annie Li <ji_li@apple.com>
1 parent 1b56a8e commit 3c7c75b

File tree

3 files changed

+143
-0
lines changed

3 files changed

+143
-0
lines changed

server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1651,6 +1651,16 @@ protected Pair<Map<Volume, List<StoragePool>>, List<Volume>> findSuitablePoolsFo
16511651
for (VolumeVO toBeCreated : volumesTobeCreated) {
16521652
s_logger.debug("Checking suitable pools for volume (Id, Type): (" + toBeCreated.getId() + "," + toBeCreated.getVolumeType().name() + ")");
16531653

1654+
if (toBeCreated.getState() == Volume.State.Allocated && toBeCreated.getPoolId() != null) {
1655+
toBeCreated.setPoolId(null);
1656+
if (!_volsDao.update(toBeCreated.getId(), toBeCreated)) {
1657+
throw new CloudRuntimeException(String.format("Error updating volume [%s] to clear pool Id.", toBeCreated.getId()));
1658+
}
1659+
if (s_logger.isDebugEnabled()) {
1660+
String msg = String.format("Setting pool_id to NULL for volume id=%s as it is in Allocated state", toBeCreated.getId());
1661+
s_logger.debug(msg);
1662+
}
1663+
}
16541664
// If the plan specifies a poolId, it means that this VM's ROOT
16551665
// volume is ready and the pool should be reused.
16561666
// In this case, also check if rest of the volumes are ready and can

server/src/test/java/com/cloud/deploy/DeploymentPlanningManagerImplTest.java

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import static org.junit.Assert.assertFalse;
2020
import static org.junit.Assert.assertNull;
2121
import static org.junit.Assert.assertTrue;
22+
import static org.mockito.Mockito.times;
23+
import static org.mockito.Mockito.verify;
2224

2325
import java.io.IOException;
2426
import java.util.ArrayList;
@@ -33,26 +35,34 @@
3335

3436
import com.cloud.dc.ClusterDetailsVO;
3537
import com.cloud.dc.DataCenter;
38+
import com.cloud.dc.HostPodVO;
3639
import com.cloud.gpu.GPU;
3740
import com.cloud.host.Host;
3841
import com.cloud.host.HostVO;
3942
import com.cloud.host.Status;
4043
import com.cloud.storage.DiskOfferingVO;
4144
import com.cloud.storage.Storage;
4245
import com.cloud.storage.StoragePool;
46+
import com.cloud.storage.StoragePoolStatus;
4347
import com.cloud.storage.VMTemplateVO;
4448
import com.cloud.storage.Volume;
4549
import com.cloud.storage.VolumeVO;
4650
import com.cloud.storage.dao.VMTemplateDao;
51+
import com.cloud.template.VirtualMachineTemplate;
52+
import com.cloud.user.Account;
4753
import com.cloud.user.AccountVO;
4854
import com.cloud.user.dao.AccountDao;
4955
import com.cloud.utils.Pair;
56+
import com.cloud.vm.DiskProfile;
5057
import com.cloud.vm.VMInstanceVO;
5158
import com.cloud.vm.VirtualMachine;
5259
import com.cloud.vm.VirtualMachine.Type;
5360
import com.cloud.vm.VirtualMachineProfile;
5461
import com.cloud.vm.VirtualMachineProfileImpl;
5562
import org.apache.cloudstack.affinity.dao.AffinityGroupDomainMapDao;
63+
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
64+
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore;
65+
import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
5666
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
5767
import org.apache.commons.collections.CollectionUtils;
5868
import org.junit.Assert;
@@ -67,6 +77,7 @@
6777
import org.mockito.Mockito;
6878
import org.mockito.MockitoAnnotations;
6979
import org.mockito.Spy;
80+
import org.powermock.api.mockito.PowerMockito;
7081
import org.springframework.context.annotation.Bean;
7182
import org.springframework.context.annotation.ComponentScan;
7283
import org.springframework.context.annotation.ComponentScan.Filter;
@@ -197,6 +208,18 @@ public class DeploymentPlanningManagerImplTest {
197208
@Mock
198209
ConfigurationDao configDao;
199210

211+
@Mock
212+
AccountManager _accountMgr;
213+
214+
@Inject
215+
DiskOfferingDao _diskOfferingDao;
216+
217+
@Mock
218+
DataStoreManager _dataStoreManager;
219+
220+
@Inject
221+
HostPodDao _podDao;
222+
200223
private static final long dataCenterId = 1L;
201224
private static final long instanceId = 123L;
202225
private static final long hostId = 0L;
@@ -242,6 +265,8 @@ public void testSetUp() {
242265
List<DeploymentPlanner> planners = new ArrayList<DeploymentPlanner>();
243266
planners.add(_planner);
244267
_dpm.setPlanners(planners);
268+
StoragePoolAllocator allocator = Mockito.mock(StoragePoolAllocator.class);
269+
_dpm.setStoragePoolAllocators(Arrays.asList(allocator));
245270

246271
Mockito.when(host.getId()).thenReturn(hostId);
247272
Mockito.doNothing().when(_dpm).avoidDisabledResources(vmProfile, dc, avoids);
@@ -702,6 +727,84 @@ public void failEncRootPlannerHostSupportingEncryptionTest() {
702727
}
703728
}
704729

730+
@Test
731+
public void findSuitablePoolsForVolumesTest() throws Exception {
732+
Long diskOfferingId = 1L;
733+
HostVO host = Mockito.spy(new HostVO("host"));
734+
Map<String, String> hostDetails = new HashMap<>() {
735+
{
736+
put(Host.HOST_VOLUME_ENCRYPTION, "true");
737+
}
738+
};
739+
host.setDetails(hostDetails);
740+
Mockito.when(host.getStatus()).thenReturn(Status.Up);
741+
742+
VolumeVO vol1 = Mockito.spy(new VolumeVO("vol1", dataCenterId, podId, 1L, 1L, instanceId, "folder", "path",
743+
Storage.ProvisioningType.THIN, (long) 10 << 30, Volume.Type.ROOT));
744+
Mockito.when(vol1.getId()).thenReturn(1L);
745+
vol1.setState(Volume.State.Allocated);
746+
vol1.setPassphraseId(1L);
747+
vol1.setPoolId(1L);
748+
vol1.setDiskOfferingId(diskOfferingId);
749+
750+
StoragePoolVO storagePool = new StoragePoolVO();
751+
storagePool.setStatus(StoragePoolStatus.Maintenance);
752+
storagePool.setId(vol1.getPoolId());
753+
storagePool.setDataCenterId(dataCenterId);
754+
storagePool.setPodId(podId);
755+
storagePool.setClusterId(clusterId);
756+
757+
DiskProfile diskProfile = Mockito.mock(DiskProfile.class);
758+
759+
StoragePoolAllocator allocator = Mockito.mock(StoragePoolAllocator.class);
760+
761+
DataCenterDeployment plan = new DataCenterDeployment(dataCenterId, podId, clusterId, null, null, null);
762+
763+
Account account = Mockito.mock(Account.class);
764+
Mockito.when(account.getId()).thenReturn(1L);
765+
Mockito.when(vmProfile.getOwner()).thenReturn(account);
766+
Mockito.when(_accountMgr.isRootAdmin(account.getId())).thenReturn(Boolean.FALSE);
767+
768+
Mockito.when(_dcDao.findById(dataCenterId)).thenReturn(dc);
769+
Mockito.when(dc.getAllocationState()).thenReturn(AllocationState.Enabled);
770+
771+
HostPodVO podVo = Mockito.mock(HostPodVO.class);
772+
Mockito.when(podVo.getAllocationState()).thenReturn(AllocationState.Enabled);
773+
Mockito.doReturn(podVo).when(_podDao).findById(podId);
774+
775+
ClusterVO cluster = Mockito.mock(ClusterVO.class);
776+
Mockito.when(cluster.getAllocationState()).thenReturn(AllocationState.Enabled);
777+
Mockito.when(_clusterDao.findById(clusterId)).thenReturn(cluster);
778+
779+
DiskOfferingVO diskOffering = Mockito.mock(DiskOfferingVO.class);
780+
781+
Mockito.when(_diskOfferingDao.findById(vol1.getDiskOfferingId())).thenReturn(diskOffering);
782+
VirtualMachineTemplate vmt = Mockito.mock(VirtualMachineTemplate.class);
783+
784+
ServiceOfferingVO serviceOffering = Mockito.mock(ServiceOfferingVO.class);
785+
Mockito.when(vmProfile.getServiceOffering()).thenReturn(serviceOffering);
786+
787+
PrimaryDataStore primaryDataStore = Mockito.mock(PrimaryDataStore.class);
788+
789+
Mockito.when(vmt.getFormat()).thenReturn(Storage.ImageFormat.ISO);
790+
Mockito.when(vmProfile.getTemplate()).thenReturn(vmt);
791+
792+
Mockito.when(vmProfile.getId()).thenReturn(1L);
793+
Mockito.when(vmProfile.getType()).thenReturn(VirtualMachine.Type.User);
794+
Mockito.when(volDao.findUsableVolumesForInstance(1L)).thenReturn(Arrays.asList(vol1));
795+
Mockito.when(volDao.findByInstanceAndType(1L, Volume.Type.ROOT)).thenReturn(Arrays.asList(vol1));
796+
Mockito.when(_dataStoreManager.getPrimaryDataStore(vol1.getPoolId())).thenReturn((DataStore) primaryDataStore);
797+
Mockito.when(avoids.shouldAvoid(storagePool)).thenReturn(Boolean.FALSE);
798+
PowerMockito.whenNew(DiskProfile.class).withAnyArguments().thenReturn(diskProfile);
799+
800+
Mockito.doReturn(Arrays.asList(storagePool)).when(allocator).allocateToPool(diskProfile, vmProfile, plan,
801+
avoids, 10);
802+
Mockito.when(volDao.update(vol1.getId(), vol1)).thenReturn(true);
803+
_dpm.findSuitablePoolsForVolumes(vmProfile, plan, avoids, 10);
804+
verify(vol1, times(1)).setPoolId(null);
805+
assertTrue(vol1.getPoolId() == null);
806+
807+
}
705808
// This is so ugly but everything is so intertwined...
706809
private DeploymentClusterPlanner setupMocksForPlanDeploymentHostTests(HostVO host, VolumeVO vol1) {
707810
long diskOfferingId = 345L;

server/src/test/java/com/cloud/storage/StorageManagerImplTest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import java.util.ArrayList;
2020
import java.util.List;
2121

22+
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
23+
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
2224
import org.junit.Assert;
2325
import org.junit.Test;
2426
import org.junit.runner.RunWith;
@@ -128,4 +130,32 @@ public void testIsVolumeSuspectedDestroyDuplicateTrue() {
128130
Assert.assertTrue(storageManagerImpl.isVolumeSuspectedDestroyDuplicateOfVmVolume(volume));
129131
}
130132

133+
@Test
134+
public void storagePoolCompatibleWithVolumePoolTestVolumeWithPoolIdInAllocatedState() {
135+
StoragePoolVO storagePool = new StoragePoolVO();
136+
storagePool.setPoolType(Storage.StoragePoolType.PowerFlex);
137+
storagePool.setId(1L);
138+
VolumeVO volume = new VolumeVO();
139+
volume.setState(Volume.State.Allocated);
140+
volume.setPoolId(1L);
141+
PrimaryDataStoreDao storagePoolDao = Mockito.mock(PrimaryDataStoreDao.class);
142+
storageManagerImpl._storagePoolDao = storagePoolDao;
143+
Mockito.doReturn(storagePool).when(storagePoolDao).findById(volume.getPoolId());
144+
Assert.assertFalse(storageManagerImpl.storagePoolCompatibleWithVolumePool(storagePool, volume));
145+
146+
}
147+
148+
@Test
149+
public void storagePoolCompatibleWithVolumePoolTestVolumeWithoutPoolIdInAllocatedState() {
150+
StoragePoolVO storagePool = new StoragePoolVO();
151+
storagePool.setPoolType(Storage.StoragePoolType.PowerFlex);
152+
storagePool.setId(1L);
153+
VolumeVO volume = new VolumeVO();
154+
volume.setState(Volume.State.Allocated);
155+
PrimaryDataStoreDao storagePoolDao = Mockito.mock(PrimaryDataStoreDao.class);
156+
storageManagerImpl._storagePoolDao = storagePoolDao;
157+
Assert.assertTrue(storageManagerImpl.storagePoolCompatibleWithVolumePool(storagePool, volume));
158+
159+
}
160+
131161
}

0 commit comments

Comments
 (0)