use of com.emc.storageos.volumecontroller.RPProtectionRecommendation in project coprhd-controller by CoprHD.
the class RecoverPointSchedulerTest method fireProtectionPlacementRulesCRRValidCapacityTest.
@Test
public void fireProtectionPlacementRulesCRRValidCapacityTest() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, ClassNotFoundException, SecurityException, NoSuchMethodException {
ProtectionSystem ps = buildProtectionSystemWithCapacity();
RPProtectionRecommendation ppm1 = new RPProtectionRecommendation();
fillRecommendationObject(ppm1, ps, "1", "2", nh1, nh2, pool1, poolA, 1);
RPProtectionRecommendation ppm2 = new RPProtectionRecommendation();
fillRecommendationObject(ppm2, ps, "1", "2", nh1, nh2, pool1, poolB, 1);
RPProtectionRecommendation ppm3 = new RPProtectionRecommendation();
fillRecommendationObject(ppm3, ps, "1", "2", nh1, nh2, pool2, poolA, 1);
RPProtectionRecommendation ppm4 = new RPProtectionRecommendation();
fillRecommendationObject(ppm4, ps, "1", "2", nh1, nh2, pool3, poolB, 1);
assertTrue(invokeFireProtectionPlacementRules(ps, ppm1, 1));
assertTrue(invokeFireProtectionPlacementRules(ps, ppm2, 1));
assertTrue(invokeFireProtectionPlacementRules(ps, ppm3, 1));
assertTrue(invokeFireProtectionPlacementRules(ps, ppm4, 1));
}
use of com.emc.storageos.volumecontroller.RPProtectionRecommendation in project coprhd-controller by CoprHD.
the class RPBlockServiceApiImpl method addJournalCapacity.
/**
* Add additional journal volume(s) to an existing recoverpoint
* consistency group copy
*
* @param param - journal volume(s) creation parameters
* @param project - the project
* @param journalVarray - the virtual array for the journal(s)
* @param journalVpool - the virtual pool for the journal(s)
* @param consistencyGroup - the recoverpoint consistency group
* @param capabilities - parameters for the journal volume(s)
* @param task - the task identifier
* @return TaskList
*/
public TaskList addJournalCapacity(VolumeCreate param, Project project, VirtualArray journalVarray, VirtualPool journalVpool, BlockConsistencyGroup consistencyGroup, VirtualPoolCapabilityValuesWrapper capabilities, String task) {
ProtectionSystem protectionSystem = getBlockScheduler().getCgProtectionSystem(consistencyGroup.getId());
if (protectionSystem != null) {
_log.info("Narrowing down placement to use protection system {}, which is currently used by RecoverPoint consistency group {}.", protectionSystem.getLabel(), consistencyGroup);
} else {
throw APIException.badRequests.noProtectionSystemAssociatedWithTheCG(consistencyGroup.getId().toString());
}
// copy name to add the journal volume to
String copyName = param.getName();
// rp cluster internal site name of the copy
String internalSiteName = null;
// adding journal to a source copy
boolean isSource = false;
// adding journal to a target copy
boolean isTarget = false;
// adding journal to a metropoint standby copy
boolean isMPStandby = copyName.contains("Standby");
// get the list of source and target volumes; for metropoint, source volumes include both sides of the source
// metro volume
List<Volume> sourceVolumes = RPHelper.getCgSourceVolumes(consistencyGroup.getId(), _dbClient);
if (sourceVolumes.isEmpty()) {
throw APIException.badRequests.noSourceVolumesInCG(consistencyGroup.getLabel());
}
// only need one source volume to set up parameters for the operation
Volume firstSrc = sourceVolumes.get(0);
StringSet sourceInternalSiteNames = new StringSet();
// both the active and the standby copies
if (RPHelper.isMetroPointVolume(_dbClient, firstSrc)) {
StringSet associatedVolumes = firstSrc.getAssociatedVolumes();
if (associatedVolumes != null && !associatedVolumes.isEmpty()) {
for (String associatedVolumeStr : associatedVolumes) {
URI associatedVolumeURI = URI.create(associatedVolumeStr);
Volume associatedVolume = _dbClient.queryObject(Volume.class, associatedVolumeURI);
sourceInternalSiteNames.add(associatedVolume.getInternalSiteName());
if (NullColumnValueGetter.isNotNullValue(associatedVolume.getRpCopyName())) {
if (associatedVolume.getRpCopyName().equals(copyName)) {
isSource = !isMPStandby;
internalSiteName = associatedVolume.getInternalSiteName();
}
}
}
}
// determine the internal site name for a source copy
} else {
sourceInternalSiteNames.add(firstSrc.getInternalSiteName());
if (NullColumnValueGetter.isNotNullValue(firstSrc.getRpCopyName())) {
if (firstSrc.getRpCopyName().equals(copyName)) {
isSource = true;
internalSiteName = firstSrc.getInternalSiteName();
}
}
}
// determine the internal site name for a target copy
for (String targetURIString : firstSrc.getRpTargets()) {
Volume tgtVolume = _dbClient.queryObject(Volume.class, URI.create(targetURIString));
if (NullColumnValueGetter.isNotNullValue(tgtVolume.getRpCopyName()) && tgtVolume.getRpCopyName().equals(copyName)) {
isTarget = true;
internalSiteName = tgtVolume.getInternalSiteName();
}
}
if (internalSiteName == null) {
throw APIException.badRequests.unableToFindTheSpecifiedCopy(copyName);
}
// if we're adding volumes to a target, we need to know if it's local or remote
String targetType = RPHelper.LOCAL;
int copyType = RecoverPointCGCopyType.PRODUCTION.getCopyNumber();
if (isTarget) {
if (sourceInternalSiteNames.contains(internalSiteName)) {
copyType = RecoverPointCGCopyType.LOCAL.getCopyNumber();
targetType = RPHelper.LOCAL;
} else {
copyType = RecoverPointCGCopyType.REMOTE.getCopyNumber();
targetType = RPHelper.REMOTE;
}
}
capabilities.put(VirtualPoolCapabilityValuesWrapper.RP_COPY_TYPE, copyType);
RPProtectionRecommendation rpProtectionRecommendation = new RPProtectionRecommendation();
rpProtectionRecommendation.setProtectionDevice(protectionSystem.getId());
RPRecommendation journalRecommendation = getBlockScheduler().buildJournalRecommendation(rpProtectionRecommendation, internalSiteName, new Long(capabilities.getSize()).toString(), journalVarray, journalVpool, protectionSystem, capabilities, capabilities.getResourceCount(), null, false);
if (journalRecommendation == null) {
throw APIException.badRequests.unableToFindSuitableJournalRecommendation();
}
String copyTypeString = RPHelper.SOURCE;
if (isSource) {
rpProtectionRecommendation.setSourceJournalRecommendation(journalRecommendation);
}
if (isMPStandby) {
rpProtectionRecommendation.setStandbyJournalRecommendation(journalRecommendation);
copyTypeString = "standby " + RPHelper.SOURCE;
}
if (isTarget) {
List<RPRecommendation> journalRecommendations = Lists.newArrayList();
journalRecommendations.add(journalRecommendation);
rpProtectionRecommendation.setTargetJournalRecommendations(journalRecommendations);
copyTypeString = targetType + " " + RPHelper.TARGET;
}
List<Recommendation> recommendations = Lists.newArrayList();
recommendations.add(rpProtectionRecommendation);
// need to set the journal copy name to something unique
param.setName(copyName + "_" + task);
_log.info("Request to add journal capacity to {} copy {}", copyTypeString, copyName);
_log.info("Copy {} is protected by RP Site {}", copyName, internalSiteName);
TaskList taskList = new TaskList();
Map<VpoolUse, List<Recommendation>> recommendationMap = new HashMap<VpoolUse, List<Recommendation>>();
recommendationMap.put(VpoolUse.ROOT, recommendations);
return this.createVolumes(param, project, journalVarray, journalVpool, recommendationMap, taskList, task, capabilities);
}
use of com.emc.storageos.volumecontroller.RPProtectionRecommendation in project coprhd-controller by CoprHD.
the class RecoverPointScheduler method getRecommendedPools.
/**
* Returns a list of recommendations for storage pools that satisfy the request.
* The return list is sorted in increasing order by the number of resources of size X
* that the pool can satisfy, where X is the size of each resource in this request.
*
* @param rpProtectionRecommendation - RP protection recommendation
* @param varray - Virtual Array
* @param vpool - Virtual Pool
* @param haVarray - HA Virtual Array
* @param haVpool - HA Virtual Pool
* @param capabilities - Virtual Pool capabilities
* @param personality - Volume personality
* @param internalSiteName - RP internal site name
* @return - List of recommendations
*/
private List<Recommendation> getRecommendedPools(RPProtectionRecommendation rpProtectionRecommendation, VirtualArray varray, VirtualPool vpool, VirtualArray haVarray, VirtualPool haVpool, VirtualPoolCapabilityValuesWrapper capabilities, String personality, String internalSiteName) {
// TODO (Brad/Bharath): ChangeVPool doesn't add any new targets. If new targets are requested as part of the changeVpool,
// then this code needs to be enhanced to be able to handle that.
_log.info("RP Placement : Fetching pool recommendations for : " + personality);
long sizeInBytes = capabilities.getSize();
long requestedCount = capabilities.getResourceCount();
long sizeInKB = getSizeInKB(sizeInBytes);
List<Recommendation> recommendations = new ArrayList<Recommendation>();
_log.info(String.format("RP Placement : Requested size : [%s] Bytes - [%s] KB - [%s] GB", sizeInBytes, sizeInKB, SizeUtil.translateSize(sizeInBytes, SizeUtil.SIZE_GB)));
// Fetch candidate storage pools
List<StoragePool> candidatePools = getCandidatePools(varray, vpool, haVarray, haVpool, capabilities, personality);
// Get all the pools already recommended
List<RPRecommendation> poolsInAllRecommendations = rpProtectionRecommendation.getPoolsInAllRecommendations();
// Get all the pools that can satisfy the size constraint of (size * resourceCount)
List<RPRecommendation> reconsiderPools = new ArrayList<RPRecommendation>();
StringBuffer buff = new StringBuffer();
for (StoragePool storagePool : candidatePools) {
int count = Math.abs((int) (storagePool.getFreeCapacity() / (sizeInKB)));
RPRecommendation recommendedPool = getRecommendationForStoragePool(poolsInAllRecommendations, storagePool);
// pool should be capable of satisfying at least one resource of the specified size.
if (count >= 1) {
if (recommendedPool == null) {
buff.append(String.format("%nRP Placement : # of resources of size %fGB that pool %s can accomodate: %s", SizeUtil.translateSize(sizeInBytes, SizeUtil.SIZE_GB), storagePool.getLabel(), count));
// Pool not in any recommendation thus far, create a new recommendation
Recommendation recommendation = new Recommendation();
recommendation.setSourceStoragePool(storagePool.getId());
recommendation.setSourceStorageSystem(storagePool.getStorageDevice());
recommendation.setResourceCount(count);
recommendations.add(recommendation);
} else {
// Pool already consumed in recommendation, save it and reconsider if there are no unused free pools in this
// recommendation
reconsiderPools.add(recommendedPool);
}
}
}
_log.info(buff.toString());
// Append the reconsider pool list, that way the non-reconsider pools are considered first and then the reconsider pools
if (!reconsiderPools.isEmpty()) {
// Reconsider all the consumed pools and see if there is any pool that can match the cumulative size.
// Say the pool was already recommended for X resources, and the current request needed Y resources.
// The pool recommendation should satisfy X+Y to be a valid recommendation.
recommendations.addAll(placeAlreadyRecommendedPool(sizeInBytes, requestedCount, sizeInKB, reconsiderPools));
}
if (!recommendations.isEmpty()) {
// There is at least one pool that is capable of satisfying the request, return the list.
printPoolRecommendations(recommendations);
return recommendations;
}
if (personality.equals(RPHelper.SOURCE)) {
List<RPRecommendation> existingSourcePoolRecs = rpProtectionRecommendation.getSourcePoolsInRecommendation();
recommendations = placeAlreadyRecommendedPool(sizeInBytes, requestedCount, sizeInKB, existingSourcePoolRecs);
if (recommendations.isEmpty()) {
existingSourcePoolRecs = rpProtectionRecommendation.getTargetPoolsInRecommendation();
recommendations = placeAlreadyRecommendedPool(sizeInBytes, requestedCount, sizeInKB, existingSourcePoolRecs);
}
if (recommendations.isEmpty()) {
existingSourcePoolRecs = rpProtectionRecommendation.getJournalPoolsInRecommendation();
recommendations = placeAlreadyRecommendedPool(sizeInBytes, requestedCount, sizeInKB, existingSourcePoolRecs);
}
} else if (personality.equals(RPHelper.TARGET)) {
List<RPRecommendation> existingTargetPoolRecs = rpProtectionRecommendation.getTargetPoolsInRecommendation();
recommendations = placeAlreadyRecommendedPool(sizeInBytes, requestedCount, sizeInKB, existingTargetPoolRecs);
if (recommendations.isEmpty()) {
existingTargetPoolRecs = rpProtectionRecommendation.getSourcePoolsInRecommendation();
recommendations = placeAlreadyRecommendedPool(sizeInBytes, requestedCount, sizeInKB, existingTargetPoolRecs);
}
if (recommendations.isEmpty()) {
existingTargetPoolRecs = rpProtectionRecommendation.getJournalPoolsInRecommendation();
recommendations = placeAlreadyRecommendedPool(sizeInBytes, requestedCount, sizeInKB, existingTargetPoolRecs);
}
} else {
// Looking for a recommendation for RP journal. If we got here it implies that there are no "free" pools and all the recommended
// pools are already used up. Check the list of pools in journal recommendation first and filter them by the internal site
// to consider only the pools that have visibility to the internal site.
List<RPRecommendation> journalRecs = rpProtectionRecommendation.getJournalPoolsInRecommendation();
for (RPRecommendation journalRec : journalRecs) {
if (journalRec.getInternalSiteName().equals(internalSiteName)) {
StoragePool existingTargetPool = dbClient.queryObject(StoragePool.class, journalRec.getSourceStoragePool());
int count = Math.abs((int) (existingTargetPool.getFreeCapacity() / (sizeInKB)));
_log.info(String.format("%nRP Placement : # of resources of size %fGB that pool %s can accomodate: %s%n", SizeUtil.translateSize(sizeInBytes, SizeUtil.SIZE_GB), existingTargetPool.getLabel(), count));
if (count >= requestedCount + journalRec.getResourceCount()) {
recommendations.add(journalRec);
}
}
}
if (recommendations.isEmpty()) {
// Couldn't find a free pool or used pool, return all the pools that sees the same RP site as the one we are trying for a
// recommendation for.
journalRecs = rpProtectionRecommendation.getPoolsInAllRecommendations();
for (RPRecommendation journalRec : journalRecs) {
if (journalRec.getInternalSiteName().equals(internalSiteName)) {
StoragePool existingTargetPool = dbClient.queryObject(StoragePool.class, journalRec.getSourceStoragePool());
int count = Math.abs((int) (existingTargetPool.getFreeCapacity() / (sizeInKB)));
_log.info(String.format("%nRP Placement : # of resources of size %sGB that pool %s can accomodate: %s%n", SizeUtil.translateSize(sizeInBytes, SizeUtil.SIZE_GB).toString(), existingTargetPool.getLabel(), count));
if (count >= requestedCount + journalRec.getResourceCount()) {
recommendations.add(journalRec);
}
}
}
}
}
Collections.sort(recommendations, new Comparator<Recommendation>() {
@Override
public int compare(Recommendation a1, Recommendation a2) {
return ComparisonChain.start().compare(a1.getResourceCount(), a2.getResourceCount()).compare(a1.getResourceCount(), a1.getResourceCount()).result();
}
});
printPoolRecommendations(recommendations);
return recommendations;
}
use of com.emc.storageos.volumecontroller.RPProtectionRecommendation in project coprhd-controller by CoprHD.
the class RecoverPointScheduler method getRecommendationsForResources.
/**
* Select and return one or more storage pools where the volume(s)
* should be created. The placement logic is based on:
* - VirtualArray, only storage devices in the given varray are candidates
* - protection varrays
* - VirtualPool, specifies must-meet & best-meet service specifications
* - access-protocols: storage pools must support all protocols specified in CoS
* - 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 varray varray requested for source
* @param project for the storage
* @param vpool vpool requested
* @param capabilities CoS capabilities parameters
* @return list of Recommendation objects to satisfy the request
*/
@Override
public List<Recommendation> getRecommendationsForResources(VirtualArray varray, Project project, VirtualPool vpool, VirtualPoolCapabilityValuesWrapper capabilities) {
// Check to see if we need to throttle concurrent requests for the same RP CG
throttleConncurrentRequests(vpool, capabilities.getBlockConsistencyGroup());
Volume changeVpoolVolume = null;
if (capabilities.getChangeVpoolVolume() != null) {
changeVpoolVolume = dbClient.queryObject(Volume.class, URI.create(capabilities.getChangeVpoolVolume()));
_log.info(String.format("Existing volume [%s](%s) will be used as RP Source volume in recommendations.", changeVpoolVolume.getLabel(), changeVpoolVolume.getId()));
} else {
_log.info(String.format("Schedule new storage for [%s] resource(s) of size [%s].", capabilities.getResourceCount(), capabilities.getSize()));
}
List<VirtualArray> protectionVarrays = getProtectionVirtualArraysForVirtualPool(project, vpool, dbClient, _permissionsHelper);
VirtualArray haVarray = null;
VirtualPool haVpool = null;
SwapContainer container = null;
if (VirtualPool.vPoolSpecifiesHighAvailabilityDistributed(vpool)) {
container = swapSrcAndHAIfNeeded(varray, vpool);
varray = container.getSrcVarray();
vpool = container.getSrcVpool();
haVarray = container.getHaVarray();
haVpool = container.getHaVpool();
}
// Get all storage pools that match the passed Virtual Pool params and protocols.
// In addition, the pool must have enough capacity to hold at least one resource of the requested size.
List<StoragePool> candidatePools = getCandidatePools(varray, vpool, haVarray, haVpool, capabilities, RPHelper.SOURCE);
if (candidatePools == null || candidatePools.isEmpty()) {
_log.error(String.format("No matching storage pools found for the source varray: %s. 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.", varray.getLabel()));
throw APIException.badRequests.noMatchingStoragePoolsForVpoolAndVarray(vpool.getLabel(), varray.getLabel());
}
this.initResources();
List<Recommendation> recommendations = buildCgRecommendations(capabilities, vpool, protectionVarrays, changeVpoolVolume);
if (recommendations.isEmpty()) {
if (VirtualPool.vPoolSpecifiesMetroPoint(vpool)) {
_log.info("Finding recommendations for Metropoint volume placement...");
// MetroPoint has been enabled. get the HA virtual array and virtual pool. This will allow us to obtain
// candidate storage pool and secondary cluster protection recommendations.
haVarray = vplexScheduler.getHaVirtualArray(container.getSrcVarray(), project, container.getSrcVpool());
haVpool = vplexScheduler.getHaVirtualPool(container.getSrcVarray(), project, container.getSrcVpool());
// Get the candidate source pools for the distributed cluster. The 2 null params are ignored in the pool matching
// because they are used to build the HA recommendations, which will not be done if MetroPoint is enabled.
List<StoragePool> haCandidateStoragePools = getCandidatePools(haVarray, haVpool, null, null, capabilities, RPHelper.SOURCE);
// MetroPoint has been enabled so we need to obtain recommendations for the primary (active) and secondary (HA/Stand-by)
// VPlex clusters.
recommendations = createMetroPointRecommendations(container.getSrcVarray(), protectionVarrays, container.getSrcVpool(), haVarray, haVpool, project, capabilities, candidatePools, haCandidateStoragePools, changeVpoolVolume);
} else {
_log.info("Finding recommendations for RecoverPoint volume placement...");
// Schedule storage based on the source pool constraint.
recommendations = scheduleStorageSourcePoolConstraint(varray, protectionVarrays, vpool, capabilities, candidatePools, project, changeVpoolVolume, null);
}
}
// There is only one entry of type RPProtectionRecommendation ever in the returned recommendation list.
_log.info(String.format("%s %n", ((RPProtectionRecommendation) recommendations.get(0)).toString(dbClient)));
return recommendations;
}
use of com.emc.storageos.volumecontroller.RPProtectionRecommendation in project coprhd-controller by CoprHD.
the class RecoverPointScheduler method createMetroPointRecommendations.
/**
* Creates recommendations for MetroPoint. This consists of single recommendations that include
* the both the primary and secondary HA clusters and their associated RP protection details.
*
* @param srcVarray the source virtual array.
* @param tgtVarrays the target protection virtual arrays.
* @param srcVpool the source virtual pool.
* @param haVarray the HA (second cluster) virtual array.
* @param haVpool the HA (second cluster) virtual array.
* @param project the project.
* @param capabilities the capability params.
* @param candidatePrimaryPools candidate source pools to use for the primary cluster.
* @param candidateSecondaryPools candidate source pools to use for the primary cluster.
* @return list of Recommendation objects to satisfy the request
*/
private List<Recommendation> createMetroPointRecommendations(VirtualArray srcVarray, List<VirtualArray> tgtVarrays, VirtualPool srcVpool, VirtualArray haVarray, VirtualPool haVpool, Project project, VirtualPoolCapabilityValuesWrapper capabilities, List<StoragePool> candidatePrimaryPools, List<StoragePool> candidateSecondaryPools, Volume vpoolChangeVolume) {
// Initialize a list of recommendations to be returned.
List<Recommendation> recommendations = new ArrayList<Recommendation>();
RPProtectionRecommendation rpProtectionRecommendaton = null;
// Get all the matching pools for each target virtual array. If the target varray's
// vpool specifies HA, we will only look for VPLEX connected storage pools.
Map<VirtualArray, List<StoragePool>> tgtVarrayStoragePoolsMap = getVplexTargetMatchingPools(tgtVarrays, srcVpool, project, capabilities, vpoolChangeVolume);
rpProtectionRecommendaton = createRPProtectionRecommendationForMetroPoint(srcVarray, tgtVarrays, srcVpool, haVarray, haVpool, capabilities, candidatePrimaryPools, candidateSecondaryPools, tgtVarrayStoragePoolsMap, vpoolChangeVolume, project);
_log.info(String.format("Produced %s recommendations for MetroPoint placement.", rpProtectionRecommendaton.getResourceCount()));
recommendations.add(rpProtectionRecommendaton);
return recommendations;
}
Aggregations