Implementation for the ability to disable a storage pool for provisioning

... of new volumes. Following changes are implemented 1. Disable or enable a pool with the
updateStoragePool api. A new 'enabled' parameter added for the same. 2. When a
pool is disabled the state of the pool is updated to 'Disabled' in the db. On
enabling it is updated back to 'Up'. Alert is raised when a pool is disabled or
enabled. 3. Updated other storage providers to also honour the disabled state.
4. A disabled pool is skipped by allocators for provisioing of new volumes. 5.
Since the allocators skip a disabled pool for provisioning of volumes, the
volumes are also not listed as a destination for volume migration.

FS: https://cwiki.apache.org/confluence/display/CLOUDSTACK/Disabling+Storage+Pool+for+Provisioning

This closes #257

Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
Devdeep Singh 2015-05-05 18:24:04 +05:30 committed by Rohit Yadav
parent bab4e3a6af
commit a99c9d0e68
17 changed files with 187 additions and 4 deletions

View File

@ -54,6 +54,7 @@ import com.cloud.offering.NetworkOffering;
import com.cloud.offering.ServiceOffering; import com.cloud.offering.ServiceOffering;
import com.cloud.projects.Project; import com.cloud.projects.Project;
import com.cloud.server.ResourceTag; import com.cloud.server.ResourceTag;
import com.cloud.storage.StoragePool;
import com.cloud.storage.GuestOS; import com.cloud.storage.GuestOS;
import com.cloud.storage.GuestOSHypervisor; import com.cloud.storage.GuestOSHypervisor;
import com.cloud.storage.Snapshot; import com.cloud.storage.Snapshot;
@ -306,6 +307,10 @@ public class EventTypes {
public static final String EVENT_MAINTENANCE_PREPARE = "MAINT.PREPARE"; public static final String EVENT_MAINTENANCE_PREPARE = "MAINT.PREPARE";
public static final String EVENT_MAINTENANCE_PREPARE_PRIMARY_STORAGE = "MAINT.PREPARE.PS"; public static final String EVENT_MAINTENANCE_PREPARE_PRIMARY_STORAGE = "MAINT.PREPARE.PS";
// Primary storage pool
public static final String EVENT_ENABLE_PRIMARY_STORAGE = "ENABLE.PS";
public static final String EVENT_DISABLE_PRIMARY_STORAGE = "DISABLE.PS";
// VPN // VPN
public static final String EVENT_REMOTE_ACCESS_VPN_CREATE = "VPN.REMOTE.ACCESS.CREATE"; public static final String EVENT_REMOTE_ACCESS_VPN_CREATE = "VPN.REMOTE.ACCESS.CREATE";
public static final String EVENT_REMOTE_ACCESS_VPN_DESTROY = "VPN.REMOTE.ACCESS.DESTROY"; public static final String EVENT_REMOTE_ACCESS_VPN_DESTROY = "VPN.REMOTE.ACCESS.DESTROY";
@ -728,6 +733,10 @@ public class EventTypes {
entityEventDetails.put(EVENT_MAINTENANCE_PREPARE, Host.class); entityEventDetails.put(EVENT_MAINTENANCE_PREPARE, Host.class);
entityEventDetails.put(EVENT_MAINTENANCE_PREPARE_PRIMARY_STORAGE, Host.class); entityEventDetails.put(EVENT_MAINTENANCE_PREPARE_PRIMARY_STORAGE, Host.class);
// Primary storage pool
entityEventDetails.put(EVENT_ENABLE_PRIMARY_STORAGE, StoragePool.class);
entityEventDetails.put(EVENT_DISABLE_PRIMARY_STORAGE, StoragePool.class);
// VPN // VPN
entityEventDetails.put(EVENT_REMOTE_ACCESS_VPN_CREATE, RemoteAccessVpn.class); entityEventDetails.put(EVENT_REMOTE_ACCESS_VPN_CREATE, RemoteAccessVpn.class);
entityEventDetails.put(EVENT_REMOTE_ACCESS_VPN_DESTROY, RemoteAccessVpn.class); entityEventDetails.put(EVENT_REMOTE_ACCESS_VPN_DESTROY, RemoteAccessVpn.class);

View File

@ -17,5 +17,5 @@
package com.cloud.storage; package com.cloud.storage;
public enum StoragePoolStatus { public enum StoragePoolStatus {
Initial, Initialized, Creating, Attaching, Up, PrepareForMaintenance, ErrorInMaintenance, CancelMaintenance, Maintenance, Removed; Initial, Initialized, Creating, Attaching, Up, PrepareForMaintenance, ErrorInMaintenance, CancelMaintenance, Maintenance, Disabled, Removed;
} }

View File

@ -54,6 +54,10 @@ public class UpdateStoragePoolCmd extends BaseCmd {
@Parameter(name = ApiConstants.CAPACITY_BYTES, type = CommandType.LONG, required = false, description = "bytes CloudStack can provision from this storage pool") @Parameter(name = ApiConstants.CAPACITY_BYTES, type = CommandType.LONG, required = false, description = "bytes CloudStack can provision from this storage pool")
private Long capacityBytes; private Long capacityBytes;
@Parameter(name = ApiConstants.ENABLED, type = CommandType.BOOLEAN, required = false, description = "false to disable the pool for allocation of new volumes, true to" +
" enable it back.")
private Boolean enabled;
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
/////////////////// Accessors /////////////////////// /////////////////// Accessors ///////////////////////
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
@ -74,6 +78,10 @@ public class UpdateStoragePoolCmd extends BaseCmd {
return capacityBytes; return capacityBytes;
} }
public Boolean getEnabled() {
return enabled;
}
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
/////////////// API Implementation/////////////////// /////////////// API Implementation///////////////////
///////////////////////////////////////////////////// /////////////////////////////////////////////////////

View File

@ -27,4 +27,6 @@ public interface PrimaryDataStoreLifeCycle extends DataStoreLifeCycle {
public static final String CAPACITY_IOPS = "capacityIops"; public static final String CAPACITY_IOPS = "capacityIops";
void updateStoragePool(StoragePool storagePool, Map<String, String> details); void updateStoragePool(StoragePool storagePool, Map<String, String> details);
void enableStoragePool(DataStore store);
void disableStoragePool(DataStore store);
} }

View File

@ -77,6 +77,8 @@ public interface PrimaryDataStoreDao extends GenericDao<StoragePoolVO, Long> {
List<StoragePoolVO> findPoolsByTags(long dcId, long podId, Long clusterId, String[] tags); List<StoragePoolVO> findPoolsByTags(long dcId, long podId, Long clusterId, String[] tags);
List<StoragePoolVO> findDisabledPoolsByScope(long dcId, Long podId, Long clusterId, ScopeType scope);
/** /**
* Find pool by UUID. * Find pool by UUID.
* *

View File

@ -76,6 +76,7 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase<StoragePoolVO, Long>
AllFieldSearch.and("datacenterId", AllFieldSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ); AllFieldSearch.and("datacenterId", AllFieldSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ);
AllFieldSearch.and("hostAddress", AllFieldSearch.entity().getHostAddress(), SearchCriteria.Op.EQ); AllFieldSearch.and("hostAddress", AllFieldSearch.entity().getHostAddress(), SearchCriteria.Op.EQ);
AllFieldSearch.and("status", AllFieldSearch.entity().getStatus(), SearchCriteria.Op.EQ); AllFieldSearch.and("status", AllFieldSearch.entity().getStatus(), SearchCriteria.Op.EQ);
AllFieldSearch.and("scope", AllFieldSearch.entity().getScope(), SearchCriteria.Op.EQ);
AllFieldSearch.and("path", AllFieldSearch.entity().getPath(), SearchCriteria.Op.EQ); AllFieldSearch.and("path", AllFieldSearch.entity().getPath(), SearchCriteria.Op.EQ);
AllFieldSearch.and("podId", AllFieldSearch.entity().getPodId(), Op.EQ); AllFieldSearch.and("podId", AllFieldSearch.entity().getPodId(), Op.EQ);
AllFieldSearch.and("clusterId", AllFieldSearch.entity().getClusterId(), Op.EQ); AllFieldSearch.and("clusterId", AllFieldSearch.entity().getClusterId(), Op.EQ);
@ -309,6 +310,26 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase<StoragePoolVO, Long>
return storagePools; return storagePools;
} }
@Override
public List<StoragePoolVO> findDisabledPoolsByScope(long dcId, Long podId, Long clusterId, ScopeType scope) {
List<StoragePoolVO> storagePools = null;
SearchCriteria<StoragePoolVO> sc = AllFieldSearch.create();
sc.setParameters("status", StoragePoolStatus.Disabled);
sc.setParameters("scope", scope);
if (scope == ScopeType.ZONE) {
sc.setParameters("datacenterId", dcId);
storagePools = listBy(sc);
} else if ((scope == ScopeType.CLUSTER || scope == ScopeType.HOST) && podId != null && clusterId != null) {
sc.setParameters("datacenterId", dcId);
sc.setParameters("podId", podId);
sc.setParameters("clusterId", clusterId);
storagePools = listBy(sc);
}
return storagePools;
}
@Override @Override
public List<StoragePoolVO> findLocalStoragePoolsByTags(long dcId, long podId, Long clusterId, String[] tags) { public List<StoragePoolVO> findLocalStoragePoolsByTags(long dcId, long podId, Long clusterId, String[] tags) {
List<StoragePoolVO> storagePools = null; List<StoragePoolVO> storagePools = null;

View File

@ -33,6 +33,7 @@ import org.springframework.stereotype.Component;
import com.cloud.deploy.DeploymentPlan; import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.offering.ServiceOffering; import com.cloud.offering.ServiceOffering;
import com.cloud.storage.ScopeType;
import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePool;
import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.vm.DiskProfile; import com.cloud.vm.DiskProfile;
@ -70,9 +71,20 @@ public class ClusterScopeStoragePoolAllocator extends AbstractStoragePoolAllocat
return null; return null;
} }
if (dskCh.getTags() != null && dskCh.getTags().length != 0) { if (dskCh.getTags() != null && dskCh.getTags().length != 0) {
s_logger.debug("Looking for pools in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId + " having tags:" + Arrays.toString(dskCh.getTags())); s_logger.debug("Looking for pools in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId + " having tags:" + Arrays.toString(dskCh.getTags()) +
". Disabled pools will be ignored.");
} else { } else {
s_logger.debug("Looking for pools in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId); s_logger.debug("Looking for pools in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId + ". Disabled pools will be ignored.");
}
if (s_logger.isTraceEnabled()) {
// Log the pools details that are ignored because they are in disabled state
List<StoragePoolVO> disabledPools = _storagePoolDao.findDisabledPoolsByScope(dcId, podId, clusterId, ScopeType.CLUSTER);
if (disabledPools != null && !disabledPools.isEmpty()) {
for (StoragePoolVO pool : disabledPools) {
s_logger.trace("Ignoring pool " + pool + " as it is in disabled state.");
}
}
} }
List<StoragePoolVO> pools = _storagePoolDao.findPoolsByTags(dcId, podId, clusterId, dskCh.getTags()); List<StoragePoolVO> pools = _storagePoolDao.findPoolsByTags(dcId, podId, clusterId, dskCh.getTags());

View File

@ -35,6 +35,7 @@ import com.cloud.capacity.dao.CapacityDao;
import com.cloud.deploy.DeploymentPlan; import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.storage.ScopeType;
import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePool;
import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.storage.dao.StoragePoolHostDao;
import com.cloud.utils.NumbersUtil; import com.cloud.utils.NumbersUtil;
@ -69,6 +70,16 @@ public class LocalStoragePoolAllocator extends AbstractStoragePoolAllocator {
return null; return null;
} }
if (s_logger.isTraceEnabled()) {
// Log the pools details that are ignored because they are in disabled state
List<StoragePoolVO> disabledPools = _storagePoolDao.findDisabledPoolsByScope(plan.getDataCenterId(), plan.getPodId(), plan.getClusterId(), ScopeType.HOST);
if (disabledPools != null && !disabledPools.isEmpty()) {
for (StoragePoolVO pool : disabledPools) {
s_logger.trace("Ignoring pool " + pool + " as it is in disabled state.");
}
}
}
List<StoragePool> suitablePools = new ArrayList<StoragePool>(); List<StoragePool> suitablePools = new ArrayList<StoragePool>();
// data disk and host identified from deploying vm (attach volume case) // data disk and host identified from deploying vm (attach volume case)

View File

@ -33,6 +33,7 @@ import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import com.cloud.deploy.DeploymentPlan; import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.storage.ScopeType;
import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePool;
import com.cloud.user.Account; import com.cloud.user.Account;
import com.cloud.vm.DiskProfile; import com.cloud.vm.DiskProfile;
@ -55,6 +56,16 @@ public class ZoneWideStoragePoolAllocator extends AbstractStoragePoolAllocator {
return null; return null;
} }
if (s_logger.isTraceEnabled()) {
// Log the pools details that are ignored because they are in disabled state
List<StoragePoolVO> disabledPools = _storagePoolDao.findDisabledPoolsByScope(plan.getDataCenterId(), null, null, ScopeType.ZONE);
if (disabledPools != null && !disabledPools.isEmpty()) {
for (StoragePoolVO pool : disabledPools) {
s_logger.trace("Ignoring pool " + pool + " as it is in disabled state.");
}
}
}
List<StoragePool> suitablePools = new ArrayList<StoragePool>(); List<StoragePool> suitablePools = new ArrayList<StoragePool>();
List<StoragePoolVO> storagePools = _storagePoolDao.findZoneWideStoragePoolsByTags(plan.getDataCenterId(), dskCh.getTags()); List<StoragePoolVO> storagePools = _storagePoolDao.findZoneWideStoragePoolsByTags(plan.getDataCenterId(), dskCh.getTags());

View File

@ -192,6 +192,20 @@ public class PrimaryDataStoreHelper {
return true; return true;
} }
public boolean disable(DataStore store) {
StoragePoolVO pool = this.dataStoreDao.findById(store.getId());
pool.setStatus(StoragePoolStatus.Disabled);
this.dataStoreDao.update(pool.getId(), pool);
return true;
}
public boolean enable(DataStore store) {
StoragePoolVO pool = this.dataStoreDao.findById(store.getId());
pool.setStatus(StoragePoolStatus.Up);
dataStoreDao.update(pool.getId(), pool);
return true;
}
protected boolean deletePoolStats(Long poolId) { protected boolean deletePoolStats(Long poolId) {
CapacityVO capacity1 = _capacityDao.findByHostIdType(poolId, Capacity.CAPACITY_TYPE_STORAGE); CapacityVO capacity1 = _capacityDao.findByHostIdType(poolId, Capacity.CAPACITY_TYPE_STORAGE);
CapacityVO capacity2 = _capacityDao.findByHostIdType(poolId, Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED); CapacityVO capacity2 = _capacityDao.findByHostIdType(poolId, Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED);

View File

@ -464,6 +464,16 @@ public class ElastistorPrimaryDataStoreLifeCycle implements PrimaryDataStoreLife
return true; return true;
} }
@Override
public void enableStoragePool(DataStore dataStore) {
_dataStoreHelper.enable(dataStore);
}
@Override
public void disableStoragePool(DataStore dataStore) {
_dataStoreHelper.disable(dataStore);
}
@SuppressWarnings("finally") @SuppressWarnings("finally")
@Override @Override
public boolean deleteDataStore(DataStore store) { public boolean deleteDataStore(DataStore store) {

View File

@ -522,4 +522,14 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl implements PrimaryDataStore
@Override @Override
public void updateStoragePool(StoragePool storagePool, Map<String, String> details) { public void updateStoragePool(StoragePool storagePool, Map<String, String> details) {
} }
@Override
public void enableStoragePool(DataStore dataStore) {
dataStoreHelper.enable(dataStore);
}
@Override
public void disableStoragePool(DataStore dataStore) {
dataStoreHelper.disable(dataStore);
}
} }

View File

@ -165,6 +165,16 @@ public class NexentaPrimaryDataStoreLifeCycle
return true; return true;
} }
@Override
public void enableStoragePool(DataStore dataStore) {
dataStoreHelper.enable(dataStore);
}
@Override
public void disableStoragePool(DataStore dataStore) {
dataStoreHelper.disable(dataStore);
}
@Override @Override
public boolean deleteDataStore(DataStore store) { public boolean deleteDataStore(DataStore store) {
return dataStoreHelper.deletePrimaryDataStore(store); return dataStoreHelper.deletePrimaryDataStore(store);

View File

@ -138,4 +138,12 @@ public class SamplePrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLife
@Override @Override
public void updateStoragePool(StoragePool storagePool, Map<String, String> details) { public void updateStoragePool(StoragePool storagePool, Map<String, String> details) {
} }
@Override
public void enableStoragePool(DataStore store) {
}
@Override
public void disableStoragePool(DataStore store) {
}
} }

View File

@ -287,4 +287,14 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
} }
} }
} }
@Override
public void enableStoragePool(DataStore dataStore) {
dataStoreHelper.enable(dataStore);
}
@Override
public void disableStoragePool(DataStore dataStore) {
dataStoreHelper.disable(dataStore);
}
} }

View File

@ -659,4 +659,14 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor
SolidFireUtil.updateCsDbWithSolidFireIopsInfo(storagePool.getId(), _primaryDataStoreDao, _storagePoolDetailsDao, minIops, maxIops, burstIops); SolidFireUtil.updateCsDbWithSolidFireIopsInfo(storagePool.getId(), _primaryDataStoreDao, _storagePoolDetailsDao, minIops, maxIops, burstIops);
} }
@Override
public void enableStoragePool(DataStore dataStore) {
_primaryDataStoreHelper.enable(dataStore);
}
@Override
public void disableStoragePool(DataStore dataStore) {
_primaryDataStoreHelper.disable(dataStore);
}
} }

View File

@ -116,6 +116,8 @@ import com.cloud.dc.ClusterVO;
import com.cloud.dc.DataCenterVO; import com.cloud.dc.DataCenterVO;
import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.ClusterDao;
import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.DataCenterDao;
import com.cloud.event.ActionEvent;
import com.cloud.event.EventTypes;
import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.AgentUnavailableException;
import com.cloud.exception.ConnectionException; import com.cloud.exception.ConnectionException;
import com.cloud.exception.DiscoveryException; import com.cloud.exception.DiscoveryException;
@ -732,6 +734,32 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
return details; return details;
} }
@ActionEvent(eventType = EventTypes.EVENT_DISABLE_PRIMARY_STORAGE, eventDescription = "disable storage pool")
private void disablePrimaryStoragePool(StoragePoolVO primaryStorage) {
if (!primaryStorage.getStatus().equals(StoragePoolStatus.Up)) {
throw new InvalidParameterValueException("Primary storage with id " + primaryStorage.getId() + " cannot be disabled. Storage pool state : " +
primaryStorage.getStatus().toString());
}
DataStoreProvider provider = _dataStoreProviderMgr.getDataStoreProvider(primaryStorage.getStorageProviderName());
DataStoreLifeCycle dataStoreLifeCycle = provider.getDataStoreLifeCycle();
DataStore store = _dataStoreMgr.getDataStore(primaryStorage.getId(), DataStoreRole.Primary);
((PrimaryDataStoreLifeCycle)dataStoreLifeCycle).disableStoragePool(store);
}
@ActionEvent(eventType = EventTypes.EVENT_ENABLE_PRIMARY_STORAGE, eventDescription = "enable storage pool")
private void enablePrimaryStoragePool(StoragePoolVO primaryStorage) {
if (!primaryStorage.getStatus().equals(StoragePoolStatus.Disabled)) {
throw new InvalidParameterValueException("Primary storage with id " + primaryStorage.getId() + " cannot be enabled. Storage pool state : " +
primaryStorage.getStatus().toString());
}
DataStoreProvider provider = _dataStoreProviderMgr.getDataStoreProvider(primaryStorage.getStorageProviderName());
DataStoreLifeCycle dataStoreLifeCycle = provider.getDataStoreLifeCycle();
DataStore store = _dataStoreMgr.getDataStore(primaryStorage.getId(), DataStoreRole.Primary);
((PrimaryDataStoreLifeCycle)dataStoreLifeCycle).enableStoragePool(store);
}
@Override @Override
public PrimaryDataStoreInfo updateStoragePool(UpdateStoragePoolCmd cmd) throws IllegalArgumentException { public PrimaryDataStoreInfo updateStoragePool(UpdateStoragePoolCmd cmd) throws IllegalArgumentException {
// Input validation // Input validation
@ -816,7 +844,14 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
} }
} }
if (updatedDetails.size() >= 0) { Boolean enabled = cmd.getEnabled();
if (enabled != null) {
if (enabled) {
enablePrimaryStoragePool(pool);
} else {
disablePrimaryStoragePool(pool);
}
} else if (updatedDetails.size() >= 0) {
_storagePoolDao.updateDetails(id, updatedDetails); _storagePoolDao.updateDetails(id, updatedDetails);
} }