Merge forward branch '4.11' PR #2629

Fix primary storage count when deleting volumes (#2629)
This commit is contained in:
Rafael Weingärtner 2018-05-16 16:59:17 -03:00
commit 15eddf3dd6
7 changed files with 669 additions and 289 deletions

View File

@ -18,6 +18,8 @@
*/
package com.cloud.storage;
import java.net.MalformedURLException;
import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
@ -26,13 +28,10 @@ import org.apache.cloudstack.api.command.user.volume.GetUploadParamsForVolumeCmd
import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.user.Account;
import org.apache.cloudstack.api.response.GetUploadParamsResponse;
import java.net.MalformedURLException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.user.Account;
public interface VolumeApiService {
/**
@ -72,17 +71,18 @@ public interface VolumeApiService {
*
* @return Volume object
*/
Volume uploadVolume(UploadVolumeCmd cmd) throws ResourceAllocationException;
Volume uploadVolume(UploadVolumeCmd cmd) throws ResourceAllocationException;
GetUploadParamsResponse uploadVolume(GetUploadParamsForVolumeCmd cmd) throws ResourceAllocationException, MalformedURLException;
boolean deleteVolume(long volumeId, Account caller) throws ConcurrentOperationException;
boolean deleteVolume(long volumeId, Account caller);
Volume attachVolumeToVM(AttachVolumeCmd command);
Volume detachVolumeFromVM(DetachVolumeCmd cmd);
Snapshot takeSnapshot(Long volumeId, Long policyId, Long snapshotId, Account account, boolean quiescevm, Snapshot.LocationType locationType, boolean asyncBackup) throws ResourceAllocationException;
Snapshot takeSnapshot(Long volumeId, Long policyId, Long snapshotId, Account account, boolean quiescevm, Snapshot.LocationType locationType, boolean asyncBackup)
throws ResourceAllocationException;
Snapshot allocSnapshot(Long volumeId, Long policyId, String snapshotName, Snapshot.LocationType locationType) throws ResourceAllocationException;
@ -92,10 +92,8 @@ public interface VolumeApiService {
* Extracts the volume to a particular location.
*
* @param cmd
* the command specifying url (where the volume needs to be extracted to), zoneId (zone where the volume
* exists),
* the command specifying url (where the volume needs to be extracted to), zoneId (zone where the volume exists),
* id (the id of the volume)
*
*/
String extractVolume(ExtractVolumeCmd cmd);

View File

@ -25,6 +25,7 @@ import com.cloud.storage.Volume;
import com.cloud.vm.VirtualMachine;
public interface VolumeInfo extends DataObject, Volume {
boolean isAttachedVM();
void addPayload(Object data);
@ -36,6 +37,7 @@ public interface VolumeInfo extends DataObject, Volume {
Long getLastPoolId();
String getAttachedVmName();
VirtualMachine getAttachedVM();
void processEventOnly(ObjectInDataStoreStateMachine.Event event);

View File

@ -20,16 +20,15 @@ package org.apache.cloudstack.engine.subsystem.api.storage;
import java.util.Map;
import com.cloud.utils.Pair;
import org.apache.cloudstack.engine.cloud.entity.api.VolumeEntity;
import org.apache.cloudstack.framework.async.AsyncCallFuture;
import org.apache.cloudstack.storage.command.CommandResult;
import com.cloud.agent.api.to.VirtualMachineTO;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.host.Host;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.offering.DiskOffering;
import com.cloud.utils.Pair;
public interface VolumeService {
class VolumeApiResult extends CommandResult {
@ -54,38 +53,24 @@ public interface VolumeService {
/**
* Creates the volume based on the given criteria
*
* @param cmd
*
* @return the volume object
*/
AsyncCallFuture<VolumeApiResult> createVolumeAsync(VolumeInfo volume, DataStore store);
/**
* Delete volume
*
* @param volumeId
* @return
* @throws ConcurrentOperationException
*/
AsyncCallFuture<VolumeApiResult> expungeVolumeAsync(VolumeInfo volume);
/**
*
*/
boolean cloneVolume(long volumeId, long baseVolId);
/**
*
*/
AsyncCallFuture<VolumeApiResult> createVolumeFromSnapshot(VolumeInfo volume, DataStore store, SnapshotInfo snapshot);
VolumeEntity getVolumeEntity(long volumeId);
AsyncCallFuture<VolumeApiResult> createManagedStorageVolumeFromTemplateAsync(VolumeInfo volumeInfo, long destDataStoreId,
TemplateInfo srcTemplateInfo, long destHostId);
AsyncCallFuture<VolumeApiResult> createManagedStorageVolumeFromTemplateAsync(VolumeInfo volumeInfo, long destDataStoreId, TemplateInfo srcTemplateInfo, long destHostId);
AsyncCallFuture<VolumeApiResult> createVolumeFromTemplateAsync(VolumeInfo volume, long dataStoreId,
TemplateInfo template);
AsyncCallFuture<VolumeApiResult> createVolumeFromTemplateAsync(VolumeInfo volume, long dataStoreId, TemplateInfo template);
AsyncCallFuture<VolumeApiResult> copyVolume(VolumeInfo srcVolume, DataStore destStore);
@ -93,11 +78,11 @@ public interface VolumeService {
AsyncCallFuture<CommandResult> migrateVolumes(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost);
boolean destroyVolume(long volumeId) throws ConcurrentOperationException;
void destroyVolume(long volumeId);
AsyncCallFuture<VolumeApiResult> registerVolume(VolumeInfo volume, DataStore store);
public Pair<EndPoint,DataObject> registerVolumeForPostUpload(VolumeInfo volume, DataStore store);
public Pair<EndPoint, DataObject> registerVolumeForPostUpload(VolumeInfo volume, DataStore store);
AsyncCallFuture<VolumeApiResult> resize(VolumeInfo volume);
@ -108,5 +93,4 @@ public interface VolumeService {
SnapshotInfo takeSnapshot(VolumeInfo volume);
VolumeInfo updateHypervisorSnapshotReserveForVolume(DiskOffering diskOffering, long volumeId, HypervisorType hyperType);
}
}

View File

@ -85,7 +85,6 @@ import com.cloud.configuration.Resource.ResourceType;
import com.cloud.dc.dao.ClusterDao;
import com.cloud.event.EventTypes;
import com.cloud.event.UsageEventUtils;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.host.Host;
import com.cloud.host.HostVO;
@ -110,6 +109,7 @@ import com.cloud.storage.Volume.State;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.VMTemplatePoolDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.storage.dao.VolumeDetailsDao;
import com.cloud.storage.snapshot.SnapshotManager;
import com.cloud.storage.template.TemplateProp;
import com.cloud.user.AccountManager;
@ -119,8 +119,6 @@ import com.cloud.utils.Pair;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.GlobalLock;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.storage.dao.VolumeDetailsDao;
@Component
public class VolumeServiceImpl implements VolumeService {
@ -420,8 +418,7 @@ public class VolumeServiceImpl implements VolumeService {
if (!supportsStorageSystemSnapshots) {
_snapshotStoreDao.remove(snapStoreVo.getId());
}
}
else {
} else {
_snapshotStoreDao.remove(snapStoreVo.getId());
}
}
@ -453,8 +450,8 @@ public class VolumeServiceImpl implements VolumeService {
private final TemplateInfo _templateInfo;
private final AsyncCallFuture<VolumeApiResult> _future;
public ManagedCreateBaseImageContext(AsyncCompletionCallback<T> callback, VolumeInfo volumeInfo,
PrimaryDataStore primaryDatastore, TemplateInfo templateInfo, AsyncCallFuture<VolumeApiResult> future) {
public ManagedCreateBaseImageContext(AsyncCompletionCallback<T> callback, VolumeInfo volumeInfo, PrimaryDataStore primaryDatastore, TemplateInfo templateInfo,
AsyncCallFuture<VolumeApiResult> future) {
super(callback);
_volumeInfo = volumeInfo;
@ -488,8 +485,8 @@ public class VolumeServiceImpl implements VolumeService {
final DataObject destObj;
long templatePoolId;
public CreateBaseImageContext(AsyncCompletionCallback<T> callback, VolumeInfo volume, PrimaryDataStore datastore, TemplateInfo srcTemplate,
AsyncCallFuture<VolumeApiResult> future, DataObject destObj, long templatePoolId) {
public CreateBaseImageContext(AsyncCompletionCallback<T> callback, VolumeInfo volume, PrimaryDataStore datastore, TemplateInfo srcTemplate, AsyncCallFuture<VolumeApiResult> future,
DataObject destObj, long templatePoolId) {
super(callback);
this.volume = volume;
this.dataStore = datastore;
@ -549,13 +546,11 @@ public class VolumeServiceImpl implements VolumeService {
throw new CloudRuntimeException("Failed to find template " + template.getUniqueName() + " in storage pool " + dataStore.getId());
} else {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Found template " + template.getUniqueName() + " in storage pool " + dataStore.getId() + " with VMTemplateStoragePool id: " +
templatePoolRef.getId());
s_logger.debug("Found template " + template.getUniqueName() + " in storage pool " + dataStore.getId() + " with VMTemplateStoragePool id: " + templatePoolRef.getId());
}
}
long templatePoolRefId = templatePoolRef.getId();
CreateBaseImageContext<CreateCmdResult> context =
new CreateBaseImageContext<CreateCmdResult>(null, volume, dataStore, template, future, templateOnPrimaryStoreObj, templatePoolRefId);
CreateBaseImageContext<CreateCmdResult> context = new CreateBaseImageContext<CreateCmdResult>(null, volume, dataStore, template, future, templateOnPrimaryStoreObj, templatePoolRefId);
AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
caller.setCallback(caller.getTarget().copyBaseImageCallback(null, null)).setContext(context);
@ -571,8 +566,8 @@ public class VolumeServiceImpl implements VolumeService {
}
templatePoolRef = _tmpltPoolDao.findByPoolTemplate(dataStore.getId(), template.getId());
if (templatePoolRef != null && templatePoolRef.getState() == ObjectInDataStoreStateMachine.State.Ready) {
s_logger.info("Unable to acquire lock on VMTemplateStoragePool " + templatePoolRefId + ", But Template " + template.getUniqueName() +
" is already copied to primary storage, skip copying");
s_logger.info(
"Unable to acquire lock on VMTemplateStoragePool " + templatePoolRefId + ", But Template " + template.getUniqueName() + " is already copied to primary storage, skip copying");
createVolumeFromBaseImageAsync(volume, templateOnPrimaryStoreObj, dataStore, future);
return;
}
@ -606,8 +601,7 @@ public class VolumeServiceImpl implements VolumeService {
return;
}
protected Void managedCopyBaseImageCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback,
ManagedCreateBaseImageContext<VolumeApiResult> context) {
protected Void managedCopyBaseImageCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback, ManagedCreateBaseImageContext<VolumeApiResult> context) {
CopyCommandResult result = callback.getResult();
VolumeInfo volumeInfo = context.getVolumeInfo();
VolumeApiResult res = new VolumeApiResult(volumeInfo);
@ -626,8 +620,7 @@ public class VolumeServiceImpl implements VolumeService {
}
volDao.update(volume.getId(), volume);
}
else {
} else {
volumeInfo.processEvent(Event.DestroyRequested);
res.setResult(result.getResult());
@ -652,8 +645,7 @@ public class VolumeServiceImpl implements VolumeService {
if (result.isSuccess()) {
((TemplateObject)templateOnPrimaryStoreObj).setInstallPath(result.getPath());
templateOnPrimaryStoreObj.processEvent(Event.OperationSuccessed, result.getAnswer());
}
else {
} else {
templateOnPrimaryStoreObj.processEvent(Event.OperationFailed);
}
@ -673,8 +665,7 @@ public class VolumeServiceImpl implements VolumeService {
if (result.isSuccess()) {
templateOnPrimaryStoreObj.processEvent(Event.OperationSuccessed, result.getAnswer());
}
else {
} else {
templateOnPrimaryStoreObj.processEvent(Event.OperationFailed);
}
@ -708,8 +699,8 @@ public class VolumeServiceImpl implements VolumeService {
private final DataObject templateOnStore;
private final SnapshotInfo snapshot;
public CreateVolumeFromBaseImageContext(AsyncCompletionCallback<T> callback, DataObject vo, DataStore primaryStore, DataObject templateOnStore,
AsyncCallFuture<VolumeApiResult> future, SnapshotInfo snapshot) {
public CreateVolumeFromBaseImageContext(AsyncCompletionCallback<T> callback, DataObject vo, DataStore primaryStore, DataObject templateOnStore, AsyncCallFuture<VolumeApiResult> future,
SnapshotInfo snapshot) {
super(callback);
this.vo = vo;
this.future = future;
@ -727,8 +718,7 @@ public class VolumeServiceImpl implements VolumeService {
DataObject volumeOnPrimaryStorage = pd.create(volume);
volumeOnPrimaryStorage.processEvent(Event.CreateOnlyRequested);
CreateVolumeFromBaseImageContext<VolumeApiResult> context =
new CreateVolumeFromBaseImageContext<VolumeApiResult>(null, volumeOnPrimaryStorage, pd, templateOnPrimaryStore, future, null);
CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<VolumeApiResult>(null, volumeOnPrimaryStorage, pd, templateOnPrimaryStore, future, null);
AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
caller.setCallback(caller.getTarget().createVolumeFromBaseImageCallBack(null, null));
caller.setContext(context);
@ -738,8 +728,7 @@ public class VolumeServiceImpl implements VolumeService {
}
@DB
protected Void createVolumeFromBaseImageCallBack(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback,
CreateVolumeFromBaseImageContext<VolumeApiResult> context) {
protected Void createVolumeFromBaseImageCallBack(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback, CreateVolumeFromBaseImageContext<VolumeApiResult> context) {
DataObject vo = context.vo;
DataObject tmplOnPrimary = context.templateOnStore;
CopyCommandResult result = callback.getResult();
@ -771,7 +760,7 @@ public class VolumeServiceImpl implements VolumeService {
_tmpltPoolDao.update(templatePoolRefId, templatePoolRef);
}
}finally {
} finally {
_tmpltPoolDao.releaseFromLockTable(templatePoolRefId);
}
}
@ -836,10 +825,9 @@ public class VolumeServiceImpl implements VolumeService {
VolumeApiResult result = createTemplateFuture.get();
if (result.isFailed()) {
String errMesg = result.getResult();
String errMesg = result.getResult();
throw new CloudRuntimeException("Unable to create template " + templateOnPrimary.getId() +
" on primary storage " + destPrimaryDataStore.getId() + ":" + errMesg);
throw new CloudRuntimeException("Unable to create template " + templateOnPrimary.getId() + " on primary storage " + destPrimaryDataStore.getId() + ":" + errMesg);
}
} catch (Throwable e) {
s_logger.debug("Failed to create template volume on storage", e);
@ -847,8 +835,7 @@ public class VolumeServiceImpl implements VolumeService {
templateOnPrimary.processEvent(Event.OperationFailed);
throw new CloudRuntimeException(e.getMessage());
}
finally {
} finally {
_tmpltPoolDao.releaseFromLockTable(templatePoolRefId);
}
@ -866,9 +853,8 @@ public class VolumeServiceImpl implements VolumeService {
* @param destPrimaryDataStore The managed primary storage
* @param destHost The host that we will use for the copy
*/
private void copyTemplateToManagedTemplateVolume(TemplateInfo srcTemplateInfo, TemplateInfo templateOnPrimary, VMTemplateStoragePoolVO templatePoolRef,
PrimaryDataStore destPrimaryDataStore, Host destHost)
{
private void copyTemplateToManagedTemplateVolume(TemplateInfo srcTemplateInfo, TemplateInfo templateOnPrimary, VMTemplateStoragePoolVO templatePoolRef, PrimaryDataStore destPrimaryDataStore,
Host destHost) {
AsyncCallFuture<VolumeApiResult> copyTemplateFuture = new AsyncCallFuture<>();
int storagePoolMaxWaitSeconds = NumbersUtil.parseInt(configDao.getValue(Config.StoragePoolMaxWaitSeconds.key()), 3600);
long templatePoolRefId = templatePoolRef.getId();
@ -889,11 +875,9 @@ public class VolumeServiceImpl implements VolumeService {
}
try {
// copy the template from sec storage to the created volume
CreateBaseImageContext<CreateCmdResult> copyContext = new CreateBaseImageContext<>(
null, null, destPrimaryDataStore, srcTemplateInfo,
copyTemplateFuture, templateOnPrimary, templatePoolRefId
);
// copy the template from sec storage to the created volume
CreateBaseImageContext<CreateCmdResult> copyContext = new CreateBaseImageContext<>(null, null, destPrimaryDataStore, srcTemplateInfo, copyTemplateFuture, templateOnPrimary,
templatePoolRefId);
AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> copyCaller = AsyncCallbackDispatcher.create(this);
copyCaller.setCallback(copyCaller.getTarget().copyManagedTemplateCallback(null, null)).setContext(copyContext);
@ -930,8 +914,7 @@ public class VolumeServiceImpl implements VolumeService {
motionSrv.copyAsync(srcTemplateInfo, templateOnPrimary, destHost, copyCaller);
result = copyTemplateFuture.get();
}
finally {
} finally {
revokeAccess(templateOnPrimary, destHost, destPrimaryDataStore);
if (HypervisorType.VMware.equals(destHost.getHypervisorType())) {
@ -946,21 +929,18 @@ public class VolumeServiceImpl implements VolumeService {
}
if (result.isFailed()) {
throw new CloudRuntimeException("Failed to copy template " + templateOnPrimary.getId() +
" to primary storage " + destPrimaryDataStore.getId() + ": " + result.getResult());
throw new CloudRuntimeException("Failed to copy template " + templateOnPrimary.getId() + " to primary storage " + destPrimaryDataStore.getId() + ": " + result.getResult());
// XXX: I find it is useful to destroy the volume on primary storage instead of another thread trying the copy again because I've seen
// something weird happens to the volume (XenServer creates an SR, but the VDI copy can fail).
// For now, I just retry the copy.
}
}
catch (Throwable e) {
} catch (Throwable e) {
s_logger.debug("Failed to create a template on primary storage", e);
templateOnPrimary.processEvent(Event.OperationFailed);
throw new CloudRuntimeException(e.getMessage());
}
finally {
} finally {
_tmpltPoolDao.releaseFromLockTable(templatePoolRefId);
}
}
@ -983,8 +963,7 @@ public class VolumeServiceImpl implements VolumeService {
String msg = "Unable to get an answer to the modify targets command";
s_logger.warn(msg);
}
else if (!answer.getResult()) {
} else if (!answer.getResult()) {
String msg = "Unable to modify target on the following host: " + hostId;
s_logger.warn(msg);
@ -999,8 +978,7 @@ public class VolumeServiceImpl implements VolumeService {
* @param destPrimaryDataStore Primary storage of the volume
* @param future For async
*/
private void createManagedVolumeCloneTemplateAsync(VolumeInfo volumeInfo, TemplateInfo templateOnPrimary, PrimaryDataStore destPrimaryDataStore,
AsyncCallFuture<VolumeApiResult> future) {
private void createManagedVolumeCloneTemplateAsync(VolumeInfo volumeInfo, TemplateInfo templateOnPrimary, PrimaryDataStore destPrimaryDataStore, AsyncCallFuture<VolumeApiResult> future) {
VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.findByPoolTemplate(destPrimaryDataStore.getId(), templateOnPrimary.getId());
if (templatePoolRef == null) {
@ -1015,8 +993,7 @@ public class VolumeServiceImpl implements VolumeService {
try {
volumeInfo.processEvent(Event.CreateOnlyRequested);
CreateVolumeFromBaseImageContext<VolumeApiResult> context =
new CreateVolumeFromBaseImageContext<>(null, volumeInfo, destPrimaryDataStore, templateOnPrimary, future, null);
CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<>(null, volumeInfo, destPrimaryDataStore, templateOnPrimary, future, null);
AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
@ -1033,8 +1010,7 @@ public class VolumeServiceImpl implements VolumeService {
}
}
private void createManagedVolumeCopyTemplateAsync(VolumeInfo volumeInfo, PrimaryDataStore primaryDataStore, TemplateInfo srcTemplateInfo, Host destHost,
AsyncCallFuture<VolumeApiResult> future) {
private void createManagedVolumeCopyTemplateAsync(VolumeInfo volumeInfo, PrimaryDataStore primaryDataStore, TemplateInfo srcTemplateInfo, Host destHost, AsyncCallFuture<VolumeApiResult> future) {
try {
// Create a volume on managed storage.
@ -1050,8 +1026,7 @@ public class VolumeServiceImpl implements VolumeService {
// Refresh the volume info from the DB.
volumeInfo = volFactory.getVolume(volumeInfo.getId(), primaryDataStore);
ManagedCreateBaseImageContext<CreateCmdResult> context = new ManagedCreateBaseImageContext<CreateCmdResult>(null, volumeInfo,
primaryDataStore, srcTemplateInfo, future);
ManagedCreateBaseImageContext<CreateCmdResult> context = new ManagedCreateBaseImageContext<CreateCmdResult>(null, volumeInfo, primaryDataStore, srcTemplateInfo, future);
AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
caller.setCallback(caller.getTarget().managedCopyBaseImageCallback(null, null)).setContext(context);
@ -1081,8 +1056,7 @@ public class VolumeServiceImpl implements VolumeService {
try {
motionSrv.copyAsync(srcTemplateInfo, destTemplateInfo, destHost, caller);
}
finally {
} finally {
revokeAccess(volumeInfo, destHost, primaryDataStore);
}
} catch (Throwable t) {
@ -1098,8 +1072,7 @@ public class VolumeServiceImpl implements VolumeService {
if (expungeVolumeResult.isFailed()) {
errMsg += " : Failed to expunge a volume that was created";
}
}
catch (Exception ex) {
} catch (Exception ex) {
errMsg += " : " + ex.getMessage();
}
@ -1112,8 +1085,7 @@ public class VolumeServiceImpl implements VolumeService {
}
@Override
public AsyncCallFuture<VolumeApiResult> createManagedStorageVolumeFromTemplateAsync(VolumeInfo volumeInfo, long destDataStoreId,
TemplateInfo srcTemplateInfo, long destHostId) {
public AsyncCallFuture<VolumeApiResult> createManagedStorageVolumeFromTemplateAsync(VolumeInfo volumeInfo, long destDataStoreId, TemplateInfo srcTemplateInfo, long destHostId) {
PrimaryDataStore destPrimaryDataStore = dataStoreMgr.getPrimaryDataStore(destDataStoreId);
Host destHost = _hostDao.findById(destHostId);
@ -1121,9 +1093,7 @@ public class VolumeServiceImpl implements VolumeService {
throw new CloudRuntimeException("Destination host should not be null.");
}
Boolean storageCanCloneVolume = new Boolean(
destPrimaryDataStore.getDriver().getCapabilities().get(DataStoreCapabilities.CAN_CREATE_VOLUME_FROM_VOLUME.toString())
);
Boolean storageCanCloneVolume = new Boolean(destPrimaryDataStore.getDriver().getCapabilities().get(DataStoreCapabilities.CAN_CREATE_VOLUME_FROM_VOLUME.toString()));
boolean computeSupportsVolumeClone = computeSupportsVolumeClone(destHost.getDataCenterId(), destHost.getHypervisorType());
@ -1146,10 +1116,7 @@ public class VolumeServiceImpl implements VolumeService {
VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.findByPoolTemplate(destPrimaryDataStore.getId(), templateOnPrimary.getId());
if (templatePoolRef == null) {
throw new CloudRuntimeException("Failed to find template " +
srcTemplateInfo.getUniqueName() + " in storage pool " +
destPrimaryDataStore.getId()
);
throw new CloudRuntimeException("Failed to find template " + srcTemplateInfo.getUniqueName() + " in storage pool " + destPrimaryDataStore.getId());
}
if (templatePoolRef.getDownloadState() == Status.NOT_DOWNLOADED) {
@ -1190,8 +1157,7 @@ public class VolumeServiceImpl implements VolumeService {
Collections.shuffle(clusters, new Random(System.nanoTime()));
clusters:
for (Cluster cluster : clusters) {
clusters: for (Cluster cluster : clusters) {
if (cluster.getAllocationState() == AllocationState.Enabled) {
List<HostVO> hosts = _hostDao.findByClusterId(cluster.getId());
@ -1203,13 +1169,11 @@ public class VolumeServiceImpl implements VolumeService {
if (computeClusterMustSupportResign) {
if (clusterDao.getSupportsResigning(cluster.getId())) {
return host;
}
else {
} else {
// no other host in the cluster in question should be able to satisfy our requirements here, so move on to the next cluster
continue clusters;
}
}
else {
} else {
return host;
}
}
@ -1237,17 +1201,15 @@ public class VolumeServiceImpl implements VolumeService {
return future;
}
@Override
@DB
public boolean destroyVolume(long volumeId) throws ConcurrentOperationException {
@Override
public void destroyVolume(long volumeId) {
// mark volume entry in volumes table as destroy state
VolumeInfo vol = volFactory.getVolume(volumeId);
vol.stateTransit(Volume.Event.DestroyRequested);
snapshotMgr.deletePoliciesForVolume(volumeId);
vol.stateTransit(Volume.Event.OperationSucceeded);
return true;
}
@Override
@ -1259,8 +1221,7 @@ public class VolumeServiceImpl implements VolumeService {
volumeOnStore.processEvent(Event.CreateOnlyRequested);
_volumeDetailsDao.addDetail(volume.getId(), SNAPSHOT_ID, Long.toString(snapshot.getId()), false);
CreateVolumeFromBaseImageContext<VolumeApiResult> context =
new CreateVolumeFromBaseImageContext<VolumeApiResult>(null, volume, store, volumeOnStore, future, snapshot);
CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<VolumeApiResult>(null, volume, store, volumeOnStore, future, snapshot);
AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
caller.setCallback(caller.getTarget().createVolumeFromSnapshotCallback(null, null)).setContext(context);
motionSrv.copyAsync(snapshot, volumeOnStore, caller);
@ -1274,8 +1235,7 @@ public class VolumeServiceImpl implements VolumeService {
return future;
}
protected Void createVolumeFromSnapshotCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback,
CreateVolumeFromBaseImageContext<VolumeApiResult> context) {
protected Void createVolumeFromSnapshotCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback, CreateVolumeFromBaseImageContext<VolumeApiResult> context) {
CopyCommandResult result = callback.getResult();
VolumeInfo volume = (VolumeInfo)context.templateOnStore;
SnapshotInfo snapshot = context.snapshot;
@ -1332,8 +1292,7 @@ public class VolumeServiceImpl implements VolumeService {
final VolumeInfo destVolume;
final AsyncCallFuture<VolumeApiResult> future;
public CopyVolumeContext(AsyncCompletionCallback<T> callback, AsyncCallFuture<VolumeApiResult> future, VolumeInfo srcVolume, VolumeInfo destVolume,
DataStore destStore) {
public CopyVolumeContext(AsyncCompletionCallback<T> callback, AsyncCallFuture<VolumeApiResult> future, VolumeInfo srcVolume, VolumeInfo destVolume, DataStore destStore) {
super(callback);
this.srcVolume = srcVolume;
this.destVolume = destVolume;
@ -1370,8 +1329,7 @@ public class VolumeServiceImpl implements VolumeService {
}
}
protected Void
copyVolumeFromImageToPrimaryCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback, CopyVolumeContext<VolumeApiResult> context) {
protected Void copyVolumeFromImageToPrimaryCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback, CopyVolumeContext<VolumeApiResult> context) {
VolumeInfo srcVolume = context.srcVolume;
VolumeInfo destVolume = context.destVolume;
CopyCommandResult result = callback.getResult();
@ -1424,8 +1382,7 @@ public class VolumeServiceImpl implements VolumeService {
}
}
protected Void
copyVolumeFromPrimaryToImageCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback, CopyVolumeContext<VolumeApiResult> context) {
protected Void copyVolumeFromPrimaryToImageCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback, CopyVolumeContext<VolumeApiResult> context) {
VolumeInfo srcVolume = context.srcVolume;
VolumeInfo destVolume = context.destVolume;
CopyCommandResult result = callback.getResult();
@ -1542,8 +1499,7 @@ public class VolumeServiceImpl implements VolumeService {
/**
* @param callback
*/
public MigrateVolumeContext(AsyncCompletionCallback<T> callback, AsyncCallFuture<VolumeApiResult> future, VolumeInfo srcVolume, VolumeInfo destVolume,
DataStore destStore) {
public MigrateVolumeContext(AsyncCompletionCallback<T> callback, AsyncCallFuture<VolumeApiResult> future, VolumeInfo srcVolume, VolumeInfo destVolume, DataStore destStore) {
super(callback);
this.srcVolume = srcVolume;
this.destVolume = destVolume;
@ -1654,8 +1610,7 @@ public class VolumeServiceImpl implements VolumeService {
return future;
}
protected Void
migrateVmWithVolumesCallBack(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback, MigrateVmWithVolumesContext<CommandResult> context) {
protected Void migrateVmWithVolumesCallBack(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback, MigrateVmWithVolumesContext<CommandResult> context) {
Map<VolumeInfo, DataStore> volumeToPool = context.volumeToPool;
CopyCommandResult result = callback.getResult();
AsyncCallFuture<CommandResult> future = context.future;
@ -1715,7 +1670,7 @@ public class VolumeServiceImpl implements VolumeService {
}
@Override
public Pair<EndPoint,DataObject> registerVolumeForPostUpload(VolumeInfo volume, DataStore store) {
public Pair<EndPoint, DataObject> registerVolumeForPostUpload(VolumeInfo volume, DataStore store) {
EndPoint ep = _epSelector.select(store);
if (ep == null) {
@ -1724,7 +1679,7 @@ public class VolumeServiceImpl implements VolumeService {
throw new CloudRuntimeException(errorMessage);
}
DataObject volumeOnStore = store.create(volume);
return new Pair<>(ep,volumeOnStore);
return new Pair<>(ep, volumeOnStore);
}
protected Void registerVolumeCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> callback, CreateVolumeContext<VolumeApiResult> context) {
@ -1751,21 +1706,20 @@ public class VolumeServiceImpl implements VolumeService {
if (volStore != null) {
physicalSize = volStore.getPhysicalSize();
} else {
s_logger.warn("No entry found in volume_store_ref for volume id: " + vo.getId() + " and image store id: " + ds.getId() +
" at the end of uploading volume!");
s_logger.warn("No entry found in volume_store_ref for volume id: " + vo.getId() + " and image store id: " + ds.getId() + " at the end of uploading volume!");
}
Scope dsScope = ds.getScope();
if (dsScope.getScopeType() == ScopeType.ZONE) {
if (dsScope.getScopeId() != null) {
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_UPLOAD, vo.getAccountId(), dsScope.getScopeId(), vo.getId(), vo.getName(), null,
null, physicalSize, vo.getSize(), Volume.class.getName(), vo.getUuid());
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_UPLOAD, vo.getAccountId(), dsScope.getScopeId(), vo.getId(), vo.getName(), null, null, physicalSize, vo.getSize(),
Volume.class.getName(), vo.getUuid());
} else {
s_logger.warn("Zone scope image store " + ds.getId() + " has a null scope id");
}
} else if (dsScope.getScopeType() == ScopeType.REGION) {
// publish usage event for region-wide image store using a -1 zoneId for 4.2, need to revisit post-4.2
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_UPLOAD, vo.getAccountId(), -1, vo.getId(), vo.getName(), null, null, physicalSize,
vo.getSize(), Volume.class.getName(), vo.getUuid());
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_UPLOAD, vo.getAccountId(), -1, vo.getId(), vo.getName(), null, null, physicalSize, vo.getSize(),
Volume.class.getName(), vo.getUuid());
_resourceLimitMgr.incrementResourceCount(vo.getAccountId(), ResourceType.secondary_storage, vo.getSize());
}
@ -1829,8 +1783,8 @@ public class VolumeServiceImpl implements VolumeService {
if (ep != null) {
VolumeVO volume = volDao.findById(volumeId);
PrimaryDataStore primaryDataStore = this.dataStoreMgr.getPrimaryDataStore(volume.getPoolId());
ResizeVolumeCommand resizeCmd = new ResizeVolumeCommand(volume.getPath(), new StorageFilerTO(primaryDataStore),
volume.getSize(), newSize, true, instanceName, primaryDataStore.isManaged(), volume.get_iScsiName());
ResizeVolumeCommand resizeCmd = new ResizeVolumeCommand(volume.getPath(), new StorageFilerTO(primaryDataStore), volume.getSize(), newSize, true, instanceName,
primaryDataStore.isManaged(), volume.get_iScsiName());
answer = ep.sendMessage(resizeCmd);
} else {
@ -1903,8 +1857,8 @@ public class VolumeServiceImpl implements VolumeService {
for (VolumeDataStoreVO volumeStore : dbVolumes) {
VolumeVO volume = volDao.findById(volumeStore.getVolumeId());
if (volume == null) {
s_logger.warn("Volume_store_ref table shows that volume " + volumeStore.getVolumeId() + " is on image store " + storeId +
", but the volume is not found in volumes table, potentially some bugs in deleteVolume, so we just treat this volume to be deleted and mark it as destroyed");
s_logger.warn("Volume_store_ref table shows that volume " + volumeStore.getVolumeId() + " is on image store " + storeId
+ ", but the volume is not found in volumes table, potentially some bugs in deleteVolume, so we just treat this volume to be deleted and mark it as destroyed");
volumeStore.setDestroyed(true);
_volumeStoreDao.update(volumeStore.getId(), volumeStore);
continue;
@ -1929,7 +1883,8 @@ public class VolumeServiceImpl implements VolumeService {
VolumeObject volObj = (VolumeObject)volFactory.getVolume(volume.getId());
volObj.processEvent(Event.OperationFailed);
} else if (volumeStore.getDownloadUrl() == null) {
msg = "Volume (" + volume.getUuid() + ") with install path " + volInfo.getInstallPath() + " is corrupted, please check in image store: " + volumeStore.getDataStoreId();
msg = "Volume (" + volume.getUuid() + ") with install path " + volInfo.getInstallPath() + " is corrupted, please check in image store: "
+ volumeStore.getDataStoreId();
s_logger.warn(msg);
} else {
s_logger.info("Removing volume_store_ref entry for corrupted volume " + volume.getName());
@ -1959,8 +1914,8 @@ public class VolumeServiceImpl implements VolumeService {
if (volInfo.getSize() > 0) {
try {
_resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(volume.getAccountId()),
com.cloud.configuration.Resource.ResourceType.secondary_storage, volInfo.getSize() - volInfo.getPhysicalSize());
_resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(volume.getAccountId()), com.cloud.configuration.Resource.ResourceType.secondary_storage,
volInfo.getSize() - volInfo.getPhysicalSize());
} catch (ResourceAllocationException e) {
s_logger.warn(e.getMessage());
_alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED, volume.getDataCenterId(), volume.getPodId(), e.getMessage(), e.getMessage());
@ -2021,7 +1976,7 @@ public class VolumeServiceImpl implements VolumeService {
}
// Delete volumes which are not present on DB.
for (Map.Entry<Long,TemplateProp> entry : volumeInfos.entrySet()) {
for (Map.Entry<Long, TemplateProp> entry : volumeInfos.entrySet()) {
Long uniqueName = entry.getKey();
TemplateProp tInfo = entry.getValue();
@ -2091,7 +2046,7 @@ public class VolumeServiceImpl implements VolumeService {
s_logger.error("Take snapshot: " + volume.getId() + " failed", cre);
throw cre;
} catch (Exception e) {
if(s_logger.isDebugEnabled()) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("unknown exception while taking snapshot for volume " + volume.getId() + " was caught", e);
}
throw new CloudRuntimeException("Failed to take snapshot", e);

View File

@ -38,7 +38,6 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.api.command.admin.storage.CancelPrimaryStorageMaintenanceCmd;
import org.apache.cloudstack.api.command.admin.storage.CreateSecondaryStagingStoreCmd;
@ -466,8 +465,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
}
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
public boolean configure(String name, Map<String, Object> params) {
Map<String, String> configs = _configDao.getConfiguration("management-server", params);
_storagePoolAcquisitionWaitSeconds = NumbersUtil.parseInt(configs.get("pool.acquisition.wait.seconds"), 1800);
@ -524,7 +522,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
@Override
public String getStoragePoolTags(long poolId) {
return StringUtils.listToCsvTags(_storagePoolDao.searchForStoragePoolTags(poolId));
return com.cloud.utils.StringUtils.listToCsvTags(_storagePoolDao.searchForStoragePoolTags(poolId));
}
@Override
@ -1176,10 +1174,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
Host host = _hostDao.findById(ep.getId());
if (host != null && host.getManagementServerId() != null) {
if (_serverId == host.getManagementServerId().longValue()) {
if (!volService.destroyVolume(volume.getId())) {
s_logger.warn("Unable to destroy uploaded volume " + volume.getUuid());
continue;
}
volService.destroyVolume(volume.getId());
// decrement volume resource count
_resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.volume, volume.isDisplayVolume());
// expunge volume from secondary if volume is on image store
@ -1844,8 +1839,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
totalOverProvCapacity = overProvFactor.multiply(new BigDecimal(pool.getCapacityBytes())).longValue();
s_logger.debug("Found storage pool " + poolVO.getName() + " of type " + pool.getPoolType().toString() + " with over-provisioning factor " +
overProvFactor.toString());
s_logger.debug("Found storage pool " + poolVO.getName() + " of type " + pool.getPoolType().toString() + " with over-provisioning factor " + overProvFactor.toString());
s_logger.debug("Total over-provisioned capacity calculated is " + overProvFactor + " * " + pool.getCapacityBytes());
} else {
totalOverProvCapacity = pool.getCapacityBytes();
@ -1858,18 +1852,16 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
double storageAllocatedThreshold = CapacityManager.StorageAllocatedCapacityDisableThreshold.valueIn(pool.getDataCenterId());
if (s_logger.isDebugEnabled()) {
s_logger.debug("Checking pool with ID " + pool.getId() + " for volume allocation " + volumes.toString() + ", maxSize: " +
totalOverProvCapacity + ", totalAllocatedSize: " + allocatedSizeWithTemplate + ", askingSize: " + totalAskingSize +
", allocated disable threshold: " + storageAllocatedThreshold);
s_logger.debug("Checking pool with ID " + pool.getId() + " for volume allocation " + volumes.toString() + ", maxSize: " + totalOverProvCapacity + ", totalAllocatedSize: "
+ allocatedSizeWithTemplate + ", askingSize: " + totalAskingSize + ", allocated disable threshold: " + storageAllocatedThreshold);
}
double usedPercentage = (allocatedSizeWithTemplate + totalAskingSize) / (double)(totalOverProvCapacity);
if (usedPercentage > storageAllocatedThreshold) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Insufficient un-allocated capacity on the pool with ID " + pool.getId() + " for volume allocation: " + volumes.toString() +
" since its allocated percentage " + usedPercentage + " has crossed the allocated pool.storage.allocated.capacity.disablethreshold " +
storageAllocatedThreshold + ", skipping this pool");
s_logger.debug("Insufficient un-allocated capacity on the pool with ID " + pool.getId() + " for volume allocation: " + volumes.toString() + " since its allocated percentage "
+ usedPercentage + " has crossed the allocated pool.storage.allocated.capacity.disablethreshold " + storageAllocatedThreshold + ", skipping this pool");
}
return false;
@ -1877,9 +1869,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
if (totalOverProvCapacity < (allocatedSizeWithTemplate + totalAskingSize)) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Insufficient un-allocated capacity on the pool with ID " + pool.getId() + " for volume allocation: " + volumes.toString() +
"; not enough storage, maxSize: " + totalOverProvCapacity + ", totalAllocatedSize: " + allocatedSizeWithTemplate + ", askingSize: " +
totalAskingSize);
s_logger.debug("Insufficient un-allocated capacity on the pool with ID " + pool.getId() + " for volume allocation: " + volumes.toString() + "; not enough storage, maxSize: "
+ totalOverProvCapacity + ", totalAllocatedSize: " + allocatedSizeWithTemplate + ", askingSize: " + totalAskingSize);
}
return false;

View File

@ -1237,92 +1237,139 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
}
}
@Override
@DB
@Override
@ActionEvent(eventType = EventTypes.EVENT_VOLUME_DELETE, eventDescription = "deleting volume")
/**
* Executes the removal of the volume. If the volume is only allocated we do not try to remove it from primary and secondary storage.
* Otherwise, after the removal in the database, we will try to remove the volume from both primary and secondary storage.
*/
public boolean deleteVolume(long volumeId, Account caller) throws ConcurrentOperationException {
VolumeVO volume = _volsDao.findById(volumeId);
if (volume == null) {
throw new InvalidParameterValueException("Unable to find volume with ID: " + volumeId);
}
if (!_snapshotMgr.canOperateOnVolume(volume)) {
throw new InvalidParameterValueException("There are snapshot operations in progress on the volume, unable to delete it");
}
_accountMgr.checkAccess(caller, null, true, volume);
if (volume.getInstanceId() != null) {
throw new InvalidParameterValueException("Please specify a volume that is not attached to any VM.");
}
if (volume.getState() == Volume.State.UploadOp) {
VolumeDataStoreVO volumeStore = _volumeStoreDao.findByVolume(volume.getId());
if (volumeStore.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS) {
throw new InvalidParameterValueException("Please specify a volume that is not uploading");
}
}
if (volume.getState() == Volume.State.NotUploaded || volume.getState() == Volume.State.UploadInProgress) {
throw new InvalidParameterValueException("The volume is either getting uploaded or it may be initiated shortly, please wait for it to be completed");
}
VolumeVO volume = retrieveAndValidateVolume(volumeId, caller);
try {
if (volume.getState() != Volume.State.Destroy && volume.getState() != Volume.State.Expunging && volume.getState() != Volume.State.Expunged) {
Long instanceId = volume.getInstanceId();
if (!volService.destroyVolume(volume.getId())) {
return false;
}
VMInstanceVO vmInstance = _vmInstanceDao.findById(instanceId);
if (instanceId == null || (vmInstance.getType().equals(VirtualMachine.Type.User))) {
// Decrement the resource count for volumes and primary storage belonging user VM's only
_resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.volume, volume.isDisplayVolume());
_resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.primary_storage, volume.isDisplayVolume(), new Long(volume.getSize()));
}
}
destroyVolumeIfPossible(volume);
// Mark volume as removed if volume has not been created on primary or secondary
if (volume.getState() == Volume.State.Allocated) {
_volsDao.remove(volumeId);
stateTransitTo(volume, Volume.Event.DestroyRequested);
return true;
}
// expunge volume from primary if volume is on primary
VolumeInfo volOnPrimary = volFactory.getVolume(volume.getId(), DataStoreRole.Primary);
if (volOnPrimary != null) {
s_logger.info("Expunging volume " + volume.getId() + " from primary data store");
AsyncCallFuture<VolumeApiResult> future = volService.expungeVolumeAsync(volOnPrimary);
future.get();
//decrement primary storage count
_resourceLimitMgr.decrementResourceCount(volOnPrimary.getAccountId(), ResourceType.volume, volOnPrimary.isDisplayVolume());
_resourceLimitMgr.decrementResourceCount(volOnPrimary.getAccountId(), ResourceType.primary_storage, volOnPrimary.isDisplayVolume(), new Long(volOnPrimary.getSize()));
}
// expunge volume from secondary if volume is on image store
VolumeInfo volOnSecondary = volFactory.getVolume(volume.getId(), DataStoreRole.Image);
if (volOnSecondary != null) {
s_logger.info("Expunging volume " + volume.getId() + " from secondary data store");
AsyncCallFuture<VolumeApiResult> future2 = volService.expungeVolumeAsync(volOnSecondary);
future2.get();
//decrement secondary storage count
_resourceLimitMgr.decrementResourceCount(volOnSecondary.getAccountId(), ResourceType.secondary_storage, new Long(volOnSecondary.getSize()));
}
// delete all cache entries for this volume
List<VolumeInfo> cacheVols = volFactory.listVolumeOnCache(volume.getId());
for (VolumeInfo volOnCache : cacheVols) {
s_logger.info("Delete volume from image cache store: " + volOnCache.getDataStore().getName());
volOnCache.delete();
}
expungeVolumesInPrimaryStorageIfNeeded(volume);
expungeVolumesInSecondaryStorageIfNeeded(volume);
cleanVolumesCache(volume);
return true;
} catch (InterruptedException | ExecutionException | NoTransitionException e) {
s_logger.warn("Failed to expunge volume:", e);
s_logger.warn("Failed to expunge volume: " + volume.getUuid(), e);
return false;
}
return true;
}
private boolean stateTransitTo(Volume vol, Volume.Event event) throws NoTransitionException {
/**
* Retrieves and validates the volume for the {@link #deleteVolume(long, Account)} method. The following validation are executed.
* <ul>
* <li> if no volume is found in the database, we throw an {@link InvalidParameterValueException};
* <li> if there are snapshots operation on the volume we cannot delete it. Therefore, an {@link InvalidParameterValueException} is thrown;
* <li> if the volume is still attached to a VM we throw an {@link InvalidParameterValueException};
* <li> if volume state is in {@link Volume.State#UploadOp}, we check the {@link VolumeDataStoreVO}. Then, if the {@link VolumeDataStoreVO} for the given volume has download status of {@link VMTemplateStorageResourceAssoc.Status#DOWNLOAD_IN_PROGRESS}, an exception is throw;
* <li> if the volume state is in {@link Volume.State#NotUploaded} or if the state is {@link Volume.State#UploadInProgress}, an {@link InvalidParameterValueException} is thrown;
* <li> we also check if the user has access to the given volume using {@link AccountManager#checkAccess(Account, org.apache.cloudstack.acl.SecurityChecker.AccessType, boolean, String)}.
* </ul>
*
* After all validations we return the volume object.
*/
protected VolumeVO retrieveAndValidateVolume(long volumeId, Account caller) {
VolumeVO volume = _volsDao.findById(volumeId);
if (volume == null) {
throw new InvalidParameterValueException("Unable to find volume with ID: " + volumeId);
}
if (!_snapshotMgr.canOperateOnVolume(volume)) {
throw new InvalidParameterValueException("There are snapshot operations in progress on the volume, unable to delete it");
}
if (volume.getInstanceId() != null) {
throw new InvalidParameterValueException("Please specify a volume that is not attached to any VM.");
}
if (volume.getState() == Volume.State.UploadOp) {
VolumeDataStoreVO volumeStore = _volumeStoreDao.findByVolume(volume.getId());
if (volumeStore.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS) {
throw new InvalidParameterValueException("Please specify a volume that is not uploading");
}
}
if (volume.getState() == Volume.State.NotUploaded || volume.getState() == Volume.State.UploadInProgress) {
throw new InvalidParameterValueException("The volume is either getting uploaded or it may be initiated shortly, please wait for it to be completed");
}
_accountMgr.checkAccess(caller, null, true, volume);
return volume;
}
/**
* Destroy the volume if possible and then decrement the following resource types.
* <ul>
* <li> {@link ResourceType#volume};
* <li> {@link ResourceType#primary_storage}
* </ul>
*
* A volume can be destroyed if it is not in any of the following states.
* <ul>
* <li> {@value Volume.State#Destroy};
* <li> {@value Volume.State#Expunging};
* <li> {@value Volume.State#Expunged}.
* </ul>
*
* The volume is destroyed via {@link VolumeService#destroyVolume(long)} method.
*/
protected void destroyVolumeIfPossible(VolumeVO volume) {
if (volume.getState() != Volume.State.Destroy && volume.getState() != Volume.State.Expunging && volume.getState() != Volume.State.Expunged) {
volService.destroyVolume(volume.getId());
// Decrement the resource count for volumes and primary storage belonging user VM's only
_resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.volume, volume.isDisplayVolume());
_resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.primary_storage, volume.isDisplayVolume(), volume.getSize());
}
}
/**
* We will check if the given volume is in the primary storage. If it is, we will execute an asynchronous call to delete it there.
* If the volume is not in the primary storage, we do nothing here.
*/
protected void expungeVolumesInPrimaryStorageIfNeeded(VolumeVO volume) throws InterruptedException, ExecutionException {
VolumeInfo volOnPrimary = volFactory.getVolume(volume.getId(), DataStoreRole.Primary);
if (volOnPrimary != null) {
s_logger.info("Expunging volume " + volume.getId() + " from primary data store");
AsyncCallFuture<VolumeApiResult> future = volService.expungeVolumeAsync(volOnPrimary);
future.get();
}
}
/**
* We will check if the given volume is in the secondary storage. If the volume is not in the primary storage, we do nothing here.
* If it is, we will execute an asynchronous call to delete it there. Then, we decrement the {@link ResourceType#secondary_storage} for the account that owns the volume.
*/
protected void expungeVolumesInSecondaryStorageIfNeeded(VolumeVO volume) throws InterruptedException, ExecutionException {
VolumeInfo volOnSecondary = volFactory.getVolume(volume.getId(), DataStoreRole.Image);
if (volOnSecondary != null) {
s_logger.info("Expunging volume " + volume.getId() + " from secondary data store");
AsyncCallFuture<VolumeApiResult> future2 = volService.expungeVolumeAsync(volOnSecondary);
future2.get();
_resourceLimitMgr.decrementResourceCount(volOnSecondary.getAccountId(), ResourceType.secondary_storage, volOnSecondary.getSize());
}
}
/**
* Clean volumes cache entries (if they exist).
*/
protected void cleanVolumesCache(VolumeVO volume) {
List<VolumeInfo> cacheVols = volFactory.listVolumeOnCache(volume.getId());
if (CollectionUtils.isEmpty(cacheVols)) {
return;
}
for (VolumeInfo volOnCache : cacheVols) {
s_logger.info("Delete volume from image cache store: " + volOnCache.getDataStore().getName());
volOnCache.delete();
}
}
protected boolean stateTransitTo(Volume vol, Volume.Event event) throws NoTransitionException {
return _volStateMachine.transitTo(vol, event, null, _volsDao);
}
@ -3198,4 +3245,4 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
return workJob;
}
}
}

View File

@ -30,16 +30,20 @@ import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult;
import org.apache.cloudstack.framework.async.AsyncCallFuture;
import org.apache.cloudstack.framework.jobs.AsyncJobExecutionContext;
import org.apache.cloudstack.framework.jobs.AsyncJobManager;
import org.apache.cloudstack.framework.jobs.dao.AsyncJobJoinMapDao;
@ -48,6 +52,8 @@ import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@ -63,6 +69,7 @@ import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
import com.cloud.configuration.Resource;
import com.cloud.configuration.Resource.ResourceType;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.exception.InvalidParameterValueException;
@ -73,6 +80,7 @@ import com.cloud.org.Grouping;
import com.cloud.serializer.GsonHelper;
import com.cloud.storage.Volume.Type;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.storage.snapshot.SnapshotManager;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.AccountVO;
@ -81,6 +89,7 @@ import com.cloud.user.User;
import com.cloud.user.UserVO;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.fsm.NoTransitionException;
import com.cloud.vm.UserVmManager;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.VirtualMachine;
@ -97,13 +106,17 @@ public class VolumeApiServiceImplTest {
@InjectMocks
private VolumeApiServiceImpl volumeApiServiceImpl;
@Mock
private VolumeDao _volumeDao;
private SnapshotManager snapshotManagerMock;
@Mock
private AccountManager _accountMgr;
private VolumeDataStoreDao volumeDataStoreDaoMock;
@Mock
private UserVmDao _userVmDao;
private VolumeDao volumeDaoMock;
@Mock
private PrimaryDataStoreDao _storagePoolDao;
private AccountManager accountManagerMock;
@Mock
private UserVmDao userVmDaoMock;
@Mock
private PrimaryDataStoreDao primaryDataStoreDaoMock;
@Mock
private VMSnapshotDao _vmSnapshotDao;
@Mock
@ -111,7 +124,7 @@ public class VolumeApiServiceImplTest {
@Mock
private AsyncJobJoinMapDao _joinMapDao;
@Mock
private VolumeDataFactory _volFactory;
private VolumeDataFactory volumeDataFactoryMock;
@Mock
private VMInstanceDao _vmInstanceDao;
@Mock
@ -119,7 +132,7 @@ public class VolumeApiServiceImplTest {
@Mock
private SnapshotInfo snapshotInfoMock;
@Mock
private VolumeService volService;
private VolumeService volumeServiceMock;
@Mock
private CreateVolumeCmd createVol;
@Mock
@ -127,7 +140,7 @@ public class VolumeApiServiceImplTest {
@Mock
private DataCenterDao _dcDao;
@Mock
private ResourceLimitService _resourceLimitMgr;
private ResourceLimitService resourceLimitServiceMock;
@Mock
private AccountDao _accountDao;
@Mock
@ -142,10 +155,22 @@ public class VolumeApiServiceImplTest {
private StoragePool storagePoolMock;
private long storagePoolMockId = 1;
@Mock
private VolumeVO volumeVOMock;
@Mock
private DiskOfferingVO newDiskOfferingMock;
@Mock
private VolumeVO volumeVoMock;
@Mock
private Account accountMock;
@Mock
private VolumeDataStoreVO volumeDataStoreVoMock;
@Mock
private AsyncCallFuture<VolumeApiResult> asyncCallFutureVolumeapiResultMock;
private long accountMockId = 456l;
private long volumeMockId = 12313l;
private long vmInstanceMockId = 1123l;
private long volumeSizeMock = 456789921939l;
@Before
public void before() throws Exception {
Mockito.when(storagePoolMock.getId()).thenReturn(storagePoolMockId);
@ -167,50 +192,50 @@ public class VolumeApiServiceImplTest {
try {
// volume of running vm id=1
VolumeVO volumeOfRunningVm = new VolumeVO("root", 1L, 1L, 1L, 1L, 1L, "root", "root", Storage.ProvisioningType.THIN, 1, null, null, "root", Volume.Type.ROOT);
when(_volumeDao.findById(1L)).thenReturn(volumeOfRunningVm);
when(volumeDaoMock.findById(1L)).thenReturn(volumeOfRunningVm);
UserVmVO runningVm = new UserVmVO(1L, "vm", "vm", 1, HypervisorType.XenServer, 1L, false, false, 1L, 1L, 1, 1L, null, "vm", null);
runningVm.setState(State.Running);
runningVm.setDataCenterId(1L);
when(_userVmDao.findById(1L)).thenReturn(runningVm);
when(userVmDaoMock.findById(1L)).thenReturn(runningVm);
// volume of stopped vm id=2
VolumeVO volumeOfStoppedVm = new VolumeVO("root", 1L, 1L, 1L, 1L, 2L, "root", "root", Storage.ProvisioningType.THIN, 1, null, null, "root", Volume.Type.ROOT);
volumeOfStoppedVm.setPoolId(1L);
when(_volumeDao.findById(2L)).thenReturn(volumeOfStoppedVm);
when(volumeDaoMock.findById(2L)).thenReturn(volumeOfStoppedVm);
UserVmVO stoppedVm = new UserVmVO(2L, "vm", "vm", 1, HypervisorType.XenServer, 1L, false, false, 1L, 1L, 1, 1L, null, "vm", null);
stoppedVm.setState(State.Stopped);
stoppedVm.setDataCenterId(1L);
when(_userVmDao.findById(2L)).thenReturn(stoppedVm);
when(userVmDaoMock.findById(2L)).thenReturn(stoppedVm);
// volume of hyperV vm id=3
UserVmVO hyperVVm = new UserVmVO(3L, "vm", "vm", 1, HypervisorType.Hyperv, 1L, false, false, 1L, 1L, 1, 1L, null, "vm", null);
hyperVVm.setState(State.Stopped);
hyperVVm.setDataCenterId(1L);
when(_userVmDao.findById(3L)).thenReturn(hyperVVm);
when(userVmDaoMock.findById(3L)).thenReturn(hyperVVm);
VolumeVO volumeOfStoppeHyperVVm = new VolumeVO("root", 1L, 1L, 1L, 1L, 3L, "root", "root", Storage.ProvisioningType.THIN, 1, null, null, "root", Volume.Type.ROOT);
volumeOfStoppeHyperVVm.setPoolId(1L);
when(_volumeDao.findById(3L)).thenReturn(volumeOfStoppeHyperVVm);
when(volumeDaoMock.findById(3L)).thenReturn(volumeOfStoppeHyperVVm);
StoragePoolVO unmanagedPool = new StoragePoolVO();
when(_storagePoolDao.findById(1L)).thenReturn(unmanagedPool);
when(primaryDataStoreDaoMock.findById(1L)).thenReturn(unmanagedPool);
// volume of managed pool id=4
StoragePoolVO managedPool = new StoragePoolVO();
managedPool.setManaged(true);
when(_storagePoolDao.findById(2L)).thenReturn(managedPool);
when(primaryDataStoreDaoMock.findById(2L)).thenReturn(managedPool);
VolumeVO managedPoolVolume = new VolumeVO("root", 1L, 1L, 1L, 1L, 2L, "root", "root", Storage.ProvisioningType.THIN, 1, null, null, "root", Volume.Type.ROOT);
managedPoolVolume.setPoolId(2L);
when(_volumeDao.findById(4L)).thenReturn(managedPoolVolume);
when(volumeDaoMock.findById(4L)).thenReturn(managedPoolVolume);
// non-root non-datadisk volume
VolumeInfo volumeWithIncorrectVolumeType = Mockito.mock(VolumeInfo.class);
when(volumeWithIncorrectVolumeType.getId()).thenReturn(5L);
when(volumeWithIncorrectVolumeType.getVolumeType()).thenReturn(Volume.Type.ISO);
when(_volFactory.getVolume(5L)).thenReturn(volumeWithIncorrectVolumeType);
when(volumeDataFactoryMock.getVolume(5L)).thenReturn(volumeWithIncorrectVolumeType);
// correct root volume
VolumeInfo correctRootVolume = Mockito.mock(VolumeInfo.class);
@ -221,10 +246,10 @@ public class VolumeApiServiceImplTest {
when(correctRootVolume.getState()).thenReturn(Volume.State.Ready);
when(correctRootVolume.getTemplateId()).thenReturn(null);
when(correctRootVolume.getPoolId()).thenReturn(1L);
when(_volFactory.getVolume(6L)).thenReturn(correctRootVolume);
when(volumeDataFactoryMock.getVolume(6L)).thenReturn(correctRootVolume);
VolumeVO correctRootVolumeVO = new VolumeVO("root", 1L, 1L, 1L, 1L, 2L, "root", "root", Storage.ProvisioningType.THIN, 1, null, null, "root", Volume.Type.ROOT);
when(_volumeDao.findById(6L)).thenReturn(correctRootVolumeVO);
when(volumeDaoMock.findById(6L)).thenReturn(correctRootVolumeVO);
// managed root volume
VolumeInfo managedVolume = Mockito.mock(VolumeInfo.class);
@ -233,21 +258,21 @@ public class VolumeApiServiceImplTest {
when(managedVolume.getVolumeType()).thenReturn(Volume.Type.ROOT);
when(managedVolume.getInstanceId()).thenReturn(null);
when(managedVolume.getPoolId()).thenReturn(2L);
when(_volFactory.getVolume(7L)).thenReturn(managedVolume);
when(volumeDataFactoryMock.getVolume(7L)).thenReturn(managedVolume);
VolumeVO managedVolume1 = new VolumeVO("root", 1L, 1L, 1L, 1L, 2L, "root", "root", Storage.ProvisioningType.THIN, 1, null, null, "root", Volume.Type.ROOT);
managedVolume1.setPoolId(2L);
managedVolume1.setDataCenterId(1L);
when(_volumeDao.findById(7L)).thenReturn(managedVolume1);
when(volumeDaoMock.findById(7L)).thenReturn(managedVolume1);
// vm having root volume
UserVmVO vmHavingRootVolume = new UserVmVO(4L, "vm", "vm", 1, HypervisorType.XenServer, 1L, false, false, 1L, 1L, 1, 1L, null, "vm", null);
vmHavingRootVolume.setState(State.Stopped);
vmHavingRootVolume.setDataCenterId(1L);
when(_userVmDao.findById(4L)).thenReturn(vmHavingRootVolume);
when(userVmDaoMock.findById(4L)).thenReturn(vmHavingRootVolume);
List<VolumeVO> vols = new ArrayList<VolumeVO>();
vols.add(new VolumeVO());
when(_volumeDao.findByInstanceAndDeviceId(4L, 0L)).thenReturn(vols);
when(volumeDaoMock.findByInstanceAndDeviceId(4L, 0L)).thenReturn(vols);
// volume in uploaded state
VolumeInfo uploadedVolume = Mockito.mock(VolumeInfo.class);
@ -257,13 +282,13 @@ public class VolumeApiServiceImplTest {
when(uploadedVolume.getInstanceId()).thenReturn(null);
when(uploadedVolume.getPoolId()).thenReturn(1L);
when(uploadedVolume.getState()).thenReturn(Volume.State.Uploaded);
when(_volFactory.getVolume(8L)).thenReturn(uploadedVolume);
when(volumeDataFactoryMock.getVolume(8L)).thenReturn(uploadedVolume);
VolumeVO upVolume = new VolumeVO("root", 1L, 1L, 1L, 1L, 2L, "root", "root", Storage.ProvisioningType.THIN, 1, null, null, "root", Volume.Type.ROOT);
upVolume.setPoolId(1L);
upVolume.setDataCenterId(1L);
upVolume.setState(Volume.State.Uploaded);
when(_volumeDao.findById(8L)).thenReturn(upVolume);
when(volumeDaoMock.findById(8L)).thenReturn(upVolume);
// helper dao methods mock
when(_vmSnapshotDao.findByVm(any(Long.class))).thenReturn(new ArrayList<VMSnapshotVO>());
@ -279,7 +304,7 @@ public class VolumeApiServiceImplTest {
}
// helper methods mock
doNothing().when(_accountMgr).checkAccess(any(Account.class), any(AccessType.class), any(Boolean.class), any(ControlledEntity.class));
doNothing().when(accountManagerMock).checkAccess(any(Account.class), any(AccessType.class), any(Boolean.class), any(ControlledEntity.class));
doNothing().when(_jobMgr).updateAsyncJobAttachment(any(Long.class), any(String.class), any(Long.class));
when(_jobMgr.submitAsyncJob(any(AsyncJobVO.class), any(String.class), any(Long.class))).thenReturn(1L);
}
@ -374,7 +399,7 @@ public class VolumeApiServiceImplTest {
// volume not Ready
@Test(expected = InvalidParameterValueException.class)
public void testTakeSnapshotF1() throws ResourceAllocationException {
when(_volFactory.getVolume(anyLong())).thenReturn(volumeInfoMock);
when(volumeDataFactoryMock.getVolume(anyLong())).thenReturn(volumeInfoMock);
when(volumeInfoMock.getState()).thenReturn(Volume.State.Allocated);
when(volumeInfoMock.getPoolId()).thenReturn(1L);
volumeApiServiceImpl.takeSnapshot(5L, Snapshot.MANUAL_POLICY_ID, 3L, null, false, null, false);
@ -382,11 +407,11 @@ public class VolumeApiServiceImplTest {
@Test
public void testTakeSnapshotF2() throws ResourceAllocationException {
when(_volFactory.getVolume(anyLong())).thenReturn(volumeInfoMock);
when(volumeDataFactoryMock.getVolume(anyLong())).thenReturn(volumeInfoMock);
when(volumeInfoMock.getState()).thenReturn(Volume.State.Ready);
when(volumeInfoMock.getInstanceId()).thenReturn(null);
when(volumeInfoMock.getPoolId()).thenReturn(1L);
when(volService.takeSnapshot(Mockito.any(VolumeInfo.class))).thenReturn(snapshotInfoMock);
when(volumeServiceMock.takeSnapshot(Mockito.any(VolumeInfo.class))).thenReturn(snapshotInfoMock);
volumeApiServiceImpl.takeSnapshot(5L, Snapshot.MANUAL_POLICY_ID, 3L, null, false, null, false);
}
@ -422,7 +447,7 @@ public class VolumeApiServiceImplTest {
@Test
public void testUpdateMissingRootDiskControllerWithValidChainInfo() {
UserVmVO vm = _userVmDao.findById(1L);
UserVmVO vm = userVmDaoMock.findById(1L);
Mockito.doNothing().when(userVmManager).persistDeviceBusInfo(any(UserVmVO.class), eq("scsi"));
volumeApiServiceImpl.updateMissingRootDiskController(vm, "{\"diskDeviceBusName\":\"scsi0:0\",\"diskChain\":[\"[somedatastore] i-3-VM-somePath/ROOT-1.vmdk\"]}");
@ -451,7 +476,7 @@ public class VolumeApiServiceImplTest {
*/
@Test
public void testResourceLimitCheckForUploadedVolume() throws NoSuchFieldException, IllegalAccessException, ResourceAllocationException {
doThrow(new ResourceAllocationException("primary storage resource limit check failed", Resource.ResourceType.primary_storage)).when(_resourceLimitMgr).checkResourceLimit(any(AccountVO.class),
doThrow(new ResourceAllocationException("primary storage resource limit check failed", Resource.ResourceType.primary_storage)).when(resourceLimitServiceMock).checkResourceLimit(any(AccountVO.class),
any(Resource.ResourceType.class), any(Long.class));
UserVmVO vm = Mockito.mock(UserVmVO.class);
VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class);
@ -459,12 +484,12 @@ public class VolumeApiServiceImplTest {
when(volumeToAttach.getDataCenterId()).thenReturn(34L);
when(volumeToAttach.getVolumeType()).thenReturn(Volume.Type.DATADISK);
when(volumeToAttach.getInstanceId()).thenReturn(null);
when(_userVmDao.findById(anyLong())).thenReturn(vm);
when(userVmDaoMock.findById(anyLong())).thenReturn(vm);
when(vm.getType()).thenReturn(VirtualMachine.Type.User);
when(vm.getState()).thenReturn(State.Running);
when(vm.getDataCenterId()).thenReturn(34L);
when(_volumeDao.findByInstanceAndType(anyLong(), any(Volume.Type.class))).thenReturn(new ArrayList<>(10));
when(_volFactory.getVolume(9L)).thenReturn(volumeToAttach);
when(volumeDaoMock.findByInstanceAndType(anyLong(), any(Volume.Type.class))).thenReturn(new ArrayList<>(10));
when(volumeDataFactoryMock.getVolume(9L)).thenReturn(volumeToAttach);
when(volumeToAttach.getState()).thenReturn(Volume.State.Uploaded);
DataCenterVO zoneWithDisabledLocalStorage = Mockito.mock(DataCenterVO.class);
when(_dcDao.findById(anyLong())).thenReturn(zoneWithDisabledLocalStorage);
@ -511,39 +536,39 @@ public class VolumeApiServiceImplTest {
@Test
public void validateConditionsToReplaceDiskOfferingOfVolumeTestNoNewDiskOffering() {
volumeApiServiceImpl.validateConditionsToReplaceDiskOfferingOfVolume(volumeVOMock, null, storagePoolMock);
volumeApiServiceImpl.validateConditionsToReplaceDiskOfferingOfVolume(volumeVoMock, null, storagePoolMock);
Mockito.verify(volumeVOMock, times(0)).getVolumeType();
Mockito.verify(volumeVoMock, times(0)).getVolumeType();
}
@Test
public void validateConditionsToReplaceDiskOfferingOfVolumeTestRootVolume() {
Mockito.when(volumeVOMock.getVolumeType()).thenReturn(Type.ROOT);
Mockito.when(volumeVoMock.getVolumeType()).thenReturn(Type.ROOT);
volumeApiServiceImpl.validateConditionsToReplaceDiskOfferingOfVolume(volumeVOMock, newDiskOfferingMock, storagePoolMock);
volumeApiServiceImpl.validateConditionsToReplaceDiskOfferingOfVolume(volumeVoMock, newDiskOfferingMock, storagePoolMock);
}
@Test(expected = InvalidParameterValueException.class)
public void validateConditionsToReplaceDiskOfferingOfVolumeTestTargetPoolSharedDiskOfferingLocal() {
Mockito.when(volumeVOMock.getVolumeType()).thenReturn(Type.DATADISK);
Mockito.when(volumeVoMock.getVolumeType()).thenReturn(Type.DATADISK);
Mockito.when(newDiskOfferingMock.getUseLocalStorage()).thenReturn(true);
Mockito.when(storagePoolMock.isShared()).thenReturn(true);
volumeApiServiceImpl.validateConditionsToReplaceDiskOfferingOfVolume(volumeVOMock, newDiskOfferingMock, storagePoolMock);
volumeApiServiceImpl.validateConditionsToReplaceDiskOfferingOfVolume(volumeVoMock, newDiskOfferingMock, storagePoolMock);
}
@Test(expected = InvalidParameterValueException.class)
public void validateConditionsToReplaceDiskOfferingOfVolumeTestTargetPoolLocalDiskOfferingShared() {
Mockito.when(volumeVOMock.getVolumeType()).thenReturn(Type.DATADISK);
Mockito.when(volumeVoMock.getVolumeType()).thenReturn(Type.DATADISK);
Mockito.when(newDiskOfferingMock.isShared()).thenReturn(true);
Mockito.when(storagePoolMock.isLocal()).thenReturn(true);
volumeApiServiceImpl.validateConditionsToReplaceDiskOfferingOfVolume(volumeVOMock, newDiskOfferingMock, storagePoolMock);
volumeApiServiceImpl.validateConditionsToReplaceDiskOfferingOfVolume(volumeVoMock, newDiskOfferingMock, storagePoolMock);
}
@Test(expected = InvalidParameterValueException.class)
public void validateConditionsToReplaceDiskOfferingOfVolumeTestTagsDoNotMatch() {
Mockito.when(volumeVOMock.getVolumeType()).thenReturn(Type.DATADISK);
Mockito.when(volumeVoMock.getVolumeType()).thenReturn(Type.DATADISK);
Mockito.when(newDiskOfferingMock.getUseLocalStorage()).thenReturn(false);
Mockito.when(storagePoolMock.isShared()).thenReturn(true);
@ -555,12 +580,12 @@ public class VolumeApiServiceImplTest {
Mockito.doReturn(null).when(volumeApiServiceImpl).getStoragePoolTags(storagePoolMock);
volumeApiServiceImpl.validateConditionsToReplaceDiskOfferingOfVolume(volumeVOMock, newDiskOfferingMock, storagePoolMock);
volumeApiServiceImpl.validateConditionsToReplaceDiskOfferingOfVolume(volumeVoMock, newDiskOfferingMock, storagePoolMock);
}
@Test
public void validateConditionsToReplaceDiskOfferingOfVolumeTestEverythingWorking() {
Mockito.when(volumeVOMock.getVolumeType()).thenReturn(Type.DATADISK);
Mockito.when(volumeVoMock.getVolumeType()).thenReturn(Type.DATADISK);
Mockito.when(newDiskOfferingMock.getUseLocalStorage()).thenReturn(false);
Mockito.when(storagePoolMock.isShared()).thenReturn(true);
@ -572,9 +597,9 @@ public class VolumeApiServiceImplTest {
Mockito.doReturn("tag1").when(volumeApiServiceImpl).getStoragePoolTags(storagePoolMock);
volumeApiServiceImpl.validateConditionsToReplaceDiskOfferingOfVolume(volumeVOMock, newDiskOfferingMock, storagePoolMock);
volumeApiServiceImpl.validateConditionsToReplaceDiskOfferingOfVolume(volumeVoMock, newDiskOfferingMock, storagePoolMock);
InOrder inOrder = Mockito.inOrder(volumeVOMock, newDiskOfferingMock, storagePoolMock, volumeApiServiceImpl);
InOrder inOrder = Mockito.inOrder(volumeVoMock, newDiskOfferingMock, storagePoolMock, volumeApiServiceImpl);
inOrder.verify(storagePoolMock).isShared();
inOrder.verify(newDiskOfferingMock).getUseLocalStorage();
inOrder.verify(storagePoolMock).isLocal();
@ -582,7 +607,385 @@ public class VolumeApiServiceImplTest {
inOrder.verify(volumeApiServiceImpl).getStoragePoolTags(storagePoolMock);
inOrder.verify(newDiskOfferingMock).getTags();
inOrder.verify(volumeVOMock).getSize();
inOrder.verify(volumeVoMock).getSize();
inOrder.verify(newDiskOfferingMock).getDiskSize();
}
@Test(expected = InvalidParameterValueException.class)
public void retrieveAndValidateVolumeTestVolumeNotFound() {
Mockito.doReturn(null).when(volumeDaoMock).findById(volumeMockId);
volumeApiServiceImpl.retrieveAndValidateVolume(volumeMockId, accountMock);
}
@Test(expected = InvalidParameterValueException.class)
public void retrieveAndValidateVolumeTestCannotOperateOnVolumeDueToSnapshot() {
Mockito.doReturn(volumeVoMock).when(volumeDaoMock).findById(volumeMockId);
Mockito.doReturn(false).when(snapshotManagerMock).canOperateOnVolume(volumeVoMock);
volumeApiServiceImpl.retrieveAndValidateVolume(volumeMockId, accountMock);
}
@Test(expected = InvalidParameterValueException.class)
public void retrieveAndValidateVolumeTestVolumePluggedIntoVm() {
Mockito.doReturn(volumeVoMock).when(volumeDaoMock).findById(volumeMockId);
Mockito.doReturn(vmInstanceMockId).when(volumeVoMock).getInstanceId();
Mockito.doReturn(true).when(snapshotManagerMock).canOperateOnVolume(volumeVoMock);
volumeApiServiceImpl.retrieveAndValidateVolume(volumeMockId, accountMock);
}
@Test(expected = InvalidParameterValueException.class)
public void retrieveAndValidateVolumeTestStateUploadOpAndDownloadInProgress() {
Mockito.doReturn(volumeVoMock).when(volumeDaoMock).findById(volumeMockId);
Mockito.doReturn(null).when(volumeVoMock).getInstanceId();
Mockito.doReturn(Volume.State.UploadOp).when(volumeVoMock).getState();
Mockito.doReturn(true).when(snapshotManagerMock).canOperateOnVolume(volumeVoMock);
Mockito.doReturn(volumeDataStoreVoMock).when(volumeDataStoreDaoMock).findByVolume(volumeMockId);
Mockito.doReturn(VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS).when(volumeDataStoreVoMock).getDownloadState();
volumeApiServiceImpl.retrieveAndValidateVolume(volumeMockId, accountMock);
}
@Test(expected = InvalidParameterValueException.class)
public void retrieveAndValidateVolumeTestStateNotUploaded() {
Mockito.doReturn(volumeVoMock).when(volumeDaoMock).findById(volumeMockId);
Mockito.doReturn(null).when(volumeVoMock).getInstanceId();
Mockito.doReturn(Volume.State.NotUploaded).when(volumeVoMock).getState();
Mockito.doReturn(true).when(snapshotManagerMock).canOperateOnVolume(volumeVoMock);
volumeApiServiceImpl.retrieveAndValidateVolume(volumeMockId, accountMock);
}
@Test(expected = InvalidParameterValueException.class)
public void retrieveAndValidateVolumeTestUploadInProgress() {
Mockito.doReturn(volumeVoMock).when(volumeDaoMock).findById(volumeMockId);
Mockito.doReturn(null).when(volumeVoMock).getInstanceId();
Mockito.doReturn(Volume.State.UploadInProgress).when(volumeVoMock).getState();
Mockito.doReturn(true).when(snapshotManagerMock).canOperateOnVolume(volumeVoMock);
volumeApiServiceImpl.retrieveAndValidateVolume(volumeMockId, accountMock);
}
@Test
public void retrieveAndValidateVolumeTest() {
Mockito.doReturn(volumeVoMock).when(volumeDaoMock).findById(volumeMockId);
Mockito.doReturn(null).when(volumeVoMock).getInstanceId();
Mockito.doReturn(Volume.State.Ready).when(volumeVoMock).getState();
Mockito.doReturn(true).when(snapshotManagerMock).canOperateOnVolume(volumeVoMock);
Mockito.doNothing().when(accountManagerMock).checkAccess(accountMock, null, true, volumeVoMock);
volumeApiServiceImpl.retrieveAndValidateVolume(volumeMockId, accountMock);
Mockito.verify(accountManagerMock).checkAccess(accountMock, null, true, volumeVoMock);
}
@Test
public void destroyVolumeIfPossibleTestVolumeStateIsDestroy() {
Mockito.doReturn(Volume.State.Destroy).when(volumeVoMock).getState();
configureMocksForTestDestroyVolumeWhenVolume();
volumeApiServiceImpl.destroyVolumeIfPossible(volumeVoMock);
verifyMocksForTestDestroyVolumeWhenVolumeIsNotInRightState();
}
@Test
public void destroyVolumeIfPossibleTestVolumeStateIsExpunging() {
Mockito.doReturn(Volume.State.Expunging).when(volumeVoMock).getState();
configureMocksForTestDestroyVolumeWhenVolume();
volumeApiServiceImpl.destroyVolumeIfPossible(volumeVoMock);
verifyMocksForTestDestroyVolumeWhenVolumeIsNotInRightState();
}
@Test
public void destroyVolumeIfPossibleTestVolumeStateIsExpunged() {
Mockito.doReturn(Volume.State.Expunged).when(volumeVoMock).getState();
configureMocksForTestDestroyVolumeWhenVolume();
volumeApiServiceImpl.destroyVolumeIfPossible(volumeVoMock);
verifyMocksForTestDestroyVolumeWhenVolumeIsNotInRightState();
}
@Test
public void destroyVolumeIfPossibleTestVolumeStateReady() {
Mockito.doReturn(Volume.State.Ready).when(volumeVoMock).getState();
configureMocksForTestDestroyVolumeWhenVolume();
volumeApiServiceImpl.destroyVolumeIfPossible(volumeVoMock);
Mockito.verify(volumeServiceMock, Mockito.times(1)).destroyVolume(volumeMockId);
Mockito.verify(resourceLimitServiceMock, Mockito.times(1)).decrementResourceCount(accountMockId, ResourceType.volume, true);
Mockito.verify(resourceLimitServiceMock, Mockito.times(1)).decrementResourceCount(accountMockId, ResourceType.primary_storage, true, volumeSizeMock);
}
private void verifyMocksForTestDestroyVolumeWhenVolumeIsNotInRightState() {
Mockito.verify(volumeServiceMock, Mockito.times(0)).destroyVolume(volumeMockId);
Mockito.verify(resourceLimitServiceMock, Mockito.times(0)).decrementResourceCount(accountMockId, ResourceType.volume, true);
Mockito.verify(resourceLimitServiceMock, Mockito.times(0)).decrementResourceCount(accountMockId, ResourceType.primary_storage, true, volumeSizeMock);
}
private void configureMocksForTestDestroyVolumeWhenVolume() {
Mockito.doReturn(accountMockId).when(volumeVoMock).getAccountId();
Mockito.doReturn(true).when(volumeVoMock).isDisplayVolume();
Mockito.doNothing().when(volumeServiceMock).destroyVolume(volumeMockId);
Mockito.doNothing().when(resourceLimitServiceMock).decrementResourceCount(accountMockId, ResourceType.volume, true);
Mockito.doNothing().when(resourceLimitServiceMock).decrementResourceCount(accountMockId, ResourceType.primary_storage, true, volumeSizeMock);
}
@Test
public void expungeVolumesInPrimaryStorageIfNeededTestVolumeNotInPrimaryDataStore() throws InterruptedException, ExecutionException {
Mockito.doReturn(asyncCallFutureVolumeapiResultMock).when(volumeServiceMock).expungeVolumeAsync(volumeInfoMock);
Mockito.doReturn(null).when(volumeDataFactoryMock).getVolume(volumeMockId, DataStoreRole.Primary);
volumeApiServiceImpl.expungeVolumesInPrimaryStorageIfNeeded(volumeVoMock);
Mockito.verify(volumeServiceMock, Mockito.times(0)).expungeVolumeAsync(volumeInfoMock);
Mockito.verify(asyncCallFutureVolumeapiResultMock, Mockito.times(0)).get();
}
@Test
public void expungeVolumesInPrimaryStorageIfNeededTestVolumeInPrimaryDataStore() throws InterruptedException, ExecutionException {
Mockito.doReturn(asyncCallFutureVolumeapiResultMock).when(volumeServiceMock).expungeVolumeAsync(volumeInfoMock);
Mockito.doReturn(volumeInfoMock).when(volumeDataFactoryMock).getVolume(volumeMockId, DataStoreRole.Primary);
volumeApiServiceImpl.expungeVolumesInPrimaryStorageIfNeeded(volumeVoMock);
Mockito.verify(volumeServiceMock, Mockito.times(1)).expungeVolumeAsync(volumeInfoMock);
Mockito.verify(asyncCallFutureVolumeapiResultMock, Mockito.times(1)).get();
}
@Test(expected = InterruptedException.class)
public void expungeVolumesInPrimaryStorageIfNeededTestThrowingInterruptedException() throws InterruptedException, ExecutionException {
Mockito.doReturn(asyncCallFutureVolumeapiResultMock).when(volumeServiceMock).expungeVolumeAsync(volumeInfoMock);
Mockito.doReturn(volumeInfoMock).when(volumeDataFactoryMock).getVolume(volumeMockId, DataStoreRole.Primary);
Mockito.doThrow(InterruptedException.class).when(asyncCallFutureVolumeapiResultMock).get();
volumeApiServiceImpl.expungeVolumesInPrimaryStorageIfNeeded(volumeVoMock);
}
@Test(expected = ExecutionException.class)
public void expungeVolumesInPrimaryStorageIfNeededTestThrowingExecutionException() throws InterruptedException, ExecutionException {
Mockito.doReturn(asyncCallFutureVolumeapiResultMock).when(volumeServiceMock).expungeVolumeAsync(volumeInfoMock);
Mockito.doReturn(volumeInfoMock).when(volumeDataFactoryMock).getVolume(volumeMockId, DataStoreRole.Primary);
Mockito.doThrow(ExecutionException.class).when(asyncCallFutureVolumeapiResultMock).get();
volumeApiServiceImpl.expungeVolumesInPrimaryStorageIfNeeded(volumeVoMock);
}
@Test
public void expungeVolumesInSecondaryStorageIfNeededTestVolumeNotFoundInSecondaryStorage() throws InterruptedException, ExecutionException {
Mockito.doReturn(asyncCallFutureVolumeapiResultMock).when(volumeServiceMock).expungeVolumeAsync(volumeInfoMock);
Mockito.doReturn(null).when(volumeDataFactoryMock).getVolume(volumeMockId, DataStoreRole.Image);
Mockito.doNothing().when(resourceLimitServiceMock).decrementResourceCount(accountMockId, ResourceType.secondary_storage, volumeSizeMock);
Mockito.doReturn(accountMockId).when(volumeInfoMock).getAccountId();
Mockito.doReturn(volumeSizeMock).when(volumeInfoMock).getSize();
volumeApiServiceImpl.expungeVolumesInSecondaryStorageIfNeeded(volumeVoMock);
Mockito.verify(volumeServiceMock, Mockito.times(0)).expungeVolumeAsync(volumeInfoMock);
Mockito.verify(asyncCallFutureVolumeapiResultMock, Mockito.times(0)).get();
Mockito.verify(resourceLimitServiceMock, Mockito.times(0)).decrementResourceCount(accountMockId, ResourceType.secondary_storage, volumeSizeMock);
}
@Test
public void expungeVolumesInSecondaryStorageIfNeededTestVolumeFoundInSecondaryStorage() throws InterruptedException, ExecutionException {
Mockito.doReturn(asyncCallFutureVolumeapiResultMock).when(volumeServiceMock).expungeVolumeAsync(volumeInfoMock);
Mockito.doReturn(volumeInfoMock).when(volumeDataFactoryMock).getVolume(volumeMockId, DataStoreRole.Image);
Mockito.doNothing().when(resourceLimitServiceMock).decrementResourceCount(accountMockId, ResourceType.secondary_storage, volumeSizeMock);
Mockito.doReturn(accountMockId).when(volumeInfoMock).getAccountId();
Mockito.doReturn(volumeSizeMock).when(volumeInfoMock).getSize();
volumeApiServiceImpl.expungeVolumesInSecondaryStorageIfNeeded(volumeVoMock);
Mockito.verify(volumeServiceMock, Mockito.times(1)).expungeVolumeAsync(volumeInfoMock);
Mockito.verify(asyncCallFutureVolumeapiResultMock, Mockito.times(1)).get();
Mockito.verify(resourceLimitServiceMock, Mockito.times(1)).decrementResourceCount(accountMockId, ResourceType.secondary_storage, volumeSizeMock);
}
@Test(expected = InterruptedException.class)
public void expungeVolumesInSecondaryStorageIfNeededTestthrowinInterruptedException() throws InterruptedException, ExecutionException {
Mockito.doReturn(asyncCallFutureVolumeapiResultMock).when(volumeServiceMock).expungeVolumeAsync(volumeInfoMock);
Mockito.doReturn(volumeInfoMock).when(volumeDataFactoryMock).getVolume(volumeMockId, DataStoreRole.Image);
Mockito.doNothing().when(resourceLimitServiceMock).decrementResourceCount(accountMockId, ResourceType.secondary_storage, volumeSizeMock);
Mockito.doReturn(accountMockId).when(volumeInfoMock).getAccountId();
Mockito.doReturn(volumeSizeMock).when(volumeInfoMock).getSize();
Mockito.doThrow(InterruptedException.class).when(asyncCallFutureVolumeapiResultMock).get();
volumeApiServiceImpl.expungeVolumesInSecondaryStorageIfNeeded(volumeVoMock);
}
@Test(expected = ExecutionException.class)
public void expungeVolumesInSecondaryStorageIfNeededTestthrowinExecutionException() throws InterruptedException, ExecutionException {
Mockito.doReturn(asyncCallFutureVolumeapiResultMock).when(volumeServiceMock).expungeVolumeAsync(volumeInfoMock);
Mockito.doReturn(volumeInfoMock).when(volumeDataFactoryMock).getVolume(volumeMockId, DataStoreRole.Image);
Mockito.doNothing().when(resourceLimitServiceMock).decrementResourceCount(accountMockId, ResourceType.secondary_storage, volumeSizeMock);
Mockito.doReturn(accountMockId).when(volumeInfoMock).getAccountId();
Mockito.doReturn(volumeSizeMock).when(volumeInfoMock).getSize();
Mockito.doThrow(ExecutionException.class).when(asyncCallFutureVolumeapiResultMock).get();
volumeApiServiceImpl.expungeVolumesInSecondaryStorageIfNeeded(volumeVoMock);
}
@Test
public void cleanVolumesCacheTest() {
List<VolumeInfo> volumeInfos = new ArrayList<>();
VolumeInfo volumeInfoMock1 = Mockito.mock(VolumeInfo.class);
VolumeInfo volumeInfoMock2 = Mockito.mock(VolumeInfo.class);
DataStore dataStoreMock1 = Mockito.mock(DataStore.class);
DataStore dataStoreMock2 = Mockito.mock(DataStore.class);
Mockito.doReturn(dataStoreMock1).when(volumeInfoMock1).getDataStore();
Mockito.doReturn(dataStoreMock2).when(volumeInfoMock2).getDataStore();
volumeInfos.add(volumeInfoMock1);
volumeInfos.add(volumeInfoMock2);
Mockito.doReturn(volumeInfos).when(volumeDataFactoryMock).listVolumeOnCache(volumeMockId);
volumeApiServiceImpl.cleanVolumesCache(volumeVoMock);
Mockito.verify(dataStoreMock1).getName();
Mockito.verify(dataStoreMock2).getName();
Mockito.verify(volumeInfoMock1).delete();
Mockito.verify(volumeInfoMock2).delete();
}
@Test
public void deleteVolumeTestVolumeStateAllocated() throws InterruptedException, ExecutionException, NoTransitionException {
Mockito.doReturn(Volume.State.Allocated).when(volumeVoMock).getState();
Mockito.doReturn(volumeVoMock).when(volumeApiServiceImpl).retrieveAndValidateVolume(volumeMockId, accountMock);
Mockito.doNothing().when(volumeApiServiceImpl).destroyVolumeIfPossible(volumeVoMock);
Mockito.doNothing().when(volumeApiServiceImpl).expungeVolumesInPrimaryStorageIfNeeded(volumeVoMock);
Mockito.doNothing().when(volumeApiServiceImpl).expungeVolumesInSecondaryStorageIfNeeded(volumeVoMock);
Mockito.doNothing().when(volumeApiServiceImpl).cleanVolumesCache(volumeVoMock);
Mockito.doReturn(true).when(volumeDaoMock).remove(volumeMockId);
Mockito.doReturn(true).when(volumeApiServiceImpl).stateTransitTo(volumeVoMock, Volume.Event.DestroyRequested);
boolean result = volumeApiServiceImpl.deleteVolume(volumeMockId, accountMock);
Assert.assertTrue(result);
Mockito.verify(volumeApiServiceImpl).retrieveAndValidateVolume(volumeMockId, accountMock);
Mockito.verify(volumeApiServiceImpl).destroyVolumeIfPossible(volumeVoMock);
Mockito.verify(volumeDaoMock).remove(volumeMockId);
Mockito.verify(volumeApiServiceImpl).stateTransitTo(volumeVoMock, Volume.Event.DestroyRequested);
Mockito.verify(volumeApiServiceImpl, Mockito.times(0)).expungeVolumesInPrimaryStorageIfNeeded(volumeVoMock);
Mockito.verify(volumeApiServiceImpl, Mockito.times(0)).expungeVolumesInSecondaryStorageIfNeeded(volumeVoMock);
Mockito.verify(volumeApiServiceImpl, Mockito.times(0)).cleanVolumesCache(volumeVoMock);
}
@Test
public void deleteVolumeTestVolumeStateReady() throws InterruptedException, ExecutionException, NoTransitionException {
Mockito.doReturn(Volume.State.Ready).when(volumeVoMock).getState();
Mockito.doReturn(volumeVoMock).when(volumeApiServiceImpl).retrieveAndValidateVolume(volumeMockId, accountMock);
Mockito.doNothing().when(volumeApiServiceImpl).destroyVolumeIfPossible(volumeVoMock);
Mockito.doNothing().when(volumeApiServiceImpl).expungeVolumesInPrimaryStorageIfNeeded(volumeVoMock);
Mockito.doNothing().when(volumeApiServiceImpl).expungeVolumesInSecondaryStorageIfNeeded(volumeVoMock);
Mockito.doNothing().when(volumeApiServiceImpl).cleanVolumesCache(volumeVoMock);
Mockito.doReturn(true).when(volumeDaoMock).remove(volumeMockId);
Mockito.doReturn(true).when(volumeApiServiceImpl).stateTransitTo(volumeVoMock, Volume.Event.DestroyRequested);
boolean result = volumeApiServiceImpl.deleteVolume(volumeMockId, accountMock);
Assert.assertTrue(result);
Mockito.verify(volumeApiServiceImpl).retrieveAndValidateVolume(volumeMockId, accountMock);
Mockito.verify(volumeApiServiceImpl).destroyVolumeIfPossible(volumeVoMock);
Mockito.verify(volumeDaoMock, Mockito.times(0)).remove(volumeMockId);
Mockito.verify(volumeApiServiceImpl, Mockito.times(0)).stateTransitTo(volumeVoMock, Volume.Event.DestroyRequested);
Mockito.verify(volumeApiServiceImpl, Mockito.times(1)).expungeVolumesInPrimaryStorageIfNeeded(volumeVoMock);
Mockito.verify(volumeApiServiceImpl, Mockito.times(1)).expungeVolumesInSecondaryStorageIfNeeded(volumeVoMock);
Mockito.verify(volumeApiServiceImpl, Mockito.times(1)).cleanVolumesCache(volumeVoMock);
}
@Test
public void deleteVolumeTestVolumeStateReadyThrowingInterruptedException() throws InterruptedException, ExecutionException, NoTransitionException {
Mockito.doReturn(Volume.State.Ready).when(volumeVoMock).getState();
Mockito.doReturn(volumeVoMock).when(volumeApiServiceImpl).retrieveAndValidateVolume(volumeMockId, accountMock);
Mockito.doNothing().when(volumeApiServiceImpl).destroyVolumeIfPossible(volumeVoMock);
Mockito.doThrow(InterruptedException.class).when(volumeApiServiceImpl).expungeVolumesInPrimaryStorageIfNeeded(volumeVoMock);
Mockito.doReturn(true).when(volumeDaoMock).remove(volumeMockId);
Mockito.doReturn(true).when(volumeApiServiceImpl).stateTransitTo(volumeVoMock, Volume.Event.DestroyRequested);
boolean result = volumeApiServiceImpl.deleteVolume(volumeMockId, accountMock);
Assert.assertFalse(result);
Mockito.verify(volumeApiServiceImpl).retrieveAndValidateVolume(volumeMockId, accountMock);
Mockito.verify(volumeApiServiceImpl).destroyVolumeIfPossible(volumeVoMock);
Mockito.verify(volumeDaoMock, Mockito.times(0)).remove(volumeMockId);
Mockito.verify(volumeApiServiceImpl, Mockito.times(0)).stateTransitTo(volumeVoMock, Volume.Event.DestroyRequested);
}
@Test
public void deleteVolumeTestVolumeStateReadyThrowingExecutionException() throws InterruptedException, ExecutionException, NoTransitionException {
Mockito.doReturn(Volume.State.Ready).when(volumeVoMock).getState();
Mockito.doReturn(volumeVoMock).when(volumeApiServiceImpl).retrieveAndValidateVolume(volumeMockId, accountMock);
Mockito.doNothing().when(volumeApiServiceImpl).destroyVolumeIfPossible(volumeVoMock);
Mockito.doThrow(ExecutionException.class).when(volumeApiServiceImpl).expungeVolumesInPrimaryStorageIfNeeded(volumeVoMock);
Mockito.doReturn(true).when(volumeDaoMock).remove(volumeMockId);
Mockito.doReturn(true).when(volumeApiServiceImpl).stateTransitTo(volumeVoMock, Volume.Event.DestroyRequested);
boolean result = volumeApiServiceImpl.deleteVolume(volumeMockId, accountMock);
Assert.assertFalse(result);
Mockito.verify(volumeApiServiceImpl).retrieveAndValidateVolume(volumeMockId, accountMock);
Mockito.verify(volumeApiServiceImpl).destroyVolumeIfPossible(volumeVoMock);
Mockito.verify(volumeDaoMock, Mockito.times(0)).remove(volumeMockId);
Mockito.verify(volumeApiServiceImpl, Mockito.times(0)).stateTransitTo(volumeVoMock, Volume.Event.DestroyRequested);
}
@Test
public void deleteVolumeTestVolumeStateReadyThrowingNoTransitionException() throws InterruptedException, ExecutionException, NoTransitionException {
Mockito.doReturn(Volume.State.Ready).when(volumeVoMock).getState();
Mockito.doReturn(volumeVoMock).when(volumeApiServiceImpl).retrieveAndValidateVolume(volumeMockId, accountMock);
Mockito.doNothing().when(volumeApiServiceImpl).destroyVolumeIfPossible(volumeVoMock);
Mockito.doThrow(NoTransitionException.class).when(volumeApiServiceImpl).expungeVolumesInPrimaryStorageIfNeeded(volumeVoMock);
Mockito.doReturn(true).when(volumeDaoMock).remove(volumeMockId);
Mockito.doReturn(true).when(volumeApiServiceImpl).stateTransitTo(volumeVoMock, Volume.Event.DestroyRequested);
boolean result = volumeApiServiceImpl.deleteVolume(volumeMockId, accountMock);
Assert.assertFalse(result);
Mockito.verify(volumeApiServiceImpl).retrieveAndValidateVolume(volumeMockId, accountMock);
Mockito.verify(volumeApiServiceImpl).destroyVolumeIfPossible(volumeVoMock);
Mockito.verify(volumeDaoMock, Mockito.times(0)).remove(volumeMockId);
Mockito.verify(volumeApiServiceImpl, Mockito.times(0)).stateTransitTo(volumeVoMock, Volume.Event.DestroyRequested);
}
@Test(expected = RuntimeException.class)
public void deleteVolumeTestVolumeStateReadyThrowingRuntimeException() throws InterruptedException, ExecutionException, NoTransitionException {
Mockito.doReturn(Volume.State.Ready).when(volumeVoMock).getState();
Mockito.doReturn(volumeVoMock).when(volumeApiServiceImpl).retrieveAndValidateVolume(volumeMockId, accountMock);
Mockito.doNothing().when(volumeApiServiceImpl).destroyVolumeIfPossible(volumeVoMock);
Mockito.doThrow(RuntimeException.class).when(volumeApiServiceImpl).expungeVolumesInPrimaryStorageIfNeeded(volumeVoMock);
Mockito.doReturn(true).when(volumeDaoMock).remove(volumeMockId);
Mockito.doReturn(true).when(volumeApiServiceImpl).stateTransitTo(volumeVoMock, Volume.Event.DestroyRequested);
volumeApiServiceImpl.deleteVolume(volumeMockId, accountMock);
}
}