mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
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:
parent
bab4e3a6af
commit
a99c9d0e68
@ -54,6 +54,7 @@ import com.cloud.offering.NetworkOffering;
|
||||
import com.cloud.offering.ServiceOffering;
|
||||
import com.cloud.projects.Project;
|
||||
import com.cloud.server.ResourceTag;
|
||||
import com.cloud.storage.StoragePool;
|
||||
import com.cloud.storage.GuestOS;
|
||||
import com.cloud.storage.GuestOSHypervisor;
|
||||
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_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
|
||||
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";
|
||||
@ -728,6 +733,10 @@ public class EventTypes {
|
||||
entityEventDetails.put(EVENT_MAINTENANCE_PREPARE, 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
|
||||
entityEventDetails.put(EVENT_REMOTE_ACCESS_VPN_CREATE, RemoteAccessVpn.class);
|
||||
entityEventDetails.put(EVENT_REMOTE_ACCESS_VPN_DESTROY, RemoteAccessVpn.class);
|
||||
|
||||
@ -17,5 +17,5 @@
|
||||
package com.cloud.storage;
|
||||
|
||||
public enum StoragePoolStatus {
|
||||
Initial, Initialized, Creating, Attaching, Up, PrepareForMaintenance, ErrorInMaintenance, CancelMaintenance, Maintenance, Removed;
|
||||
Initial, Initialized, Creating, Attaching, Up, PrepareForMaintenance, ErrorInMaintenance, CancelMaintenance, Maintenance, Disabled, Removed;
|
||||
}
|
||||
|
||||
@ -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")
|
||||
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 ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
@ -74,6 +78,10 @@ public class UpdateStoragePoolCmd extends BaseCmd {
|
||||
return capacityBytes;
|
||||
}
|
||||
|
||||
public Boolean getEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@ -27,4 +27,6 @@ public interface PrimaryDataStoreLifeCycle extends DataStoreLifeCycle {
|
||||
public static final String CAPACITY_IOPS = "capacityIops";
|
||||
|
||||
void updateStoragePool(StoragePool storagePool, Map<String, String> details);
|
||||
void enableStoragePool(DataStore store);
|
||||
void disableStoragePool(DataStore store);
|
||||
}
|
||||
|
||||
@ -77,6 +77,8 @@ public interface PrimaryDataStoreDao extends GenericDao<StoragePoolVO, Long> {
|
||||
|
||||
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.
|
||||
*
|
||||
|
||||
@ -76,6 +76,7 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase<StoragePoolVO, Long>
|
||||
AllFieldSearch.and("datacenterId", AllFieldSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ);
|
||||
AllFieldSearch.and("hostAddress", AllFieldSearch.entity().getHostAddress(), 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("podId", AllFieldSearch.entity().getPodId(), Op.EQ);
|
||||
AllFieldSearch.and("clusterId", AllFieldSearch.entity().getClusterId(), Op.EQ);
|
||||
@ -309,6 +310,26 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase<StoragePoolVO, Long>
|
||||
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
|
||||
public List<StoragePoolVO> findLocalStoragePoolsByTags(long dcId, long podId, Long clusterId, String[] tags) {
|
||||
List<StoragePoolVO> storagePools = null;
|
||||
|
||||
@ -33,6 +33,7 @@ import org.springframework.stereotype.Component;
|
||||
import com.cloud.deploy.DeploymentPlan;
|
||||
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
|
||||
import com.cloud.offering.ServiceOffering;
|
||||
import com.cloud.storage.ScopeType;
|
||||
import com.cloud.storage.StoragePool;
|
||||
import com.cloud.storage.dao.DiskOfferingDao;
|
||||
import com.cloud.vm.DiskProfile;
|
||||
@ -70,9 +71,20 @@ public class ClusterScopeStoragePoolAllocator extends AbstractStoragePoolAllocat
|
||||
return null;
|
||||
}
|
||||
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 {
|
||||
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());
|
||||
|
||||
@ -35,6 +35,7 @@ import com.cloud.capacity.dao.CapacityDao;
|
||||
import com.cloud.deploy.DeploymentPlan;
|
||||
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
|
||||
import com.cloud.service.dao.ServiceOfferingDao;
|
||||
import com.cloud.storage.ScopeType;
|
||||
import com.cloud.storage.StoragePool;
|
||||
import com.cloud.storage.dao.StoragePoolHostDao;
|
||||
import com.cloud.utils.NumbersUtil;
|
||||
@ -69,6 +70,16 @@ public class LocalStoragePoolAllocator extends AbstractStoragePoolAllocator {
|
||||
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>();
|
||||
|
||||
// data disk and host identified from deploying vm (attach volume case)
|
||||
|
||||
@ -33,6 +33,7 @@ import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||
import com.cloud.deploy.DeploymentPlan;
|
||||
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.storage.ScopeType;
|
||||
import com.cloud.storage.StoragePool;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.vm.DiskProfile;
|
||||
@ -55,6 +56,16 @@ public class ZoneWideStoragePoolAllocator extends AbstractStoragePoolAllocator {
|
||||
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<StoragePoolVO> storagePools = _storagePoolDao.findZoneWideStoragePoolsByTags(plan.getDataCenterId(), dskCh.getTags());
|
||||
|
||||
@ -192,6 +192,20 @@ public class PrimaryDataStoreHelper {
|
||||
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) {
|
||||
CapacityVO capacity1 = _capacityDao.findByHostIdType(poolId, Capacity.CAPACITY_TYPE_STORAGE);
|
||||
CapacityVO capacity2 = _capacityDao.findByHostIdType(poolId, Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED);
|
||||
|
||||
@ -464,6 +464,16 @@ public class ElastistorPrimaryDataStoreLifeCycle implements PrimaryDataStoreLife
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableStoragePool(DataStore dataStore) {
|
||||
_dataStoreHelper.enable(dataStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableStoragePool(DataStore dataStore) {
|
||||
_dataStoreHelper.disable(dataStore);
|
||||
}
|
||||
|
||||
@SuppressWarnings("finally")
|
||||
@Override
|
||||
public boolean deleteDataStore(DataStore store) {
|
||||
|
||||
@ -522,4 +522,14 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl implements PrimaryDataStore
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,6 +165,16 @@ public class NexentaPrimaryDataStoreLifeCycle
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableStoragePool(DataStore dataStore) {
|
||||
dataStoreHelper.enable(dataStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableStoragePool(DataStore dataStore) {
|
||||
dataStoreHelper.disable(dataStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteDataStore(DataStore store) {
|
||||
return dataStoreHelper.deletePrimaryDataStore(store);
|
||||
|
||||
@ -138,4 +138,12 @@ public class SamplePrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLife
|
||||
@Override
|
||||
public void updateStoragePool(StoragePool storagePool, Map<String, String> details) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableStoragePool(DataStore store) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableStoragePool(DataStore store) {
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -659,4 +659,14 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,6 +116,8 @@ import com.cloud.dc.ClusterVO;
|
||||
import com.cloud.dc.DataCenterVO;
|
||||
import com.cloud.dc.dao.ClusterDao;
|
||||
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.ConnectionException;
|
||||
import com.cloud.exception.DiscoveryException;
|
||||
@ -732,6 +734,32 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
||||
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
|
||||
public PrimaryDataStoreInfo updateStoragePool(UpdateStoragePoolCmd cmd) throws IllegalArgumentException {
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user