From 8bb5a96cbe8fe3d30388989307fbb3bf53fbb9c2 Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Mon, 16 Apr 2012 13:16:59 -0700 Subject: [PATCH] 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. --- .../com/cloud/api/commands/DeletePoolCmd.java | 8 ++ api/src/com/cloud/api/commands/StopVMCmd.java | 3 +- .../com/cloud/storage/StorageManagerImpl.java | 74 ++++++++++++++----- .../src/com/cloud/storage/dao/VolumeDao.java | 21 ++++++ .../com/cloud/storage/dao/VolumeDaoImpl.java | 12 +++ 5 files changed, 97 insertions(+), 21 deletions(-) diff --git a/api/src/com/cloud/api/commands/DeletePoolCmd.java b/api/src/com/cloud/api/commands/DeletePoolCmd.java index edcd282ec72..53601947bde 100644 --- a/api/src/com/cloud/api/commands/DeletePoolCmd.java +++ b/api/src/com/cloud/api/commands/DeletePoolCmd.java @@ -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/////////////////// diff --git a/api/src/com/cloud/api/commands/StopVMCmd.java b/api/src/com/cloud/api/commands/StopVMCmd.java index a72fff6068f..f6770392234 100644 --- a/api/src/com/cloud/api/commands/StopVMCmd.java +++ b/api/src/com/cloud/api/commands/StopVMCmd.java @@ -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; // /////////////////////////////////////////////////// diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index ee3cf1ccd59..f9f797ee39f 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -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 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 vlms = _volsDao.getCountAndTotalByPool(id); + if (forced) { + if (vlms.first() > 0) { + Pair 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 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 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); } } diff --git a/server/src/com/cloud/storage/dao/VolumeDao.java b/server/src/com/cloud/storage/dao/VolumeDao.java index b949fb0a76d..920af44a884 100755 --- a/server/src/com/cloud/storage/dao/VolumeDao.java +++ b/server/src/com/cloud/storage/dao/VolumeDao.java @@ -23,29 +23,50 @@ import com.cloud.utils.db.GenericDao; import com.cloud.utils.fsm.StateDao; public interface VolumeDao extends GenericDao, StateDao { + List findDetachedByAccount(long accountId); + List findByAccount(long accountId); + Pair getCountAndTotalByPool(long poolId); + + Pair getNonDestroyedCountAndTotalByPool(long poolId); + List findByInstance(long id); + List findByInstanceAndType(long id, Volume.Type vType); + List findByInstanceIdDestroyed(long vmId); + List findByAccountAndPod(long accountId, long podId); + List 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 findCreatedByInstance(long id); + List findByPoolId(long poolId); + List findByInstanceAndDeviceId(long instanceId, long deviceId); + List findUsableVolumesForInstance(long instanceId); + Long countAllocatedVolumesForAccount(long accountId); HypervisorType getHypervisorType(long volumeId); List listVolumesToBeDestroyed(); + ImageFormat getImageFormat(Long volumeId); List findReadyRootVolumesByInstance(long instanceId); + List listPoolIdsByVolumeCount(long dcId, Long podId, Long clusterId, long accountId); } diff --git a/server/src/com/cloud/storage/dao/VolumeDaoImpl.java b/server/src/com/cloud/storage/dao/VolumeDaoImpl.java index b8cf8778fb8..0cbcf398d8e 100755 --- a/server/src/com/cloud/storage/dao/VolumeDaoImpl.java +++ b/server/src/com/cloud/storage/dao/VolumeDaoImpl.java @@ -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 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 implements Vol throw new CloudRuntimeException("Caught: " + ORDER_POOLS_NUMBER_OF_VOLUMES_FOR_ACCOUNT, e); } } + + @Override @DB(txn=false) + public Pair getNonDestroyedCountAndTotalByPool(long poolId) { + SearchCriteria sc = TotalSizeByPoolSearch.create(); + sc.setParameters("poolId", poolId); + sc.setParameters("state", State.Destroy); + List results = customSearch(sc, null); + SumCount sumCount = results.get(0); + return new Pair(sumCount.count, sumCount.sum); + } }