Search in sources :

Example 16 with VirtualPoolCapabilityValuesWrapper

use of com.emc.storageos.volumecontroller.impl.utils.VirtualPoolCapabilityValuesWrapper in project coprhd-controller by CoprHD.

the class BlockDeviceController method addStepsForCreateVolumes.

/**
 * {@inheritDoc}
 */
@Override
public String addStepsForCreateVolumes(Workflow workflow, String waitFor, List<VolumeDescriptor> origVolumes, String taskId) throws ControllerException {
    // Get the list of descriptors the BlockDeviceController needs to create volumes for.
    List<VolumeDescriptor> volumeDescriptors = VolumeDescriptor.filterByType(origVolumes, new VolumeDescriptor.Type[] { VolumeDescriptor.Type.BLOCK_DATA, VolumeDescriptor.Type.RP_SOURCE, VolumeDescriptor.Type.RP_JOURNAL, VolumeDescriptor.Type.RP_TARGET, VolumeDescriptor.Type.SRDF_SOURCE, VolumeDescriptor.Type.SRDF_TARGET }, null);
    // If no volumes to create, just return
    if (volumeDescriptors.isEmpty()) {
        return waitFor;
    }
    // Segregate by pool to list of volumes.
    Map<URI, Map<Long, List<VolumeDescriptor>>> poolMap = VolumeDescriptor.getPoolSizeMap(volumeDescriptors);
    // Add a Step to create the consistency group if needed
    waitFor = addStepsForCreateConsistencyGroup(workflow, waitFor, volumeDescriptors, CREATE_CONSISTENCY_GROUP_STEP_GROUP);
    waitFor = addStepsForReplicaRollbackCleanup(workflow, waitFor, volumeDescriptors);
    // For meta volumes add Step for each meta volume, except vmax thin meta volumes.
    for (URI poolURI : poolMap.keySet()) {
        for (Long volumeSize : poolMap.get(poolURI).keySet()) {
            List<VolumeDescriptor> descriptors = poolMap.get(poolURI).get(volumeSize);
            List<URI> volumeURIs = VolumeDescriptor.getVolumeURIs(descriptors);
            VolumeDescriptor first = descriptors.get(0);
            URI deviceURI = first.getDeviceURI();
            VirtualPoolCapabilityValuesWrapper capabilities = first.getCapabilitiesValues();
            // Check if volumes have to be created as meta volumes
            _log.debug(String.format("Capabilities : isMeta: %s, Meta Type: %s, Member size: %s, Count: %s", capabilities.getIsMetaVolume(), capabilities.getMetaVolumeType(), capabilities.getMetaVolumeMemberSize(), capabilities.getMetaVolumeMemberCount()));
            Volume volume = _dbClient.queryObject(Volume.class, first.getVolumeURI());
            StorageSystem storageSystem = _dbClient.queryObject(StorageSystem.class, volume.getStorageController());
            boolean createAsMetaVolume = capabilities.getIsMetaVolume() || MetaVolumeUtils.createAsMetaVolume(first.getVolumeURI(), _dbClient, capabilities);
            if (storageSystem.checkIfVmax3()) {
                // VMAX3 does not support META and we will get here due to change VPool
                createAsMetaVolume = false;
            // scenario
            }
            if (createAsMetaVolume) {
                // For vmax thin meta volumes we can create multiple meta volumes in one smis request
                if (volume.getThinlyProvisioned() && storageSystem.getSystemType().equals(StorageSystem.Type.vmax.toString())) {
                    workflow.createStep(CREATE_VOLUMES_STEP_GROUP, String.format("Creating meta volumes:%n%s", getVolumesMsg(_dbClient, volumeURIs)), waitFor, deviceURI, getDeviceType(deviceURI), this.getClass(), createMetaVolumesMethod(deviceURI, poolURI, volumeURIs, capabilities), rollbackCreateMetaVolumesMethod(deviceURI, volumeURIs), null);
                } else {
                    // Add workflow step for each meta volume
                    for (URI metaVolumeURI : volumeURIs) {
                        List<URI> metaVolumeURIs = new ArrayList<URI>();
                        metaVolumeURIs.add(metaVolumeURI);
                        String stepId = workflow.createStepId();
                        workflow.createStep(CREATE_VOLUMES_STEP_GROUP, String.format("Creating meta volume:%n%s", getVolumesMsg(_dbClient, metaVolumeURIs)), waitFor, deviceURI, getDeviceType(deviceURI), this.getClass(), createMetaVolumeMethod(deviceURI, poolURI, metaVolumeURI, capabilities), rollbackCreateMetaVolumeMethod(deviceURI, metaVolumeURI, stepId), stepId);
                    }
                }
            } else {
                workflow.createStep(CREATE_VOLUMES_STEP_GROUP, String.format("Creating volumes:%n%s", getVolumesMsg(_dbClient, volumeURIs)), waitFor, deviceURI, getDeviceType(deviceURI), this.getClass(), createVolumesMethod(deviceURI, poolURI, volumeURIs, capabilities), rollbackCreateVolumesMethod(deviceURI, volumeURIs), null);
            }
            // Following workflow step is only applicable to HDS Thin Volume modification.
            if (getDeviceType(deviceURI).equalsIgnoreCase(Type.hds.name())) {
                boolean modifyHitachiVolumeToApplyTieringPolicy = HDSUtils.isVolumeModifyApplicable(first.getVolumeURI(), _dbClient);
                if (modifyHitachiVolumeToApplyTieringPolicy) {
                    workflow.createStep(MODIFY_VOLUMES_STEP_GROUP, String.format("Modifying volumes:%n%s", getVolumesMsg(_dbClient, volumeURIs)), CREATE_VOLUMES_STEP_GROUP, deviceURI, getDeviceType(deviceURI), this.getClass(), moidfyVolumesMethod(deviceURI, poolURI, volumeURIs), rollbackCreateVolumesMethod(deviceURI, volumeURIs), null);
                }
            }
        }
    }
    waitFor = CREATE_VOLUMES_STEP_GROUP;
    return waitFor;
}
Also used : VirtualPoolCapabilityValuesWrapper(com.emc.storageos.volumecontroller.impl.utils.VirtualPoolCapabilityValuesWrapper) VolumeDescriptor(com.emc.storageos.blockorchestrationcontroller.VolumeDescriptor) ArrayList(java.util.ArrayList) NamedURI(com.emc.storageos.db.client.model.NamedURI) FCTN_MIRROR_TO_URI(com.emc.storageos.db.client.util.CommonTransformerFunctions.FCTN_MIRROR_TO_URI) URI(java.net.URI) Volume(com.emc.storageos.db.client.model.Volume) Map(java.util.Map) OpStatusMap(com.emc.storageos.db.client.model.OpStatusMap) HashMap(java.util.HashMap) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 17 with VirtualPoolCapabilityValuesWrapper

use of com.emc.storageos.volumecontroller.impl.utils.VirtualPoolCapabilityValuesWrapper in project coprhd-controller by CoprHD.

the class RecoverPointScheduler method findSolution.

/**
 * Placement method that assembles recommendation objects based on the vpool and protection varrays.
 * Recursive: peels off one protectionVarray to hopefully assemble one Protection object within the recommendation object, then calls
 * itself
 * with the remainder of the protectionVarrays. If it fails to find a Protection for that protectionVarray, it returns failure and puts
 * the
 * protectionVarray back on the list.
 *
 * @param rpProtectionRecommendation - Top level RP recommendation
 * @param sourceRecommendation - Source Recommendation against which we need to find the solution for targets
 * @param varray - Source Virtual Array
 * @param vpool - Source Virtual Pool
 * @param targetVarrays - List of protection Virtual Arrays
 * @param capabilities - Virtual Pool capabilities
 * @param requestedCount - Resource count desired
 * @param isMetroPoint - Boolean indicating whether this is MetroPoint
 * @param activeSourceRecommendation - Primary Recommendation in case of MetroPoint. This field is null except for when we are finding
 *            solution for MP standby
 * @param project - Project
 * @return - True if protection solution was found, false otherwise.
 */
private boolean findSolution(RPProtectionRecommendation rpProtectionRecommendation, RPRecommendation sourceRecommendation, VirtualArray varray, VirtualPool vpool, List<VirtualArray> targetVarrays, VirtualPoolCapabilityValuesWrapper capabilities, int requestedCount, boolean isMetroPoint, RPRecommendation activeSourceRecommendation, Project project) {
    if (targetVarrays.isEmpty()) {
        _log.info("RP Placement : Could not find target solution because there are no protection virtual arrays specified.");
        return false;
    }
    // Find the virtual pool that applies to this protection virtual array
    // We are recursively calling into "findSolution", so pop the next protectionVarray off the top of the
    // passed in list of protectionVarrays. This protectionVarray will be removed from the list before
    // recursively calling back into the method (in the case that we do not find a solution).
    VirtualArray targetVarray = targetVarrays.get(0);
    placementStatus.getProcessedProtectionVArrays().put(targetVarray.getId(), true);
    // Find the correct target vpool. It is either implicitly the same as the source vpool or has been
    // explicitly set by the user.
    VpoolProtectionVarraySettings protectionSettings = RPHelper.getProtectionSettings(vpool, targetVarray, dbClient);
    // If there was no vpool specified with the protection settings, use the base vpool for this varray.
    VirtualPool targetVpool = vpool;
    if (protectionSettings.getVirtualPool() != null) {
        targetVpool = dbClient.queryObject(VirtualPool.class, protectionSettings.getVirtualPool());
    }
    _log.info("RP Placement : Determining placement on protection varray : " + targetVarray.getLabel());
    // Find matching pools for the protection varray
    VirtualPoolCapabilityValuesWrapper newCapabilities = new VirtualPoolCapabilityValuesWrapper(capabilities);
    newCapabilities.put(VirtualPoolCapabilityValuesWrapper.RESOURCE_COUNT, requestedCount);
    List<Recommendation> targetPoolRecommendations = new ArrayList<Recommendation>();
    // If MP remote target is specified, fetch the target recommendation from the active when looking at the standby side.
    if (isMetroPoint && activeSourceRecommendation != null && isMetroPointProtectionSpecified(activeSourceRecommendation, ProtectionType.REMOTE)) {
        StringBuffer unusedTargets = new StringBuffer();
        Recommendation targetPoolRecommendation = new Recommendation();
        for (RPRecommendation targetRec : activeSourceRecommendation.getTargetRecommendations()) {
            if (targetVarray.getId().equals(targetRec.getVirtualArray())) {
                targetPoolRecommendation.setSourceStoragePool(targetRec.getSourceStoragePool());
                targetPoolRecommendation.setSourceStorageSystem(targetRec.getSourceStorageSystem());
                targetPoolRecommendations.add(targetPoolRecommendation);
                break;
            } else {
                unusedTargets.append(targetRec.getVirtualArray().toString());
                unusedTargets.append(" ");
            }
        }
        // we need to kick out and continue on.
        if (targetPoolRecommendations.isEmpty()) {
            _log.warn(String.format("RP Placement : Could not find a MetroPoint CRR Solution because the" + " Active and Standby Copies could not find a common Target varray. " + "Active Target varrays [ %s] - Standby Target varray [ %s ]. " + "Reason: This might not be a MetroPoint CRR config. Please check the vpool config and " + "the RecoverPoint Protection System for the connectivity of the varrays.", unusedTargets.toString(), targetVarray.getId()));
            return false;
        }
    } else {
        // Get target pool recommendations. Each recommendation also specifies the resource
        // count that the pool can satisfy based on the size requested.
        targetPoolRecommendations = getRecommendedPools(rpProtectionRecommendation, targetVarray, targetVpool, null, null, newCapabilities, RPHelper.TARGET, null);
        if (targetPoolRecommendations.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());
        }
    }
    // Find the correct target journal varray. It is either implicitly the same as the target varray or has been
    // explicitly set by the user.
    VirtualArray targetJournalVarray = targetVarray;
    if (!NullColumnValueGetter.isNullURI(protectionSettings.getJournalVarray())) {
        targetJournalVarray = dbClient.queryObject(VirtualArray.class, protectionSettings.getJournalVarray());
    }
    // Find the correct target journal vpool. It is either implicitly the same as the target vpool or has been
    // explicitly set by the user.
    VirtualPool targetJournalVpool = targetVpool;
    if (!NullColumnValueGetter.isNullURI(protectionSettings.getJournalVpool())) {
        targetJournalVpool = dbClient.queryObject(VirtualPool.class, protectionSettings.getJournalVpool());
    }
    Iterator<Recommendation> targetPoolRecommendationsIter = targetPoolRecommendations.iterator();
    while (targetPoolRecommendationsIter.hasNext()) {
        Recommendation targetPoolRecommendation = targetPoolRecommendationsIter.next();
        StoragePool candidateTargetPool = dbClient.queryObject(StoragePool.class, targetPoolRecommendation.getSourceStoragePool());
        List<String> associatedStorageSystems = getCandidateTargetVisibleStorageSystems(rpProtectionRecommendation.getProtectionDevice(), targetVarray, sourceRecommendation.getInternalSiteName(), candidateTargetPool, VirtualPool.vPoolSpecifiesHighAvailability(targetVpool));
        if (associatedStorageSystems.isEmpty()) {
            _log.info(String.format("RP Placement : Solution cannot be found using target pool %s" + " there is no connectivity to rp cluster sites.", candidateTargetPool.getLabel()));
            continue;
        }
        // We want to find an internal site name that isn't already in the solution
        for (String associatedStorageSystem : associatedStorageSystems) {
            String targetInternalSiteName = ProtectionSystem.getAssociatedStorageSystemSiteName(associatedStorageSystem);
            URI targetStorageSystemURI = ConnectivityUtil.findStorageSystemBySerialNumber(ProtectionSystem.getAssociatedStorageSystemSerialNumber(associatedStorageSystem), dbClient, StorageSystemType.BLOCK);
            ProtectionType protectionType = null;
            if (!sourceRecommendation.containsTargetInternalSiteName(targetInternalSiteName)) {
                // MetroPoint has been specified so process the MetroPoint targets accordingly.
                if (isMetroPoint) {
                    if (targetInternalSiteName.equals(sourceRecommendation.getInternalSiteName())) {
                        // A local protection candidate.
                        if (isMetroPointProtectionSpecified(sourceRecommendation, ProtectionType.LOCAL)) {
                            // so continue onto the next candidate RP site.
                            continue;
                        }
                        // Add the local protection
                        protectionType = ProtectionType.LOCAL;
                    } else {
                        if (isMetroPointProtectionSpecified(sourceRecommendation, ProtectionType.REMOTE)) {
                            // candidate RP site.
                            continue;
                        } else {
                            if (activeSourceRecommendation != null) {
                                String primaryTargetInternalSiteName = getMetroPointRemoteTargetRPSite(rpProtectionRecommendation);
                                if (primaryTargetInternalSiteName != null && !targetInternalSiteName.equals(primaryTargetInternalSiteName)) {
                                    // site but the same as the primary target site.
                                    continue;
                                }
                            }
                            // Add the remote protection
                            protectionType = ProtectionType.REMOTE;
                        }
                    }
                }
            }
            // Check to make sure the RP site is connected to the varray
            URI protectionSystemURI = rpProtectionRecommendation.getProtectionDevice();
            if (!isRpSiteConnectedToVarray(targetStorageSystemURI, protectionSystemURI, targetInternalSiteName, targetVarray)) {
                _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]", targetInternalSiteName, targetVarray.getLabel()));
                continue;
            }
            // Maybe make a topology check in here? Or is the source topology check enough?
            StorageSystem targetStorageSystem = dbClient.queryObject(StorageSystem.class, targetStorageSystemURI);
            ProtectionSystem ps = dbClient.queryObject(ProtectionSystem.class, protectionSystemURI);
            String rpSiteName = (ps.getRpSiteNames() != null) ? ps.getRpSiteNames().get(targetInternalSiteName) : "";
            _log.info(String.format("RP Placement : Choosing RP Site %s (%s) for target on varray [%s](%s)", rpSiteName, targetInternalSiteName, targetVarray.getLabel(), targetVarray.getId()));
            // Construct the target recommendation object
            _log.info(String.format("RP Placement : Build RP Target Recommendation..."));
            RPRecommendation targetRecommendation = buildRpRecommendation(associatedStorageSystem, targetVarray, targetVpool, candidateTargetPool, newCapabilities, requestedCount, targetInternalSiteName, targetStorageSystemURI, targetStorageSystem.getSystemType(), ps);
            if (targetRecommendation == null) {
                // No Target Recommendation found, so continue.
                _log.warn(String.format("RP Placement : Could not create Target Recommendation using [%s], continuing...", associatedStorageSystem));
                continue;
            }
            _log.info(String.format("RP Placement : RP Target Recommendation %s %n", targetRecommendation.toString(dbClient, ps, 1)));
            if (protectionType != null) {
                targetRecommendation.setProtectionType(protectionType);
            }
            // First Determine if journal recommendation need to be computed. It might have already been done.
            boolean isJournalPlacedForVarray = false;
            for (RPRecommendation targetJournalRec : rpProtectionRecommendation.getTargetJournalRecommendations()) {
                if (targetJournalRec.getVirtualArray().equals(targetJournalVarray.getId())) {
                    isJournalPlacedForVarray = true;
                }
            }
            // Build the target journal recommendation
            if (!isJournalPlacedForVarray) {
                _log.info(String.format("RP Placement : Build RP Target Journal Recommendation..."));
                RPRecommendation targetJournalRecommendation = buildJournalRecommendation(rpProtectionRecommendation, targetInternalSiteName, protectionSettings.getJournalSize(), targetJournalVarray, targetJournalVpool, ps, newCapabilities, capabilities.getResourceCount(), null, false);
                if (targetJournalRecommendation == null) {
                    // No Target Journal Recommendation found, so continue.
                    _log.warn(String.format("RP Placement : Could not create Target Journal Recommendation using [%s], continuing...", associatedStorageSystem));
                    continue;
                }
                _log.info(String.format("RP Placement : RP Target Journal Recommendation %s %n", targetJournalRecommendation.toString(dbClient, ps, 1)));
                rpProtectionRecommendation.getTargetJournalRecommendations().add(targetJournalRecommendation);
            } else {
                _log.info(String.format("RP Placement : RP Target Journal already placed."));
            }
            // the Target Recommendation.
            if (sourceRecommendation.getTargetRecommendations() == null) {
                sourceRecommendation.setTargetRecommendations(new ArrayList<RPRecommendation>());
            }
            sourceRecommendation.getTargetRecommendations().add(targetRecommendation);
            // Set the placement status to reference either the primary or secondary.
            PlacementStatus tmpPlacementStatus = placementStatus;
            if (activeSourceRecommendation != null) {
                tmpPlacementStatus = secondaryPlacementStatus;
            }
            // At this point we have found a target storage pool accessible to the protection vPool and protection vArray
            // that can be protected by an rp cluster site that is part of the same rp system that can protect the source storage pool
            rpProtectionRecommendation.setPlacementStepsCompleted(PlacementProgress.IDENTIFIED_SOLUTION_FOR_SUBSET_OF_TARGETS);
            if (tmpPlacementStatus.isBestSolutionToDate(rpProtectionRecommendation)) {
                tmpPlacementStatus.setLatestInvalidRecommendation(rpProtectionRecommendation);
            }
            if (isMetroPoint) {
                if (rpProtectionRecommendation.getSourceRecommendations() != null && getProtectionVarrays(rpProtectionRecommendation).size() == targetVarrays.size()) {
                    finalizeTargetPlacement(rpProtectionRecommendation, tmpPlacementStatus);
                    return true;
                }
            } else if (targetVarrays.size() == 1) {
                finalizeTargetPlacement(rpProtectionRecommendation, tmpPlacementStatus);
                return true;
            }
            // Find a solution based on this recommendation object and the remaining target arrays
            // Make a new protection varray list
            List<VirtualArray> remainingVarrays = new ArrayList<VirtualArray>();
            remainingVarrays.addAll(targetVarrays);
            remainingVarrays.remove(targetVarray);
            if (!remainingVarrays.isEmpty()) {
                _log.info("RP placement: Calling find solution on the next virtual array : " + remainingVarrays.get(0).getLabel() + " Current virtual array: " + targetVarray.getLabel());
            } else {
                _log.info("RP Placement : Solution cannot be found, will try again with different pool combination");
                return false;
            }
            if (!this.findSolution(rpProtectionRecommendation, sourceRecommendation, varray, vpool, remainingVarrays, newCapabilities, requestedCount, isMetroPoint, activeSourceRecommendation, project)) {
                // Remove the current recommendation and try the next site name, pool, etc.
                _log.info("RP Placement: Solution for remaining virtual arrays couldn't be found. " + "Trying different solution (if available) for varray: " + targetVarray.getLabel());
            } else {
                // We found a good solution
                _log.info("RP Placement: Solution for remaining virtual arrays was found. Returning to caller. Virtual Array : " + targetVarray.getLabel());
                return true;
            }
        }
    }
    // If we get here, the recommendation object never got a new protection object, and we just return false,
    // which will move onto the next possibility (in the case of a recursive call)
    _log.info("RP Placement : Solution cannot be found, will try again with different pool combination");
    return false;
}
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) ProtectionType(com.emc.storageos.volumecontroller.RPRecommendation.ProtectionType) ArrayList(java.util.ArrayList) VpoolProtectionVarraySettings(com.emc.storageos.db.client.model.VpoolProtectionVarraySettings) 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) RPRecommendation(com.emc.storageos.volumecontroller.RPRecommendation) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 18 with VirtualPoolCapabilityValuesWrapper

use of com.emc.storageos.volumecontroller.impl.utils.VirtualPoolCapabilityValuesWrapper 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 19 with VirtualPoolCapabilityValuesWrapper

use of com.emc.storageos.volumecontroller.impl.utils.VirtualPoolCapabilityValuesWrapper 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 20 with VirtualPoolCapabilityValuesWrapper

use of com.emc.storageos.volumecontroller.impl.utils.VirtualPoolCapabilityValuesWrapper in project coprhd-controller by CoprHD.

the class RecoverPointScheduler method getJournalCapabilities.

/**
 * This method takes the passed in capabilities and returns back a capabilities object that contains information needed for
 * RP journal volumes. Calculates the size based on the journal policy and sets the resource count to 1.
 *
 * @param journalPolicy Journal Policy from the VirtualPool
 * @param capabilities Capabilities
 * @param requestedResourceCount Number of resources requested, used to compute the journal size.
 * @return capabilities
 */
private VirtualPoolCapabilityValuesWrapper getJournalCapabilities(String journalPolicy, VirtualPoolCapabilityValuesWrapper capabilities, int requestedResourceCount) {
    VirtualPoolCapabilityValuesWrapper newCapabilities = new VirtualPoolCapabilityValuesWrapper(capabilities);
    // only update the count and size of journal volumes if this is not an add journal operation
    if (!capabilities.getAddJournalCapacity()) {
        newCapabilities.put(VirtualPoolCapabilityValuesWrapper.RESOURCE_COUNT, 1);
        Long sizeInBytes = RPHelper.getJournalSizeGivenPolicy(Long.toString(capabilities.getSize()), journalPolicy, requestedResourceCount);
        newCapabilities.put(VirtualPoolCapabilityValuesWrapper.SIZE, sizeInBytes);
    }
    return newCapabilities;
}
Also used : VirtualPoolCapabilityValuesWrapper(com.emc.storageos.volumecontroller.impl.utils.VirtualPoolCapabilityValuesWrapper)

Aggregations

VirtualPoolCapabilityValuesWrapper (com.emc.storageos.volumecontroller.impl.utils.VirtualPoolCapabilityValuesWrapper)65 ArrayList (java.util.ArrayList)50 VirtualArray (com.emc.storageos.db.client.model.VirtualArray)44 VirtualPool (com.emc.storageos.db.client.model.VirtualPool)44 Project (com.emc.storageos.db.client.model.Project)41 URI (java.net.URI)34 StorageSystem (com.emc.storageos.db.client.model.StorageSystem)33 NamedURI (com.emc.storageos.db.client.model.NamedURI)32 List (java.util.List)31 StoragePool (com.emc.storageos.db.client.model.StoragePool)28 StringSet (com.emc.storageos.db.client.model.StringSet)25 Volume (com.emc.storageos.db.client.model.Volume)22 RPProtectionRecommendation (com.emc.storageos.volumecontroller.RPProtectionRecommendation)22 RPRecommendation (com.emc.storageos.volumecontroller.RPRecommendation)22 BlockConsistencyGroup (com.emc.storageos.db.client.model.BlockConsistencyGroup)21 Recommendation (com.emc.storageos.volumecontroller.Recommendation)21 TenantOrg (com.emc.storageos.db.client.model.TenantOrg)20 Test (org.junit.Test)20 Network (com.emc.storageos.db.client.model.Network)19 StringMap (com.emc.storageos.db.client.model.StringMap)19