Search in sources :

Example 11 with RPRecommendation

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));
}
Also used : VirtualPoolCapabilityValuesWrapper(com.emc.storageos.volumecontroller.impl.utils.VirtualPoolCapabilityValuesWrapper) VirtualArray(com.emc.storageos.db.client.model.VirtualArray) StoragePool(com.emc.storageos.db.client.model.StoragePool) RPProtectionRecommendation(com.emc.storageos.volumecontroller.RPProtectionRecommendation) Calendar(java.util.Calendar) ArrayList(java.util.ArrayList) VirtualPool(com.emc.storageos.db.client.model.VirtualPool) URI(java.net.URI) ProtectionSystem(com.emc.storageos.db.client.model.ProtectionSystem) VPlexRecommendation(com.emc.storageos.volumecontroller.VPlexRecommendation) Recommendation(com.emc.storageos.volumecontroller.Recommendation) RPRecommendation(com.emc.storageos.volumecontroller.RPRecommendation) RPProtectionRecommendation(com.emc.storageos.volumecontroller.RPProtectionRecommendation) AlternateIdConstraint(com.emc.storageos.db.client.constraint.AlternateIdConstraint) BlockConsistencyGroup(com.emc.storageos.db.client.model.BlockConsistencyGroup) Volume(com.emc.storageos.db.client.model.Volume) RPRecommendation(com.emc.storageos.volumecontroller.RPRecommendation) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Example 12 with RPRecommendation

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;
}
Also used : StringMap(com.emc.storageos.db.client.model.StringMap) RPRecommendation(com.emc.storageos.volumecontroller.RPRecommendation)

Example 13 with RPRecommendation

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;
}
Also used : VirtualPoolCapabilityValuesWrapper(com.emc.storageos.volumecontroller.impl.utils.VirtualPoolCapabilityValuesWrapper) StoragePool(com.emc.storageos.db.client.model.StoragePool) Volume(com.emc.storageos.db.client.model.Volume) RPRecommendation(com.emc.storageos.volumecontroller.RPRecommendation) URI(java.net.URI) VPlexRecommendation(com.emc.storageos.volumecontroller.VPlexRecommendation) Recommendation(com.emc.storageos.volumecontroller.Recommendation) RPRecommendation(com.emc.storageos.volumecontroller.RPRecommendation) RPProtectionRecommendation(com.emc.storageos.volumecontroller.RPProtectionRecommendation) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 14 with RPRecommendation

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;
}
Also used : RPRecommendation(com.emc.storageos.volumecontroller.RPRecommendation) URI(java.net.URI) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 15 with 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.");
    }
}
Also used : VirtualArray(com.emc.storageos.db.client.model.VirtualArray) Volume(com.emc.storageos.db.client.model.Volume) RPRecommendation(com.emc.storageos.volumecontroller.RPRecommendation) InterProcessLockHolder(com.emc.storageos.coordinator.client.service.InterProcessLockHolder) AlternateIdConstraint(com.emc.storageos.db.client.constraint.AlternateIdConstraint)

Aggregations

RPRecommendation (com.emc.storageos.volumecontroller.RPRecommendation)28 RPProtectionRecommendation (com.emc.storageos.volumecontroller.RPProtectionRecommendation)22 ArrayList (java.util.ArrayList)21 VirtualArray (com.emc.storageos.db.client.model.VirtualArray)19 VirtualPool (com.emc.storageos.db.client.model.VirtualPool)18 StoragePool (com.emc.storageos.db.client.model.StoragePool)16 ProtectionSystem (com.emc.storageos.db.client.model.ProtectionSystem)15 BlockConsistencyGroup (com.emc.storageos.db.client.model.BlockConsistencyGroup)14 VirtualPoolCapabilityValuesWrapper (com.emc.storageos.volumecontroller.impl.utils.VirtualPoolCapabilityValuesWrapper)14 List (java.util.List)14 NamedURI (com.emc.storageos.db.client.model.NamedURI)13 StorageSystem (com.emc.storageos.db.client.model.StorageSystem)13 StringMap (com.emc.storageos.db.client.model.StringMap)12 StringSet (com.emc.storageos.db.client.model.StringSet)12 VpoolProtectionVarraySettings (com.emc.storageos.db.client.model.VpoolProtectionVarraySettings)12 Recommendation (com.emc.storageos.volumecontroller.Recommendation)12 StringSetMap (com.emc.storageos.db.client.model.StringSetMap)11 VPlexRecommendation (com.emc.storageos.volumecontroller.VPlexRecommendation)11 Network (com.emc.storageos.db.client.model.Network)10 Project (com.emc.storageos.db.client.model.Project)10