mirror of https://github.com/apache/cloudstack.git
CS-14297: added "forced" option to deleteStoragePool command. If forced=true, all destroyed volumes are marked as Expunged even when we can't reach primary storage at the moment of deletion.
This commit is contained in:
parent
72b5a94af8
commit
8bb5a96cbe
|
|
@ -37,6 +37,10 @@ public class DeletePoolCmd extends BaseCmd {
|
|||
@IdentityMapper(entityTableName="storage_pool")
|
||||
@Parameter(name = ApiConstants.ID, type = CommandType.LONG, required = true, description = "Storage pool id")
|
||||
private Long id;
|
||||
|
||||
@Parameter(name = ApiConstants.FORCED, type = CommandType.BOOLEAN, required = false, description = "Force destroy storage pool " +
|
||||
"(force expunge volumes in Destroyed state as a part of pool removal)")
|
||||
private Boolean forced;
|
||||
|
||||
// ///////////////////////////////////////////////////
|
||||
// ///////////////// Accessors ///////////////////////
|
||||
|
|
@ -45,6 +49,10 @@ public class DeletePoolCmd extends BaseCmd {
|
|||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public boolean isForced() {
|
||||
return (forced != null) ? forced : false;
|
||||
}
|
||||
|
||||
// ///////////////////////////////////////////////////
|
||||
// ///////////// API Implementation///////////////////
|
||||
|
|
|
|||
|
|
@ -44,7 +44,8 @@ public class StopVMCmd extends BaseAsyncCmd {
|
|||
@Parameter(name = ApiConstants.ID, type = CommandType.LONG, required = true, description = "The ID of the virtual machine")
|
||||
private Long id;
|
||||
|
||||
@Parameter(name = ApiConstants.FORCED, type = CommandType.BOOLEAN, required = false, description = "Force stop the VM. The caller knows the VM is stopped.")
|
||||
@Parameter(name = ApiConstants.FORCED, type = CommandType.BOOLEAN, required = false, description = "Force stop the VM " +
|
||||
"(vm is marked as Stopped even when command fails to be send to the backend). The caller knows the VM is stopped.")
|
||||
private Boolean forced;
|
||||
|
||||
// ///////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -1389,9 +1389,10 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
|
|||
|
||||
@Override
|
||||
@DB
|
||||
public boolean deletePool(DeletePoolCmd command) {
|
||||
Long id = command.getId();
|
||||
public boolean deletePool(DeletePoolCmd cmd) {
|
||||
Long id = cmd.getId();
|
||||
boolean deleteFlag = false;
|
||||
boolean forced = cmd.isForced();
|
||||
|
||||
// verify parameters
|
||||
StoragePoolVO sPool = _storagePoolDao.findById(id);
|
||||
|
|
@ -1405,14 +1406,29 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
|
|||
throw new InvalidParameterValueException("Unable to delete local storage id: " + id);
|
||||
}
|
||||
|
||||
// Check if the pool has associated volumes in the volumes table
|
||||
// If it does, then you cannot delete the pool
|
||||
Pair<Long, Long> volumeRecords = _volsDao.getCountAndTotalByPool(id);
|
||||
|
||||
if (volumeRecords.first() > 0) {
|
||||
s_logger.warn("Cannot delete pool " + sPool.getName() + " as there are associated vols for this pool");
|
||||
return false; // cannot delete as there are associated vols
|
||||
Pair<Long, Long> vlms = _volsDao.getCountAndTotalByPool(id);
|
||||
if (forced) {
|
||||
if (vlms.first() > 0) {
|
||||
Pair<Long, Long> nonDstrdVlms = _volsDao.getNonDestroyedCountAndTotalByPool(id);
|
||||
if (nonDstrdVlms.first() > 0) {
|
||||
throw new CloudRuntimeException("Cannot delete pool " + sPool.getName() + " as there are associated " +
|
||||
"non-destroyed vols for this pool");
|
||||
}
|
||||
//force expunge non-destroyed volumes
|
||||
List<VolumeVO> vols = _volsDao.listVolumesToBeDestroyed();
|
||||
for (VolumeVO vol : vols) {
|
||||
expungeVolume(vol, true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Check if the pool has associated volumes in the volumes table
|
||||
// If it does , then you cannot delete the pool
|
||||
if (vlms.first() > 0) {
|
||||
throw new CloudRuntimeException("Cannot delete pool " + sPool.getName() + " as there are associated vols" +
|
||||
" for this pool");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// First get the host_id from storage_pool_host_ref for given pool id
|
||||
StoragePoolVO lock = _storagePoolDao.acquireInLockTable(sPool.getId());
|
||||
|
|
@ -1450,8 +1466,8 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
|
|||
} else {
|
||||
// Remove the SR associated with the Xenserver
|
||||
for (StoragePoolHostVO host : hostPoolRecords) {
|
||||
DeleteStoragePoolCommand cmd = new DeleteStoragePoolCommand(sPool);
|
||||
final Answer answer = _agentMgr.easySend(host.getHostId(), cmd);
|
||||
DeleteStoragePoolCommand deleteCmd = new DeleteStoragePoolCommand(sPool);
|
||||
final Answer answer = _agentMgr.easySend(host.getHostId(), deleteCmd);
|
||||
|
||||
if (answer != null && answer.getResult()) {
|
||||
deleteFlag = true;
|
||||
|
|
@ -1991,7 +2007,7 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
|
|||
List<VolumeVO> vols = _volsDao.listVolumesToBeDestroyed();
|
||||
for (VolumeVO vol : vols) {
|
||||
try {
|
||||
expungeVolume(vol);
|
||||
expungeVolume(vol, false);
|
||||
} catch (Exception e) {
|
||||
s_logger.warn("Unable to destroy " + vol.getId(), e);
|
||||
}
|
||||
|
|
@ -2575,7 +2591,7 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
|
|||
}
|
||||
|
||||
try {
|
||||
expungeVolume(volume);
|
||||
expungeVolume(volume, false);
|
||||
} catch (Exception e) {
|
||||
s_logger.warn("Failed to expunge volume:", e);
|
||||
return false;
|
||||
|
|
@ -3107,7 +3123,7 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
|
|||
// add code here
|
||||
}
|
||||
|
||||
public void expungeVolume(VolumeVO vol) {
|
||||
public void expungeVolume(VolumeVO vol, boolean force) {
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Expunging " + vol);
|
||||
}
|
||||
|
|
@ -3137,18 +3153,36 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
|
|||
}
|
||||
|
||||
DestroyCommand cmd = new DestroyCommand(pool, vol, vmName);
|
||||
boolean removeVolume = false;
|
||||
try {
|
||||
Answer answer = sendToPool(pool, cmd);
|
||||
if (answer != null && answer.getResult()) {
|
||||
_volsDao.remove(vol.getId());
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Volume successfully expunged from " + poolId);
|
||||
}
|
||||
removeVolume = true;
|
||||
} else {
|
||||
s_logger.info("Will retry delete of " + vol + " from " + poolId);
|
||||
}
|
||||
} catch (StorageUnavailableException e) {
|
||||
s_logger.info("Storage is unavailable currently. Will retry delete of " + vol + " from " + poolId);
|
||||
if (force) {
|
||||
s_logger.info("Storage is unavailable currently, but marking volume id=" + vol.getId() + " as expunged anyway due to force=true");
|
||||
removeVolume = true;
|
||||
} else {
|
||||
s_logger.info("Storage is unavailable currently. Will retry delete of " + vol + " from " + poolId);
|
||||
}
|
||||
} catch (RuntimeException ex) {
|
||||
if (force) {
|
||||
s_logger.info("Failed to expunge volume, but marking volume id=" + vol.getId() + " as expunged anyway " +
|
||||
"due to force=true. Volume failed to expunge due to ", ex);
|
||||
removeVolume = true;
|
||||
} else {
|
||||
throw ex;
|
||||
}
|
||||
} finally {
|
||||
if (removeVolume) {
|
||||
_volsDao.remove(vol.getId());
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Volume successfully expunged from " + poolId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -3180,7 +3214,7 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
|
|||
txn.commit();
|
||||
|
||||
for (VolumeVO expunge : toBeExpunged) {
|
||||
expungeVolume(expunge);
|
||||
expungeVolume(expunge, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,29 +23,50 @@ import com.cloud.utils.db.GenericDao;
|
|||
import com.cloud.utils.fsm.StateDao;
|
||||
|
||||
public interface VolumeDao extends GenericDao<VolumeVO, Long>, StateDao<Volume.State, Volume.Event, Volume> {
|
||||
|
||||
List<VolumeVO> findDetachedByAccount(long accountId);
|
||||
|
||||
List<VolumeVO> findByAccount(long accountId);
|
||||
|
||||
Pair<Long, Long> getCountAndTotalByPool(long poolId);
|
||||
|
||||
Pair<Long, Long> getNonDestroyedCountAndTotalByPool(long poolId);
|
||||
|
||||
List<VolumeVO> findByInstance(long id);
|
||||
|
||||
List<VolumeVO> findByInstanceAndType(long id, Volume.Type vType);
|
||||
|
||||
List<VolumeVO> findByInstanceIdDestroyed(long vmId);
|
||||
|
||||
List<VolumeVO> findByAccountAndPod(long accountId, long podId);
|
||||
|
||||
List<VolumeVO> findByTemplateAndZone(long templateId, long zoneId);
|
||||
|
||||
void deleteVolumesByInstance(long instanceId);
|
||||
|
||||
void attachVolume(long volumeId, long vmId, long deviceId);
|
||||
|
||||
void detachVolume(long volumeId);
|
||||
|
||||
boolean isAnyVolumeActivelyUsingTemplateOnPool(long templateId, long poolId);
|
||||
|
||||
List<VolumeVO> findCreatedByInstance(long id);
|
||||
|
||||
List<VolumeVO> findByPoolId(long poolId);
|
||||
|
||||
List<VolumeVO> findByInstanceAndDeviceId(long instanceId, long deviceId);
|
||||
|
||||
List<VolumeVO> findUsableVolumesForInstance(long instanceId);
|
||||
|
||||
Long countAllocatedVolumesForAccount(long accountId);
|
||||
|
||||
HypervisorType getHypervisorType(long volumeId);
|
||||
|
||||
List<VolumeVO> listVolumesToBeDestroyed();
|
||||
|
||||
ImageFormat getImageFormat(Long volumeId);
|
||||
|
||||
List<VolumeVO> findReadyRootVolumesByInstance(long instanceId);
|
||||
|
||||
List<Long> listPoolIdsByVolumeCount(long dcId, Long podId, Long clusterId, long accountId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
|||
import com.cloud.storage.Storage.ImageFormat;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.storage.Volume.Event;
|
||||
import com.cloud.storage.Volume.State;
|
||||
import com.cloud.storage.Volume.Type;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.utils.Pair;
|
||||
|
|
@ -268,6 +269,7 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
|
|||
TotalSizeByPoolSearch.select("count", Func.COUNT, (Object[])null);
|
||||
TotalSizeByPoolSearch.and("poolId", TotalSizeByPoolSearch.entity().getPoolId(), Op.EQ);
|
||||
TotalSizeByPoolSearch.and("removed", TotalSizeByPoolSearch.entity().getRemoved(), Op.NULL);
|
||||
TotalSizeByPoolSearch.and("state", TotalSizeByPoolSearch.entity().getState(), Op.NEQ);
|
||||
TotalSizeByPoolSearch.done();
|
||||
|
||||
ActiveTemplateSearch = createSearchBuilder(Long.class);
|
||||
|
|
@ -379,4 +381,14 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
|
|||
throw new CloudRuntimeException("Caught: " + ORDER_POOLS_NUMBER_OF_VOLUMES_FOR_ACCOUNT, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override @DB(txn=false)
|
||||
public Pair<Long, Long> getNonDestroyedCountAndTotalByPool(long poolId) {
|
||||
SearchCriteria<SumCount> sc = TotalSizeByPoolSearch.create();
|
||||
sc.setParameters("poolId", poolId);
|
||||
sc.setParameters("state", State.Destroy);
|
||||
List<SumCount> results = customSearch(sc, null);
|
||||
SumCount sumCount = results.get(0);
|
||||
return new Pair<Long, Long>(sumCount.count, sumCount.sum);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue