use of com.emc.storageos.volumecontroller.Recommendation in project coprhd-controller by CoprHD.
the class RecoverPointScheduler method findVPlexHARecommendations.
/**
* Find and return a recommendation for HA given the source side information.
*
* @param varray - Source Virtual Array
* @param vpool - Source Virtual Pool
* @param haVarray - HA Virtual Array
* @param haVpool - HA Virtual Pool
* @param project - Project
* @param capabilities - Virtual Pool capabilities
* @param vplexPoolMapForVarray - Map of virtual array to visible storage pools for that virtual array
* @return HA recommendation
*/
private Recommendation findVPlexHARecommendations(VirtualArray varray, VirtualPool vpool, VirtualArray haVarray, VirtualPool haVpool, Project project, VirtualPoolCapabilityValuesWrapper capabilities, Map<String, List<StoragePool>> vplexPoolMapForVarray) {
Recommendation haRecommendation = null;
List<Recommendation> vplexHaVArrayRecommendations = null;
if (haVarray == null) {
haVarray = vplexScheduler.getHaVirtualArray(varray, project, vpool);
}
if (haVpool == null) {
haVpool = vplexScheduler.getHaVirtualPool(varray, project, vpool);
}
vplexHaVArrayRecommendations = getAllHARecommendations(varray, vpool, haVarray, haVpool, capabilities, vplexPoolMapForVarray);
if (!vplexHaVArrayRecommendations.isEmpty()) {
// There is only one recommendation ever, return the first recommendation.
haRecommendation = vplexHaVArrayRecommendations.get(0);
}
return haRecommendation;
}
use of com.emc.storageos.volumecontroller.Recommendation in project coprhd-controller by CoprHD.
the class SRDFScheduler method scheduleStorageSourcePoolConstraint.
/**
* Schedule storage based on the incoming storage pools for source volumes. Find a source
* storage pool that can provide a source volume that satisfies the vpool's criteria for all
* targets varrays required and build a recommendation structure to describe the findings.
*
* Strategy:
*
* 0. When we come into method, we already have a list of candidate source pools, which may be
* in multiple arrays 1. Get matching pools for each of the target virtual arrays based on the
* target virtual pool. 2. Make a map of virtual array to potential pools in step 1. 3. Find a
* pool from each entry in the map that belongs to a storage system that is connected via SRDF
* (with the same policy) to the specific candidate pool we're looking at. 4. Generate an SRDF
* Recommendation object that reflects the combination we found.
*
* @param varray
* varray requested for source
* @param srdfVarrays
* Varray to protect this volume to.
* @param vpool
* vpool requested
* @param capabilities
* parameters
* @param candidatePools
* candidate pools to use for source
* @param vpoolChangeVolume
* vpool change volume, if applicable
* @return list of Recommendation objects to satisfy the request
*/
private List<Recommendation> scheduleStorageSourcePoolConstraint(final VirtualArray varray, final Project project, final VirtualPool vpool, final VirtualPoolCapabilityValuesWrapper capabilities, final List<StoragePool> candidatePools, final Volume vpoolChangeVolume, final URI consistencyGroupUri) {
// Initialize a list of recommendations to be returned.
List<Recommendation> recommendations = new ArrayList<Recommendation>();
if (capabilities.getResourceCount() == 1) {
// For single resource request, select storage pool randomly from all candidate pools
// (to minimize collisions).
Collections.shuffle(candidatePools);
} else {
// Sort all pools in descending order by free capacity (first order) and in ascending
// order by ratio
// of pool's subscribed capacity to total capacity(suborder). This order is kept through
// the selection procedure.
_blockScheduler.sortPools(candidatePools);
}
List<VirtualArray> targetVarrays = getTargetVirtualArraysForVirtualPool(project, vpool, _dbClient, _permissionsHelper);
// Attempt to use these pools for selection based on target
StringBuffer sb = new StringBuffer("Determining if SRDF is possible from " + varray.getId() + " to: ");
for (VirtualArray targetVarray : targetVarrays) {
sb.append(targetVarray.getId()).append(" ");
}
_log.info(sb.toString());
// The port group provided is belongs to SRDF source storage system.
// If port group set in capabilities, ViPR looks storage pools from given PG's storage system only
// Need to remove PORT_GROUP entry from capabilities for SRDF target volume,
// so that ViPR picks SRDF target storage pools from right storage system.
//
capabilities.removeCapabilityEntry(VirtualPoolCapabilityValuesWrapper.PORT_GROUP);
Map<String, Object> attributeMap = new HashMap<String, Object>();
Map<VirtualArray, List<StoragePool>> varrayPoolMap = getMatchingPools(targetVarrays, vpool, capabilities, attributeMap);
if (varrayPoolMap == null || varrayPoolMap.isEmpty()) {
// No matching storage pools found for any of the target varrays. There are no target
// storage pools that match the passed vpool parameters and protocols and/or there are
// no pools that have enough
// capacity to hold at least one resource of the requested size.
Set<String> tmpTargetVarrays = new HashSet<String>();
sb = new StringBuffer("No matching storage pools found for any of the target varrays: [ ");
for (VirtualArray targetVarray : targetVarrays) {
sb.append(targetVarray.getId()).append(" ");
tmpTargetVarrays.add(targetVarray.getLabel());
}
sb.append("]. There are no storage pools that match the passed vpool parameters and protocols and/or " + "there are no pools that have enough capacity to hold at least one resource of the requested size.");
StringBuffer errorMessage = new StringBuffer();
if (attributeMap.get(AttributeMatcher.ERROR_MESSAGE) != null) {
errorMessage = (StringBuffer) attributeMap.get(AttributeMatcher.ERROR_MESSAGE);
}
_log.error(sb.toString());
throw APIException.badRequests.noMatchingRecoverPointStoragePoolsForVpoolAndVarrays(vpool.getLabel(), tmpTargetVarrays, errorMessage.toString());
}
// Reduce the source and target pool down to the pools available via target.
Set<SRDFPoolMapping> tmpDestPoolsList = getSRDFPoolMappings(varray, candidatePools, varrayPoolMap, vpool, vpoolChangeVolume, capabilities.getSize());
if (tmpDestPoolsList == null || tmpDestPoolsList.isEmpty()) {
// There are no target pools from any of the target varrays that share the
// same SRDF connectivity as any of the source varray pools. Placement cannot
// be achieved.
Set<String> tmpSRDFVarrays = new HashSet<String>();
sb = new StringBuffer("No matching target pool found for varray: ");
sb.append(varray.getId());
sb.append(" and vpool: ");
sb.append(vpool.getId());
sb.append(" to varrays: ");
for (VirtualArray targetVarray : targetVarrays) {
sb.append(targetVarray.getId()).append(" ");
tmpSRDFVarrays.add(targetVarray.getLabel());
}
// No matching target pool found for varray so throw an exception
// indicating a placement error.
_log.error(sb.toString());
throw APIException.badRequests.noMatchingSRDFPools(varray.getLabel(), vpool.getLabel(), tmpSRDFVarrays);
}
// Fire business rules to determine which SRDFPoolMappings can be eliminated
// from consideration for placement.
Set<SRDFPoolMapping> srcDestPoolsList = fireSRDFPlacementRules(tmpDestPoolsList, capabilities.getResourceCount());
// the volume request configuration throw an exception.
if (srcDestPoolsList == null || srcDestPoolsList.isEmpty()) {
throw APIException.badRequests.srdfNoSolutionsFoundError();
}
// Get a new source pool list for pool selection
Set<StoragePool> sourceCandidatePoolList = new HashSet<StoragePool>();
for (SRDFPoolMapping srdfPoolMapping : srcDestPoolsList) {
sourceCandidatePoolList.add(srdfPoolMapping.sourceStoragePool);
}
// Try with the storagePoolList as it currently is.
// If we get through the process and couldn't achieve full target, we should
// take out the matched pool from the storagePoolList and try again.
List<StoragePool> sourcePoolList = new ArrayList<StoragePool>();
sourcePoolList.addAll(sourceCandidatePoolList);
// We need to create recommendations for one or more pools
// that can accommodate the number of requested resources.
// We start by trying to place all resources in a single
// pool if one exists that can accommodate all requested
// resources and work our way down as necessary trying to
// minimize the number of pools used to satisfy the request.
int recommendedCount = 0;
int currentCount = capabilities.getResourceCount();
// satisfied all of the requests.
while (!sourcePoolList.isEmpty() && recommendedCount < capabilities.getResourceCount()) {
// This request will either decrement the count OR shrink the sourcePoolList
// In the case of decrementing the count, it's because it was successful at
// placing volume(s). If it wasn't, that source pool goes in the trash and we
// try the next one.
long resourceSize = capabilities.getSize();
int resourceCount = capabilities.getResourceCount();
// We need to find a pool that matches the capacity for all the source/target luns
long requiredPoolCapacity = resourceSize * currentCount;
_log.info("Required pool capacity: " + requiredPoolCapacity);
StoragePool poolWithRequiredCapacity = _blockScheduler.getPoolMatchingCapacity(requiredPoolCapacity, resourceSize, currentCount, sourcePoolList, VirtualPool.ProvisioningType.Thin.toString().equalsIgnoreCase(vpool.getSupportedProvisioningType()), null);
// pool, setting the resource count for that recommendation.
if (poolWithRequiredCapacity != null) {
StoragePool recommendedPool = poolWithRequiredCapacity;
_log.debug("Recommending storage pool {} for {} resources.", recommendedPool.getId(), currentCount);
// Now we know what pool was selected, we can grab the target pools that jive with that
// source
Map<VirtualArray, List<StoragePool>> targetVarrayPoolMap = findDestPoolsForSourcePool(targetVarrays, srcDestPoolsList, recommendedPool, vpool);
if (targetVarrayPoolMap == null || targetVarrayPoolMap.isEmpty()) {
// A valid source pool was found but there are no pools from any of the
// target varrays that can protect it.
_log.info("There are no pools from any of the target varrays that can protect the source " + "varray pool {}. Will try using another source varray pool.", recommendedPool.getLabel());
// Remove the source pool and try the next one.
sourcePoolList.remove(poolWithRequiredCapacity);
} else {
// A single recommendation object will create a set of volumes for an SRDF pair.
SRDFRecommendation rec = new SRDFRecommendation();
// For each target varray, we start the process of matching source and destination
// pools to one storage system.
Map<VirtualArray, Set<StorageSystem>> varrayTargetDeviceMap = new HashMap<VirtualArray, Set<StorageSystem>>();
for (VirtualArray targetVarray1 : targetVarrayPoolMap.keySet()) {
if (rec.getSourceStoragePool() == null) {
rec.setVirtualArray(varray.getId());
rec.setVirtualPool(vpool);
rec.setSourceStoragePool(recommendedPool.getId());
rec.setResourceCount(currentCount);
rec.setSourceStorageSystem(recommendedPool.getStorageDevice());
rec.setVirtualArrayTargetMap(new HashMap<URI, Target>());
rec.setVpoolChangeVolume(vpoolChangeVolume != null ? vpoolChangeVolume.getId() : null);
rec.setVpoolChangeVpool(vpoolChangeVolume != null ? vpool.getId() : null);
}
if (targetVarrayPoolMap.get(targetVarray1) == null || targetVarrayPoolMap.get(targetVarray1).isEmpty()) {
_log.error("Could not find any suitable storage pool for target varray: " + targetVarray1.getLabel());
throw APIException.badRequests.unableToFindSuitablePoolForTargetVArray(targetVarray1.getLabel());
}
// Select the destination pool based on what was selected as source
StoragePool destinationPool = _blockScheduler.selectPool(targetVarrayPoolMap.get(targetVarray1));
_log.info("Destination target for varray " + targetVarray1.getLabel() + " was determined to be in pool: " + destinationPool.getLabel());
Target target = new Target();
target.setTargetPool(destinationPool.getId());
target.setTargetStorageDevice(destinationPool.getStorageDevice());
// Set the copy mode
Map<URI, VpoolRemoteCopyProtectionSettings> settingsMap = VirtualPool.getRemoteProtectionSettings(vpool, _dbClient);
target.setCopyMode(settingsMap.get(targetVarray1.getId()).getCopyMode());
if (target.getCopyMode() == null) {
// Set the default if not set
target.setCopyMode(RemoteDirectorGroup.SupportedCopyModes.ASYNCHRONOUS.toString());
}
// Generate a list of storage systems that match the src and dest pools lists.
Set<StorageSystem> targetDeviceList = findMatchingSRDFPools(targetVarray1, srcDestPoolsList, recommendedPool, destinationPool);
if (targetDeviceList.isEmpty()) {
_log.error("Could not find a Storage pool for target varray: " + targetVarray1.getLabel());
throw APIException.badRequests.unableToFindSuitablePoolForTargetVArray(targetVarray1.getLabel());
}
rec.getVirtualArrayTargetMap().put(targetVarray1.getId(), target);
// Add this potential solution to the map.
varrayTargetDeviceMap.put(targetVarray1, targetDeviceList);
}
// Grab any element since all varrays need to have the same SRDF connectivity.
VirtualArray firstVarray = null;
for (VirtualArray baseVarray : varrayTargetDeviceMap.keySet()) {
firstVarray = baseVarray;
break;
}
_log.info("Chose the first varray for SRDF comparison: " + firstVarray.getLabel());
// Now go through each storage system in this varray and see if it matches up
findInsertRecommendation(rec, firstVarray, recommendations, candidatePools, recommendedPool, varrayTargetDeviceMap, project, consistencyGroupUri);
// Update the count of resources for which we have created
// a recommendation.
recommendedCount += currentCount;
// Update the current count. The conditional prevents
// unnecessary attempts to look for pools of a given
// free capacity that we already know don't exist. For
// example, say we want 100 resources and the first pool
// we find that can hold multiple resources can hold only
// 10. We don't want to continue looking for pools that
// can hold 90,89,88,...11 resources. We just want to
// see if there is another pool that can hold 10 resources,
// then 9,8, and so on.
currentCount = resourceCount - recommendedCount < currentCount ? resourceCount - recommendedCount : currentCount;
}
} else {
// If we can't find a pool that can hold the current
// count of resources, decrease the count so that we look
// for pools that can hold the next smaller number.
currentCount--;
// Clear out the source pool list (which will cause failure)
sourcePoolList.clear();
}
// log an error and clear the list of recommendations.
if (recommendedCount != resourceCount) {
_log.error("Could not find matching pools for varray {} & vpool {}", varray.getId(), vpool.getId());
recommendations.clear();
// Remove the pool we chose from the list so we can try again.
sourcePoolList.remove(poolWithRequiredCapacity);
}
}
return recommendations;
}
use of com.emc.storageos.volumecontroller.Recommendation in project coprhd-controller by CoprHD.
the class SRDFScheduler method getRecommendationsForCopy.
/**
* This routine retrieves recommendations for the SRDF_COPY from previously generated SRDF Source
* recommendations. The SRDF scheduler generates them together, but upper layers of code need
* them separately so they can be encapsulated in higher level recommendations such as Vplex.
* @param vArray - Virtual Array object
* @param project - Project object
* @param vPool - Virtual Pool object
* @param capabilities - VirtualPoolCapabilitiesWrapper contains parameters
* @param currentRecommendations - Contains the current recommendations that would include SRDFRecommendations.
* The SrdfCopyRecommendations are generated from them
* @return - List of Recommendations, specifically, SRDFCopyRecommendations
*/
private List<Recommendation> getRecommendationsForCopy(VirtualArray vArray, Project project, VirtualPool vPool, VirtualPoolCapabilityValuesWrapper capabilities, List<Recommendation> currentRecommendations) {
List<Recommendation> recommendations = new ArrayList<Recommendation>();
if (currentRecommendations == null) {
throw WorkflowException.exceptions.workflowConstructionError("Required parameter currentRecommendations is null");
}
// that has has matching varray and vpool.
for (Recommendation recommendation : currentRecommendations) {
Recommendation rec = recommendation;
while (rec != null) {
if (rec instanceof SRDFRecommendation) {
SRDFRecommendation srdfrec = (SRDFRecommendation) rec;
if (srdfrec.getVirtualArrayTargetMap().containsKey(vArray.getId())) {
SRDFRecommendation.Target target = srdfrec.getVirtualArrayTargetMap().get(vArray.getId());
_log.info(String.format("Found SRDF target recommendation for va %s vpool %s", vArray.getLabel(), vPool.getLabel()));
SRDFCopyRecommendation targetRecommendation = new SRDFCopyRecommendation();
targetRecommendation.setVirtualArray(vArray.getId());
targetRecommendation.setVirtualPool(vPool);
targetRecommendation.setSourceStorageSystem(target.getTargetStorageDevice());
targetRecommendation.setSourceStoragePool(target.getTargetStoragePool());
targetRecommendation.setResourceCount(srdfrec.getResourceCount());
targetRecommendation.setRecommendation(srdfrec);
recommendations.add(targetRecommendation);
}
}
// Check child recommendations, if any
rec = rec.getRecommendation();
}
}
return recommendations;
}
use of com.emc.storageos.volumecontroller.Recommendation in project coprhd-controller by CoprHD.
the class StorageScheduler method getRecommendedPools.
/**
* Try to determine a list of storage pools from the passed list of storage
* pools that can accommodate the passed number of resources of the passed
* size.
*
* @param varrayId The VirtualArray for the recommendations.
* @param candidatePools The list of candidate storage pools.
* @param capabilities The characteristics of the recommendation request.
* @param orderPools true if candidate pools should be ordered before
* determining the recommendation, false otherwise
*
* @return The list of Recommendation instances reflecting the recommended
* pools.
*/
protected List<Recommendation> getRecommendedPools(String varrayId, List<StoragePool> candidatePools, VirtualPoolCapabilityValuesWrapper capabilities, boolean orderPools) {
List<Recommendation> recommendations = new ArrayList<Recommendation>();
long thinVolumePreAllocateSize = capabilities.getThinVolumePreAllocateSize();
if (orderPools) {
// Sort all pools in descending order by free capacity (first order)
// and in ascending order by ratio of pool's subscribed capacity to
// total capacity(suborder). This order is kept through the
// selection procedure.
sortPools(candidatePools);
}
// We need to create recommendations for one or more pools
// that can accommodate the number of requested resources.
// We start by trying to place all resources in a single
// pool if one exists that can accommodate all requested
// resources and work our way down as necessary trying to
// minimize the number of pools used to satisfy the request.
int recommendedCount = 0;
int currentCount = capabilities.getResourceCount();
while ((!candidatePools.isEmpty()) && (recommendedCount < capabilities.getResourceCount()) && (currentCount > 0)) {
long requiredPoolCapacity = capabilities.getSize() * currentCount;
long reqThinVolumePreAllocateSize = thinVolumePreAllocateSize * currentCount;
StoragePool poolWithRequiredCapacity = getPoolMatchingCapacity(requiredPoolCapacity, capabilities.getSize(), currentCount, candidatePools, capabilities.getThinProvisioning(), reqThinVolumePreAllocateSize);
if (poolWithRequiredCapacity != null) {
StoragePool recommendedPool = poolWithRequiredCapacity;
candidatePools.remove(recommendedPool);
_log.debug("Recommending storage pool {} for {} resources.", recommendedPool.getId(), currentCount);
Recommendation recommendation = new Recommendation();
recommendation.setSourceStoragePool(recommendedPool.getId());
recommendation.setResourceCount(currentCount);
recommendation.setSourceStorageSystem(recommendedPool.getStorageDevice());
recommendations.add(recommendation);
// Update the count of resources for which we have created
// a recommendation.
recommendedCount += currentCount;
// Update the current count. The conditional prevents
// unnecessary attempts to look for pools of a given
// free capacity that we already know don't exist. For
// example, say we want 100 resources and the first pool
// we find that can hold multiple resources can hold only
// 10. We don't want to continue looking for pools that
// can hold 90,89,88,...11 resources. We just want to
// see if there is another pool that can hold 10 resources,
// then 9,8, and so on.
currentCount = (capabilities.getResourceCount() - recommendedCount < currentCount ? capabilities.getResourceCount() - recommendedCount : currentCount);
} else {
// If we can't find a pool that can hold the current
// count of resources, decrease the count so that we look
// for pools that can hold the next smaller number.
currentCount--;
}
}
// log an error and clear the list of recommendations.
if (recommendedCount != capabilities.getResourceCount()) {
recommendations.clear();
}
return recommendations;
}
use of com.emc.storageos.volumecontroller.Recommendation in project coprhd-controller by CoprHD.
the class StorageScheduler method getRecommendationsForResources.
/**
* Returns list of recommendations for block volumes.
*
* Select and return one or more storage pools where the volume(s)/fileshare(s)
* should be created. The placement logic is based on:
* - VirtualArray, only storage devices in the given varray are candidates
* - VirtualPool, specifies must-meet & best-meet service specifications
* - access-protocols: storage pools must support all protocols specified in VirtualPool
* - snapshots: if yes, only select storage pools with this capability
* - snapshot-consistency: if yes, only select storage pools with this capability
* - performance: best-match, select storage pools which meets desired performance
* - provision-mode: thick/thin
* - numPaths: select storage pools with required number of paths to the volume
* - size: Place the resources in the minimum number of storage pools that can
* accommodate the size and number of resource requested.
*
* @param neighborhood
* @param cos
* @param capabilities
* @return list of VolumeRecommendation instances
*/
@Override
public List<Recommendation> getRecommendationsForResources(VirtualArray neighborhood, Project project, VirtualPool cos, VirtualPoolCapabilityValuesWrapper capabilities) {
_log.debug("Schedule storage for {} resource(s) of size {}.", capabilities.getResourceCount(), capabilities.getSize());
List<Recommendation> volumeRecommendations = new ArrayList<Recommendation>();
// Initialize a list of recommendations to be returned.
List<Recommendation> recommendations = new ArrayList<Recommendation>();
Map<String, Object> attributeMap = new HashMap<String, Object>();
// Get all storage pools that match the passed CoS params and
// protocols. In addition, the pool must have enough capacity
// to hold at least one resource of the requested size.
List<StoragePool> candidatePools = getMatchingPools(neighborhood, cos, capabilities, attributeMap);
if (CollectionUtils.isEmpty(candidatePools)) {
StringBuffer errorMessage = new StringBuffer();
if (attributeMap.get(AttributeMatcher.ERROR_MESSAGE) != null) {
errorMessage = (StringBuffer) attributeMap.get(AttributeMatcher.ERROR_MESSAGE);
}
throw APIException.badRequests.noStoragePools(neighborhood.getLabel(), cos.getLabel(), errorMessage.toString());
}
// Get the recommendations for the candidate pools.
recommendations = getRecommendationsForPools(neighborhood.getId().toString(), candidatePools, capabilities);
// log an error and clear the list of recommendations.
if (recommendations.isEmpty()) {
// TODO reevaluate
_log.error("Could not find matching pools for VArray {} & VPool {}", neighborhood.getId(), cos.getId());
return volumeRecommendations;
}
// create list of VolumeRecommendation(s) for volumes
for (Recommendation recommendation : recommendations) {
int count = recommendation.getResourceCount();
while (count > 0) {
VolumeRecommendation volumeRecommendation = new VolumeRecommendation(VolumeRecommendation.VolumeType.BLOCK_VOLUME, capabilities.getSize(), cos, neighborhood.getId());
volumeRecommendation.setSourceStoragePool(recommendation.getSourceStoragePool());
volumeRecommendation.setSourceStorageSystem(recommendation.getSourceStorageSystem());
volumeRecommendation.setVirtualArray(neighborhood.getId());
volumeRecommendation.setVirtualPool(cos);
volumeRecommendation.setResourceCount(1);
volumeRecommendation.addStoragePool(recommendation.getSourceStoragePool());
volumeRecommendation.addStorageSystem(recommendation.getSourceStorageSystem());
volumeRecommendations.add(volumeRecommendation);
if (capabilities.getBlockConsistencyGroup() != null) {
volumeRecommendation.setParameter(VolumeRecommendation.ARRAY_CG, capabilities.getBlockConsistencyGroup());
}
count--;
}
}
return volumeRecommendations;
}
Aggregations