use of com.emc.storageos.volumecontroller.RPRecommendation in project coprhd-controller by CoprHD.
the class RecoverPointScheduler method scheduleStorageSourcePoolConstraint.
/**
* Schedule storage based on the incoming storage pools for source volumes. (New version)
*
* @param varray varray requested for source
* @param protectionVarrays Neighborhood to protect this volume to.
* @param vpool vpool requested
* @param capabilities parameters
* @param candidatePools List of StoragePools already populated to choose from. RP+VPLEX.
* @param vpoolChangeVolume vpool change volume, if applicable
* @param preSelectedCandidateProtectionPoolsMap pre-populated map for tgt varray to storage pools, use null if not needed
* @return list of Recommendation objects to satisfy the request
*/
protected List<Recommendation> scheduleStorageSourcePoolConstraint(VirtualArray varray, List<VirtualArray> protectionVarrays, VirtualPool vpool, VirtualPoolCapabilityValuesWrapper capabilities, List<StoragePool> candidatePools, Project project, Volume vpoolChangeVolume, Map<VirtualArray, List<StoragePool>> preSelectedCandidateProtectionPoolsMap) {
// Initialize a list of recommendations to be returned.
List<Recommendation> recommendations = new ArrayList<Recommendation>();
String candidateSourceInternalSiteName = "";
placementStatus = new PlacementStatus();
// Attempt to use these pools for selection based on protection
StringBuffer sb = new StringBuffer("Determining if protection is possible from " + varray.getId() + " to: ");
for (VirtualArray protectionVarray : protectionVarrays) {
sb.append(protectionVarray.getId()).append(" ");
}
_log.info(sb.toString());
// BEGIN: Put the local varray first in the list. We want to give him pick of internal site name.
int index = -1;
for (VirtualArray targetVarray : protectionVarrays) {
if (targetVarray.getId().equals(varray.getId())) {
index = protectionVarrays.indexOf(targetVarray);
break;
}
}
if (index > 0) {
VirtualArray localVarray = protectionVarrays.get(index);
VirtualArray swapVarray = protectionVarrays.get(0);
protectionVarrays.set(0, localVarray);
protectionVarrays.set(index, swapVarray);
}
// END: Put the local varray first in the list. We want to give him pick of internal site name.
List<URI> protectionVarrayURIs = new ArrayList<URI>();
for (VirtualArray vArray : protectionVarrays) {
protectionVarrayURIs.add(vArray.getId());
placementStatus.getProcessedProtectionVArrays().put(vArray.getId(), false);
}
// Fetch the list of pools for the source journal if a journal virtual pool is specified to be used for journal volumes.
VirtualArray journalVarray = varray;
if (NullColumnValueGetter.isNotNullValue(vpool.getJournalVarray())) {
journalVarray = dbClient.queryObject(VirtualArray.class, URI.create(vpool.getJournalVarray()));
}
VirtualPool journalVpool = vpool;
if (NullColumnValueGetter.isNotNullValue(vpool.getJournalVpool())) {
journalVpool = dbClient.queryObject(VirtualPool.class, URI.create(vpool.getJournalVpool()));
}
// The attributes below will not change throughout the placement process
placementStatus.setSrcVArray(varray.getLabel());
placementStatus.setSrcVPool(vpool.getLabel());
BlockConsistencyGroup cg = dbClient.queryObject(BlockConsistencyGroup.class, capabilities.getBlockConsistencyGroup());
int totalRequestedCount = capabilities.getResourceCount();
int totalSatisfiedCount = 0;
int requestedCount = totalRequestedCount;
int satisfiedCount = 0;
boolean isChangeVpool = (vpoolChangeVolume != null);
RPProtectionRecommendation rpProtectionRecommendation = new RPProtectionRecommendation();
rpProtectionRecommendation.setVpoolChangeVolume(vpoolChangeVolume != null ? vpoolChangeVolume.getId() : null);
rpProtectionRecommendation.setVpoolChangeNewVpool(vpoolChangeVolume != null ? vpool.getId() : null);
rpProtectionRecommendation.setVpoolChangeProtectionAlreadyExists(vpoolChangeVolume != null ? vpoolChangeVolume.checkForRp() : false);
List<Recommendation> sourcePoolRecommendations = new ArrayList<Recommendation>();
if (isChangeVpool) {
Recommendation changeVpoolSourceRecommendation = new Recommendation();
URI existingStoragePoolId = null;
// valid source pool, the existing one. Get that pool and add it to the list.
if (RPHelper.isVPlexVolume(vpoolChangeVolume, dbClient)) {
if (null == vpoolChangeVolume.getAssociatedVolumes() || vpoolChangeVolume.getAssociatedVolumes().isEmpty()) {
_log.error("VPLEX volume {} has no backend volumes.", vpoolChangeVolume.forDisplay());
throw InternalServerErrorException.internalServerErrors.noAssociatedVolumesForVPLEXVolume(vpoolChangeVolume.forDisplay());
}
for (String associatedVolume : vpoolChangeVolume.getAssociatedVolumes()) {
Volume assocVol = dbClient.queryObject(Volume.class, URI.create(associatedVolume));
if (assocVol.getVirtualArray().equals(varray.getId())) {
existingStoragePoolId = assocVol.getPool();
break;
}
}
} else {
existingStoragePoolId = vpoolChangeVolume.getPool();
}
// This is the existing active source backing volume
changeVpoolSourceRecommendation.setSourceStoragePool(existingStoragePoolId);
StoragePool pool = dbClient.queryObject(StoragePool.class, existingStoragePoolId);
changeVpoolSourceRecommendation.setSourceStorageSystem(pool.getStorageDevice());
changeVpoolSourceRecommendation.setResourceCount(1);
sourcePoolRecommendations.add(changeVpoolSourceRecommendation);
_log.info(String.format("RP Placement : Change Virtual Pool - Active source pool already exists, reuse pool: [%s] [%s].", pool.getLabel().toString(), pool.getId().toString()));
} else {
// Recommendation analysis:
// Each recommendation returned will indicate the number of resources of specified size that it can accommodate in ascending order.
// Go through each recommendation, map to storage system from the recommendation to find connectivity
// If we get through the process and couldn't achieve full protection, we should try with the next pool in the list until
// we either find a successful solution or failure.
sourcePoolRecommendations = getRecommendedPools(rpProtectionRecommendation, varray, vpool, null, null, capabilities, RPHelper.SOURCE, null);
if (sourcePoolRecommendations == null || sourcePoolRecommendations.isEmpty()) {
_log.error(String.format("RP Placement : 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());
}
}
for (Recommendation sourcePoolRecommendation : sourcePoolRecommendations) {
satisfiedCount = ((sourcePoolRecommendation.getResourceCount()) >= requestedCount) ? requestedCount : sourcePoolRecommendation.getResourceCount();
_log.info("Looking to place " + satisfiedCount + " resources...");
// Start with the top of the list of source pools, find a solution based on that.
// Given the candidatePools.get(0), what protection systems and internal sites protect it?
Set<ProtectionSystem> protectionSystems = new HashSet<ProtectionSystem>();
ProtectionSystem cgProtectionSystem = getCgProtectionSystem(capabilities.getBlockConsistencyGroup());
StoragePool sourcePool = dbClient.queryObject(StoragePool.class, sourcePoolRecommendation.getSourceStoragePool());
// used by other volumes in it.
if (cgProtectionSystem != null) {
_log.info(String.format("RP Placement : Narrowing down placement to use ProtectionSystem %s, " + "which is currently used by RecoverPoint consistency group %s.", cgProtectionSystem.getLabel(), cg));
protectionSystems.add(cgProtectionSystem);
} else {
protectionSystems = getProtectionSystemsForStoragePool(sourcePool, varray, VirtualPool.vPoolSpecifiesHighAvailability(vpool));
// Verify that the candidate pool can be protected
if (protectionSystems.isEmpty()) {
continue;
}
}
// Sort the ProtectionSystems based on the last time a CG was created. Always use the
// ProtectionSystem with the oldest cgLastCreated timestamp to support a round-robin
// style of load balancing.
List<ProtectionSystem> protectionSystemsLst = sortProtectionSystems(protectionSystems);
for (ProtectionSystem candidateProtectionSystem : protectionSystemsLst) {
Calendar cgLastCreated = candidateProtectionSystem.getCgLastCreatedTime();
_log.info(String.format("RP Placement : Attempting to use ProtectionSystem %s, which was last used to create a CG on %s.", candidateProtectionSystem.getLabel(), cgLastCreated != null ? cgLastCreated.getTime().toString() : "N/A"));
List<String> associatedStorageSystems = new ArrayList<String>();
String internalSiteNameandAssocStorageSystem = getCgSourceInternalSiteNameAndAssociatedStorageSystem(capabilities.getBlockConsistencyGroup());
// source internal site.
if (internalSiteNameandAssocStorageSystem != null) {
_log.info(String.format("RP Placement : Narrowing down placement to use internal site %s for source, " + "which is currently used by RecoverPoint consistency group %s.", internalSiteNameandAssocStorageSystem, cg));
associatedStorageSystems.add(internalSiteNameandAssocStorageSystem);
} else {
associatedStorageSystems = getCandidateVisibleStorageSystems(sourcePool, candidateProtectionSystem, varray, protectionVarrays, VirtualPool.vPoolSpecifiesHighAvailability(vpool));
}
// make sure you check RP topology to see if the sites can protect that many targets
if (associatedStorageSystems.isEmpty()) {
// no rp site clusters connected to this storage system, should not hit this, but just to be safe we'll catch it
_log.info(String.format("RP Placement: Protection System %s does not have an RP internal site connected to Storage pool %s ", candidateProtectionSystem.getLabel(), sourcePool.getLabel()));
continue;
}
for (String associatedStorageSystem : associatedStorageSystems) {
_log.info(String.format("RP Placement : Attempting to find solution using StorageSystem : %s for RP source", associatedStorageSystem));
rpProtectionRecommendation.setProtectionDevice(candidateProtectionSystem.getId());
_log.info(String.format("RP Placement : Build RP Source Recommendation..."));
RPRecommendation rpSourceRecommendation = buildSourceRecommendation(associatedStorageSystem, varray, vpool, candidateProtectionSystem, sourcePool, capabilities, satisfiedCount, placementStatus, vpoolChangeVolume, false);
if (rpSourceRecommendation == null) {
// No placement found for the associatedStorageSystem, so continue.
_log.warn(String.format("RP Placement : Could not create Source Recommendation using [%s], continuing...", associatedStorageSystem));
continue;
}
candidateSourceInternalSiteName = rpSourceRecommendation.getInternalSiteName();
String siteName = candidateProtectionSystem.getRpSiteNames().get(candidateSourceInternalSiteName);
_log.info(String.format("RP Placement : Choosing RP internal site %s %s for source", siteName, candidateSourceInternalSiteName));
// Build the HA recommendation if HA is specified
VirtualPoolCapabilityValuesWrapper haCapabilities = new VirtualPoolCapabilityValuesWrapper(capabilities);
haCapabilities.put(VirtualPoolCapabilityValuesWrapper.RESOURCE_COUNT, satisfiedCount);
RPRecommendation haRecommendation = this.getHaRecommendation(varray, vpool, project, haCapabilities);
if (haRecommendation != null) {
rpSourceRecommendation.setHaRecommendation(haRecommendation);
}
// Build Source Journal Recommendation
RPRecommendation sourceJournalRecommendation = null;
if (rpProtectionRecommendation.getSourceJournalRecommendation() == null) {
_log.info(String.format("RP Placement : Build RP Source Journal Recommendation..."));
sourceJournalRecommendation = buildJournalRecommendation(rpProtectionRecommendation, candidateSourceInternalSiteName, vpool.getJournalSize(), journalVarray, journalVpool, candidateProtectionSystem, capabilities, totalRequestedCount, vpoolChangeVolume, false);
if (sourceJournalRecommendation == null) {
_log.warn(String.format("RP Placement : Could not create Source Journal Recommendation using [%s], continuing...", associatedStorageSystem));
continue;
}
}
rpProtectionRecommendation.getSourceRecommendations().add(rpSourceRecommendation);
rpProtectionRecommendation.setSourceJournalRecommendation(sourceJournalRecommendation);
// If we made it this far we know that our source virtual pool and associated source virtual array
// has a storage pool with enough capacity for the requested resources and which is accessible to an rp
// cluster site
rpProtectionRecommendation.setPlacementStepsCompleted(PlacementProgress.IDENTIFIED_SOLUTION_FOR_SOURCE);
if (placementStatus.isBestSolutionToDate(rpProtectionRecommendation)) {
placementStatus.setLatestInvalidRecommendation(rpProtectionRecommendation);
}
// TODO Joe: need this when we are creating multiple recommendations
placementStatus.setLatestInvalidRecommendation(null);
// Find a solution, given this vpool, and the target varrays
if (findSolution(rpProtectionRecommendation, rpSourceRecommendation, varray, vpool, protectionVarrays, capabilities, satisfiedCount, false, null, project)) {
// Found Source, Source Journal, Target, Target Journals...we're good to go.
totalSatisfiedCount += satisfiedCount;
requestedCount = requestedCount - totalSatisfiedCount;
if ((totalSatisfiedCount >= totalRequestedCount)) {
// Check to ensure the protection system can handle the new resources about to come down
if (!verifyPlacement(candidateProtectionSystem, rpProtectionRecommendation, rpProtectionRecommendation.getResourceCount())) {
// Did not pass placement verification, back out and try again...
rpProtectionRecommendation.getSourceRecommendations().remove(rpSourceRecommendation);
rpProtectionRecommendation.setSourceJournalRecommendation(null);
_log.warn(String.format("RP Placement : Placement could not be verified with " + "current resources, trying placement again...", associatedStorageSystem));
continue;
}
rpProtectionRecommendation.setResourceCount(totalSatisfiedCount);
recommendations.add(rpProtectionRecommendation);
return recommendations;
} else {
break;
}
} else {
// Not sure there's anything to do here. Just go to the next candidate protection system or Protection System
_log.info(String.format("RP Placement : Could not find a solution against ProtectionSystem %s " + "and internal site %s", candidateProtectionSystem.getLabel(), candidateSourceInternalSiteName));
rpProtectionRecommendation = getNewProtectionRecommendation(vpoolChangeVolume, vpool);
}
}
// end of for loop trying to find solution using possible rp cluster sites
rpProtectionRecommendation = getNewProtectionRecommendation(vpoolChangeVolume, vpool);
}
// end of protection systems for loop
}
// we went through all the candidate pools and there are still some of the volumes that haven't been placed, then we failed to find
// a solution
_log.error("RP Placement : ViPR could not find matching storage pools that could be protected via RecoverPoint");
throw APIException.badRequests.cannotFindSolutionForRP(placementStatus.toString(dbClient));
}
use of com.emc.storageos.volumecontroller.RPRecommendation in project coprhd-controller by CoprHD.
the class RecoverPointScheduler method fireProtectionPlacementRules.
/**
* Executes a set of business rules against the <code>List</code> of <code>ProtectionPoolMapping</code> objects to determine if they are
* capable to perform
* volume protection. The statistics are pulled from the <code>ProtectionSystem</code> and are used in executing the following business
* rules:
* <p>
* <ul>
* <li>The RP cluster (ProtectionSystem) must have the capacity to create a single CG.</li>
* <li>Each RP site must have the volume capacity to create the required number of volumes.</li>
* </ul>
*
* @param protectionSystem
* @param rpRec
* @param resourceCount number of volumes being requested for creation/protection
* @return true if recommendation can be handled by protection system
*/
private boolean fireProtectionPlacementRules(ProtectionSystem protectionSystem, RPProtectionRecommendation rpRec, Integer resourceCount) {
// Log messages used within this method - Use String.format()
final String cgCountLog = "CG count for Protection System %s is %s/%s";
final String cgNoCapacityLog = "Protection System %s does not have the CG capacity to protect volumes.";
final String sourceSiteVolumeCountLog = "Volume count for Protection System %s/site %s (source) is %s/%s";
final String destSiteVolumeCountLog = "Volume count for Protection System %s/site %s (destination) is %s/%s";
final String sourceSiteVolumeNoCapacityLog = "Protection System %s/site %s (source) does not have the volume capacity to protect volumes. " + "Requires capacity for %s volume(s).";
final String destSiteVolumeNoCapacityLog = "Protection System %s/site %s (destination) does not have the volume capacity to protect volumes. " + "Requires capacity for %s volume(s).";
final String parseSiteStatsLog = "A problem occurred parsing site volume statistics for Protection System %s. " + "Protection system is unable to protect volumes: %s";
final String missingProtectionSystemMetric = "RecoverPoint metric '%s' for Protection System %s cannot be found. " + "Unable to determine if the protection system is capable of protection volumes.";
final String missingSiteMetric = "RecoverPoint metric '%s' for Protection System %s/Site %s cannot be found. Unable " + "to determine if the protection system is capable of protection volumes.";
final String validProtectionSystem = "RecoverPoint Protection System '%s' is capable of protecting the requested volumes.";
final String inValidProtectionSystem = "RecoverPoint Protection System '%s' is not capable of protecting the requested volumes.";
final String validatingProtection = "Validating protection systems to ensure they are capable of handling a protection for %s" + " production volume(s).";
_log.info(String.format(validatingProtection, resourceCount));
boolean isValid = true;
Long rpCGCapacity = protectionSystem.getCgCapacity();
Long rpCurrentCGCount = protectionSystem.getCgCount();
if (rpCGCapacity == null) {
_log.warn(String.format(missingProtectionSystemMetric, "CG Capacity", protectionSystem));
rpCGCapacity = -1L;
}
if (rpCurrentCGCount == null) {
_log.warn(String.format(missingProtectionSystemMetric, "CG Count", protectionSystem));
rpCurrentCGCount = -1L;
}
long rpAvailableCGCapacity = rpCGCapacity - rpCurrentCGCount;
// Log the CG count.
_log.info(String.format(cgCountLog, protectionSystem.getLabel(), rpCurrentCGCount, rpCGCapacity));
// Is there enough CG capacity on the RP cluster?
if (rpAvailableCGCapacity < 1) {
isValid = false;
_log.info(String.format(cgNoCapacityLog, protectionSystem));
rpRec.setProtectionSystemCriteriaError(String.format(cgNoCapacityLog, protectionSystem));
}
// Only process the site statistics if the Protection System statistics
// are adequate for protection.
StringMap siteVolumeCapacity = protectionSystem.getSiteVolumeCapacity();
StringMap siteVolumeCount = protectionSystem.getSiteVolumeCount();
List<RPRecommendation> sourceRecommendation = rpRec.getSourceRecommendations();
String sourceInternalSiteName = sourceRecommendation.iterator().next().getInternalSiteName();
if (siteVolumeCount != null && siteVolumeCount.size() > 0) {
String sourceSiteVolumeCount = siteVolumeCount.get(String.valueOf(sourceInternalSiteName));
String sourceSiteVolumeCapacity = siteVolumeCapacity.get(String.valueOf(sourceInternalSiteName));
if (sourceSiteVolumeCount == null) {
_log.warn(String.format(missingSiteMetric, "Source Site Volume Count", protectionSystem, rpRec.getResourceCount()));
sourceSiteVolumeCount = "-1";
}
if (sourceSiteVolumeCapacity == null) {
_log.warn(String.format(missingSiteMetric, "Source Site Volume Capacity", protectionSystem, sourceInternalSiteName));
sourceSiteVolumeCapacity = "-1";
}
try {
// Get the source site available capacity.
long sourceSiteAvailableVolCapacity = Long.parseLong(sourceSiteVolumeCapacity) - Long.parseLong(sourceSiteVolumeCount);
_log.debug(String.format(sourceSiteVolumeCountLog, protectionSystem, sourceInternalSiteName, sourceSiteVolumeCount, sourceSiteVolumeCapacity));
// If the source site available capacity is not adequate, log a message.
if (sourceSiteAvailableVolCapacity < rpRec.getNumberOfVolumes(sourceInternalSiteName)) {
isValid = false;
_log.info(String.format(sourceSiteVolumeNoCapacityLog, protectionSystem, sourceInternalSiteName, resourceCount));
rpRec.setProtectionSystemCriteriaError(String.format(sourceSiteVolumeNoCapacityLog, protectionSystem, sourceInternalSiteName, resourceCount));
}
} catch (NumberFormatException nfe) {
// Catch any exceptions that occur while parsing the site specific values
isValid = false;
_log.info(String.format(parseSiteStatsLog, protectionSystem, nfe.getMessage()));
rpRec.setProtectionSystemCriteriaError(String.format(parseSiteStatsLog, protectionSystem, nfe.getMessage()));
}
for (RPRecommendation sourceRec : rpRec.getSourceRecommendations()) {
for (RPRecommendation targetRec : sourceRec.getTargetRecommendations()) {
String internalSiteName = targetRec.getInternalSiteName();
String destSiteVolumeCount = siteVolumeCount.get(String.valueOf(internalSiteName));
String destSiteVolumeCapacity = siteVolumeCapacity.get(String.valueOf(internalSiteName));
if (destSiteVolumeCount == null) {
_log.warn(String.format(missingSiteMetric, "Destination Site Volume Count", protectionSystem, internalSiteName));
destSiteVolumeCount = "-1";
}
if (destSiteVolumeCapacity == null) {
_log.warn(String.format(missingSiteMetric, "Destination Site Volume Capacity", protectionSystem, internalSiteName));
destSiteVolumeCapacity = "-1";
}
try {
// Get the destination site available capacity.
long destSiteAvailableVolCapacity = Long.parseLong(destSiteVolumeCapacity) - Long.parseLong(destSiteVolumeCount);
_log.debug(String.format(destSiteVolumeCountLog, protectionSystem, internalSiteName, destSiteVolumeCount, destSiteVolumeCapacity));
// If the destination site available capacity is not adequate, log a message.
if (destSiteAvailableVolCapacity < rpRec.getNumberOfVolumes(targetRec.getInternalSiteName())) {
isValid = false;
_log.info(String.format(destSiteVolumeNoCapacityLog, protectionSystem, internalSiteName, rpRec.getResourceCount()));
rpRec.setProtectionSystemCriteriaError(String.format(destSiteVolumeNoCapacityLog, protectionSystem, internalSiteName, rpRec.getResourceCount()));
}
} catch (NumberFormatException nfe) {
// Catch any exceptions that occur while parsing the site specific values
isValid = false;
_log.info(String.format(parseSiteStatsLog, protectionSystem, nfe.getMessage()));
rpRec.setProtectionSystemCriteriaError(String.format(parseSiteStatsLog, protectionSystem, nfe.getMessage()));
}
}
}
} else {
// There are no site volume statistics available so assume volume
// protection cannot be achieved.
isValid = false;
_log.warn(String.format(missingProtectionSystemMetric, "Site Volume Capacity/Count", protectionSystem));
rpRec.setProtectionSystemCriteriaError(String.format(missingProtectionSystemMetric, "Site Volume Capacity/Count", protectionSystem));
}
// log a message is the protection system is valid.
if (isValid) {
_log.debug(String.format(validProtectionSystem, protectionSystem));
} else {
_log.debug(String.format(inValidProtectionSystem, protectionSystem));
}
return isValid;
}
use of com.emc.storageos.volumecontroller.RPRecommendation in project coprhd-controller by CoprHD.
the class RecoverPointScheduler method buildJournalRecommendation.
/**
* Builds the journal placement recommendation
*
* @param rpProtectionRecommendation - RP Protection recommendation
* @param internalSiteName - RP site name
* @param journalPolicy - Journal Policy
* @param journalVarray - Virtual Array
* @param journalVpool - Virtual Pool
* @param ps - Protection system
* @param capabilities - Virtual Pool capabilities
* @param requestedResourceCount - Resource count satisfied in this recommendation.
* For journals, it is always 1 as we don't fragment journal over multiple pools.
* @param vpoolChangeVolume - change Virtual Pool param
* @param isMPStandby - indicates if this a MetroPoint and if this is a recommendation for the standby-site
* @return - Recommendation for journal
*/
public RPRecommendation buildJournalRecommendation(RPProtectionRecommendation rpProtectionRecommendation, String internalSiteName, String journalPolicy, VirtualArray journalVarray, VirtualPool journalVpool, ProtectionSystem ps, VirtualPoolCapabilityValuesWrapper capabilities, int requestedResourceCount, Volume vpoolChangeVolume, boolean isMPStandby) {
VirtualPoolCapabilityValuesWrapper newCapabilities = getJournalCapabilities(journalPolicy, capabilities, requestedResourceCount);
boolean foundJournal = false;
List<Recommendation> journalRec = getRecommendedPools(rpProtectionRecommendation, journalVarray, journalVpool, null, null, newCapabilities, RPHelper.JOURNAL, internalSiteName);
// Represents the journal storage pool or backing array storage pool in case of VPLEX
StoragePool journalStoragePool = null;
// Represents the journal storage system
URI storageSystemURI = null;
// Primary source journal remains what it was before the change Vpool operation.
if (vpoolChangeVolume != null && vpoolChangeVolume.checkForRp() && !isMPStandby) {
List<Volume> existingJournalVolumes = RPHelper.findExistingJournalsForCopy(dbClient, vpoolChangeVolume.getConsistencyGroup(), vpoolChangeVolume.getRpCopyName());
Volume existingJournalVolume = existingJournalVolumes.get(0);
if (existingJournalVolume == null) {
_log.error(String.format("No existing journal found in CG [%s] for copy [%s], returning false", vpoolChangeVolume.getConsistencyGroup(), vpoolChangeVolume.getRpCopyName()));
throw APIException.badRequests.unableToFindSuitableJournalRecommendation();
}
if (RPHelper.isVPlexVolume(existingJournalVolume, dbClient)) {
if (null == existingJournalVolume.getAssociatedVolumes() || existingJournalVolume.getAssociatedVolumes().isEmpty()) {
_log.error("VPLEX volume {} has no backend volumes.", existingJournalVolume.forDisplay());
throw InternalServerErrorException.internalServerErrors.noAssociatedVolumesForVPLEXVolume(existingJournalVolume.forDisplay());
}
URI backingVolumeURI = URI.create(existingJournalVolume.getAssociatedVolumes().iterator().next());
Volume backingVolume = dbClient.queryObject(Volume.class, backingVolumeURI);
journalStoragePool = dbClient.queryObject(StoragePool.class, backingVolume.getPool());
} else {
journalStoragePool = dbClient.queryObject(StoragePool.class, existingJournalVolume.getPool());
}
storageSystemURI = existingJournalVolume.getStorageController();
foundJournal = true;
} else {
for (Recommendation journalStoragePoolRec : journalRec) {
journalStoragePool = dbClient.queryObject(StoragePool.class, journalStoragePoolRec.getSourceStoragePool());
_log.info(String.format("RP Journal Placement : Checking pool : [%s]", journalStoragePool.getLabel()));
List<String> associatedStorageSystems = getCandidateTargetVisibleStorageSystems(ps.getId(), journalVarray, internalSiteName, journalStoragePool, VirtualPool.vPoolSpecifiesHighAvailability(journalVpool));
if (associatedStorageSystems == null || associatedStorageSystems.isEmpty()) {
_log.info(String.format("RP Journal Placement Solution cannot be found using target pool " + journalStoragePool.getLabel() + " there is no connectivity to rp cluster sites."));
continue;
}
_log.info(String.format("RP Journal Placement : Associated storage systems for pool [%s] : [%s]", journalStoragePool.getLabel(), Joiner.on("-").join(associatedStorageSystems)));
for (String associateStorageSystem : associatedStorageSystems) {
storageSystemURI = ConnectivityUtil.findStorageSystemBySerialNumber(ProtectionSystem.getAssociatedStorageSystemSerialNumber(associateStorageSystem), dbClient, StorageSystemType.BLOCK);
StorageSystem storageSystem = dbClient.queryObject(StorageSystem.class, storageSystemURI);
if (!isRpSiteConnectedToVarray(storageSystemURI, ps.getId(), internalSiteName, journalVarray)) {
_log.info(String.format("RP Journal Placement : StorageSystem [%s] does NOT have connectivity to RP site [%s], ignoring..", storageSystem.getLabel(), internalSiteName));
continue;
}
// Found a solution
foundJournal = true;
break;
}
if (foundJournal) {
break;
}
}
}
if (foundJournal) {
StorageSystem storageSystem = dbClient.queryObject(StorageSystem.class, storageSystemURI);
// If we got here, it means that we found a valid storage pool for journal, return back the recommendation
RPRecommendation journalRecommendation = buildRpRecommendation(storageSystem.getLabel(), journalVarray, journalVpool, journalStoragePool, newCapabilities, newCapabilities.getResourceCount(), internalSiteName, storageSystemURI, storageSystem.getSystemType(), ps);
_log.info(String.format("RP Journal Placement : Journal Recommendation %s %n", journalRecommendation.toString(dbClient, ps)));
return journalRecommendation;
}
// Couldn't find a journal recommendation
_log.info(String.format("RP Journal Placement : Unable to determine placement for RP journal on site %s", internalSiteName));
return null;
}
use of com.emc.storageos.volumecontroller.RPRecommendation in project coprhd-controller by CoprHD.
the class RecoverPointScheduler method buildSourceRecommendation.
/**
* Builds the source placement recommendation based on the source pool and its associated storage
* system/RP site.
*
* @param associatedStorageSystem - he associated RP site + storage system concatenated in a single string.
* @param varray - Virtual Array
* @param vpool - Virtual Pool
* @param ps - Protection System
* @param sourcePool - recommended storage pool
* @param capabilities - Virtual Pool capabilities
* @param satisfiedSourceVolCount - resource count that is satisfied in the recommendation
* @param placementStat - Placement status to update
* @param vpoolChangeVolume - change Virtual Pool param
* @param isMPStandby - indicates if this a MetroPoint and if this is a recommendation for the standby-site
* @return - Recommendation for source
*/
private RPRecommendation buildSourceRecommendation(String associatedStorageSystem, VirtualArray varray, VirtualPool vpool, ProtectionSystem ps, StoragePool sourcePool, VirtualPoolCapabilityValuesWrapper capabilities, int satisfiedSourceVolCount, PlacementStatus placementStat, Volume vpoolChangeVolume, boolean isMPStandby) {
String sourceInternalSiteName = ProtectionSystem.getAssociatedStorageSystemSiteName(associatedStorageSystem);
URI sourceStorageSytemUri = ConnectivityUtil.findStorageSystemBySerialNumber(ProtectionSystem.getAssociatedStorageSystemSerialNumber(associatedStorageSystem), dbClient, StorageSystemType.BLOCK);
if (!isRpSiteConnectedToVarray(sourceStorageSytemUri, ps.getId(), sourceInternalSiteName, varray)) {
_log.info(String.format("RP Placement: Disqualified RP site [%s] because its initiators are not in a network configured " + "for use by the virtual array [%s]", sourceInternalSiteName, varray.getLabel()));
_log.info("Please recheck the Copy/Site Name {} and Virtual Array {} you have selected." + "Eg: varray associated with Stand-by site must be selected if you have selected Stand-by Copy Name.", sourceInternalSiteName, varray.getLabel());
return null;
}
URI storageSystemUri = ConnectivityUtil.findStorageSystemBySerialNumber(ProtectionSystem.getAssociatedStorageSystemSerialNumber(associatedStorageSystem), dbClient, StorageSystemType.BLOCK);
StorageSystem storageSystem = dbClient.queryObject(StorageSystem.class, storageSystemUri);
String type = storageSystem.getSystemType();
RPRecommendation rpRecommendation = buildRpRecommendation(associatedStorageSystem, varray, vpool, sourcePool, capabilities, satisfiedSourceVolCount, sourceInternalSiteName, sourceStorageSytemUri, type, ps);
String rpPlacementType = "Source recommendation ";
if (isMPStandby) {
rpPlacementType = "Standby recommendation";
}
_log.info(String.format("RP Placement : %s %s %n", rpPlacementType, rpRecommendation.toString(dbClient, ps)));
return rpRecommendation;
}
use of com.emc.storageos.volumecontroller.RPRecommendation in project coprhd-controller by CoprHD.
the class RPBlockServiceApiImpl method prepareRpJournals.
/**
* Prepares all the journal volumes and populates the values into the sourceJournals and/or
* the targetJournals map.
*
* @param rpProtectionRec
* - The main rec object
* @param project
* - The project
* @param consistencyGroup
* - The CG
* @param vpool
* - The vpool (potentially swapped)
* @param originalVpool
* - The original vpool
* @param param
* - Volume create param
* @param numberOfVolumesInRequest
* - Number of volumes to create
* @param newVolumeLabel
* - Label of volume
* @param isChangeVpoolForProtectedVolume
* - Flag for protected change vpool op
* @param capabilities
* - Capabilities object
* @param protectionSystemURI
* - Protection System being used
* @param taskList
* - Task List
* @param task
* - Task
* @param descriptors
* - List of all descriptors to be added
* @param volumeURIs
* - List to store all the volume URIs
* @param volumeInfoBuffer
* - Buffer for volume info to be printed
* @param sourceCopyName
* - Source Copy Name
* @param standbySourceCopyName
* - Standby Copy Name
*/
private void prepareRpJournals(RPProtectionRecommendation rpProtectionRec, Project project, BlockConsistencyGroup consistencyGroup, VirtualPool vpool, VirtualPool originalVpool, VolumeCreate param, Integer numberOfVolumesInRequest, String newVolumeLabel, boolean isChangeVpoolForProtectedVolume, VirtualPoolCapabilityValuesWrapper capabilities, URI protectionSystemURI, TaskList taskList, String task, List<VolumeDescriptor> descriptors, List<URI> volumeURIs, StringBuffer volumeInfoBuffer, String sourceCopyName, String standbySourceCopyName) throws Exception {
Volume sourceJournal = null;
Volume standbyJournal = null;
// This boolean indicates that the operation is only for adding additional journals.
// When adding additional journals, there is the option to add multiple new journals,
// however, for all other creates we are either re-using an existing journal or
// just creating a single journal.
// i.e. the majority of the time we are only creating a single journal.
boolean journalOnlyCreate = capabilities.getAddJournalCapacity();
RPRecommendation sourceJournalRec = rpProtectionRec.getSourceJournalRecommendation();
RPRecommendation standbyJournalRec = rpProtectionRec.getStandbyJournalRecommendation();
// Only check for existing source journals if this is not a direct journal add operation.
if (!journalOnlyCreate) {
if (sourceJournalRec == null) {
_log.info(String.format("Re-use existing Source Journal for copy [%s]", sourceCopyName));
// If the CG contains volumes already and no new additional journals are provisioned,
// then we simply update the reference on the source for the journal volume.
List<Volume> existingSourceJournals = RPHelper.findExistingJournalsForCopy(_dbClient, consistencyGroup.getId(), sourceCopyName);
sourceJournal = existingSourceJournals.get(0);
_log.info(String.format("Existing Primary Source Journal: [%s] (%s)", sourceJournal.getLabel(), sourceJournal.getId()));
if (VirtualPool.vPoolSpecifiesMetroPoint(vpool) && !isChangeVpoolForProtectedVolume) {
_log.info(String.format("Re-use existing Standby Journal for copy [%s]", standbySourceCopyName));
List<Volume> existingStandbyJournals = RPHelper.findExistingJournalsForCopy(_dbClient, consistencyGroup.getId(), standbySourceCopyName);
standbyJournal = existingStandbyJournals.get(0);
_log.info(String.format("Existing Standby Source Journal: [%s] (%s)", standbyJournal.getLabel(), standbyJournal.getId()));
}
}
}
// /////// ACTIVE SOURCE JOURNAL ///////////
if (!isChangeVpoolForProtectedVolume && (sourceJournal == null) && sourceJournalRec != null) {
_log.info("Create Active Source Journal...");
// varray is used to get unique journal volume names
VirtualArray varray = _dbClient.queryObject(VirtualArray.class, sourceJournalRec.getVirtualArray());
// Number of journals to create
int numberOfJournalVolumesInRequest = sourceJournalRec.getResourceCount();
// Force resource count to 1 here because we're using numberOfJournalVolumesInRequest to create the
// correct number of journal resources.
sourceJournalRec.setResourceCount(1);
for (int volumeCount = 0; volumeCount < numberOfJournalVolumesInRequest; volumeCount++) {
// acquire a lock so it's possible to get a unique name for the volume
String lockKey = new StringBuilder(consistencyGroup.getLabel()).append("-").append(varray.getLabel()).toString();
InterProcessLockHolder lock = null;
try {
_log.info("Attempting to acquire lock: " + lockKey);
lock = InterProcessLockHolder.acquire(_coordinator, lockKey, _log, LOCK_WAIT_MILLISECONDS);
// get a unique journal volume name
String journalName = RPHelper.createJournalVolumeName(varray, consistencyGroup, _dbClient);
// Create source journal
sourceJournal = createRecoverPointVolume(sourceJournalRec, journalName, project, capabilities, consistencyGroup, param, protectionSystemURI, Volume.PersonalityTypes.METADATA, JOURNAL_RSET, null, null, taskList, task, sourceCopyName, descriptors, null, false, false, true);
} finally {
if (lock != null) {
lock.close();
}
}
volumeURIs.add(sourceJournal.getId());
volumeInfoBuffer.append(logVolumeInfo(sourceJournal));
}
}
// /////// STANDBY SOURCE JOURNAL ///////////
if (standbyJournal == null && standbyJournalRec != null) {
_log.info("Create Standby Source Journal...");
// varray is used to get unique journal volume names
VirtualArray varray = _dbClient.queryObject(VirtualArray.class, standbyJournalRec.getVirtualArray());
// Number of journals to create
int numberOfJournalVolumesInRequest = standbyJournalRec.getResourceCount();
// Force resource count to 1 here because we're using numberOfJournalVolumesInRequest to create the
// correct number of journal resources.
standbyJournalRec.setResourceCount(1);
for (int volumeCount = 0; volumeCount < numberOfJournalVolumesInRequest; volumeCount++) {
// acquire a lock so it's possible to get a unique name for the volume
String lockKey = new StringBuilder(consistencyGroup.getLabel()).append("-").append(varray.getLabel()).toString();
InterProcessLockHolder lock = null;
try {
_log.info("Attempting to acquire lock: " + lockKey);
lock = InterProcessLockHolder.acquire(_coordinator, lockKey, _log, LOCK_WAIT_MILLISECONDS);
// get a unique journal volume name
String journalName = RPHelper.createJournalVolumeName(varray, consistencyGroup, _dbClient);
// If MetroPoint is enabled we need to create the standby journal volume
standbyJournal = createRecoverPointVolume(standbyJournalRec, journalName, project, capabilities, consistencyGroup, param, protectionSystemURI, Volume.PersonalityTypes.METADATA, JOURNAL_RSET, null, null, taskList, task, standbySourceCopyName, descriptors, null, false, false, true);
} finally {
if (lock != null) {
lock.close();
}
}
volumeURIs.add(standbyJournal.getId());
volumeInfoBuffer.append(logVolumeInfo(standbyJournal));
}
}
// /////// TARGET JOURNAL(s) ///////////
if (!isChangeVpoolForProtectedVolume && rpProtectionRec.getTargetJournalRecommendations() != null && !rpProtectionRec.getTargetJournalRecommendations().isEmpty()) {
for (RPRecommendation targetJournalRec : rpProtectionRec.getTargetJournalRecommendations()) {
VirtualArray targetJournalVarray = _dbClient.queryObject(VirtualArray.class, targetJournalRec.getVirtualArray());
// This is the varray for the target we're associating the journal too. It could be the case
// that it is the same as the target journal varray set, or the user could have chosen a different
// varray for their target journal in which case we do need to find which target/copy this journal will
// be associated to in the RP CG.
// Ex:
// Target varray1
// Target journal varray6
// The target journal is varray6, however we are adding the journal to the target copy based on the protection
// settings defined for varray1.
VirtualArray targetCopyVarray = getProtectionVarray(rpProtectionRec, targetJournalRec.getInternalSiteName());
if (targetCopyVarray == null) {
targetCopyVarray = targetJournalVarray;
}
_log.info(String.format("Create Target Journal (%s)...", targetJournalVarray.getLabel()));
// Number of journals to create
int numberOfJournalVolumesInRequest = targetJournalRec.getResourceCount();
// Force resource count to 1 here because we're using numberOfJournalVolumesInRequest to create the
// correct number of journal resources.
targetJournalRec.setResourceCount(1);
for (int volumeCount = 0; volumeCount < numberOfJournalVolumesInRequest; volumeCount++) {
// acquire a lock so it's possible to get a unique name for the volume
String lockKey = new StringBuilder(consistencyGroup.getLabel()).append("-").append(targetCopyVarray.getLabel()).toString();
InterProcessLockHolder lock = null;
try {
_log.info("Attempting to acquire lock: " + lockKey);
lock = InterProcessLockHolder.acquire(_coordinator, lockKey, _log, LOCK_WAIT_MILLISECONDS);
// get a unique journal volume name
String journalName = RPHelper.createJournalVolumeName(targetCopyVarray, consistencyGroup, _dbClient);
// Create target journal
Volume targetJournalVolume = createRecoverPointVolume(targetJournalRec, journalName, project, capabilities, consistencyGroup, param, protectionSystemURI, Volume.PersonalityTypes.METADATA, JOURNAL_RSET, null, null, taskList, task, targetJournalRec.getRpCopyName(), descriptors, null, false, false, false);
volumeURIs.add(targetJournalVolume.getId());
volumeInfoBuffer.append(logVolumeInfo(targetJournalVolume));
} finally {
if (lock != null) {
lock.close();
}
}
}
}
} else {
_log.info("Re-use existing Target journals.");
}
}
Aggregations