use of com.emc.storageos.db.client.model.VirtualArray in project coprhd-controller by CoprHD.
the class VplexXtremIOMaskingOrchestrator method getPortGroups.
@Override
public Set<Map<URI, List<List<StoragePort>>>> getPortGroups(Map<URI, List<StoragePort>> allocatablePorts, Map<URI, NetworkLite> networkMap, URI varrayURI, int nInitiatorGroups, Map<URI, Map<String, Integer>> switchToPortNumber, Map<URI, PortAllocationContext> contextMap, StringBuilder errorMessages) {
/**
* Number of Port Group for XtremIO is always one.
* - If multiple port groups, each VPLEX Director's initiators will be mapped to multiple ports
*
* Single Port Group contains different set of storage ports for each network,
* so that each VPLEX director's initiators will map to different port set.
*
* why allocatePorts() not required:
* allocatePorts() would return required number of storage ports from a network from unique X-bricks.
* But we need to select storage ports uniquely across X-bricks & StorageControllers and we need
* to make use of all storage ports.
*/
Set<Map<URI, List<List<StoragePort>>>> portGroups = new HashSet<Map<URI, List<List<StoragePort>>>>();
StringSet netNames = new StringSet();
// Order the networks from those with fewest ports to those with the most ports.
List<URI> orderedNetworks = orderNetworksByNumberOfPorts(allocatablePorts);
for (URI networkURI : orderedNetworks) {
netNames.add(networkMap.get(networkURI).getLabel());
}
_log.info("Calculating PortGroups for Networks: {}", netNames.toString());
StoragePortsAllocator allocator = new StoragePortsAllocator();
// Determine if we should check connectivity from the varray.auto_san_zoning
boolean sanZoningEnabled = false;
if (!simulation) {
VirtualArray varray = _dbClient.queryObject(VirtualArray.class, varrayURI);
if (varray != null && NetworkScheduler.isZoningRequired(_dbClient, varray)) {
sanZoningEnabled = true;
}
}
/**
* Till all storage ports been processed:
* -- get a set of 4 storage ports selected equally across networks
* -- add this set into network to port List map (each port set within a network will be mapped for different
* directors)
*/
Map<URI, List<List<StoragePort>>> useablePorts = new HashMap<URI, List<List<StoragePort>>>();
Set<String> usedPorts = new HashSet<String>();
// map of selected X-brick to Storage Controllers across all networks
Map<String, List<String>> xBricksToSelectedSCs = new HashMap<String, List<String>>();
// map of network to selected X-bricks
Map<URI, List<String>> networkToSelectedXbricks = new HashMap<URI, List<String>>();
do {
Map<URI, List<StoragePort>> useablePortsSet = getUsablePortsSet(allocatablePorts, orderedNetworks, usedPorts, xBricksToSelectedSCs, networkToSelectedXbricks, networkMap, allocator, sanZoningEnabled, switchToPortNumber, contextMap);
if (useablePortsSet == null) {
// if requirement not satisfied
break;
}
for (URI networkURI : useablePortsSet.keySet()) {
if (!useablePorts.containsKey(networkURI)) {
useablePorts.put(networkURI, new ArrayList<List<StoragePort>>());
}
useablePorts.get(networkURI).add(useablePortsSet.get(networkURI));
}
} while (!isAllPortsLooped(orderedNetworks, allocatablePorts, usedPorts));
int numPG = XTREMIO_NUM_PORT_GROUP;
_log.info(String.format("Number of Port Groups: %d", numPG));
portGroups.add(useablePorts);
_log.info("Selected network to ports set: {}", useablePorts.entrySet());
// get number of X-bricks from selected ports
xtremIOXbricksCount = getXbricksCount(useablePorts);
return portGroups;
}
use of com.emc.storageos.db.client.model.VirtualArray in project coprhd-controller by CoprHD.
the class VPlexBackEndOrchestratorUtil method validateExportMask.
/**
* Validates that an ExportMask can be used.
* There are comments for each rule that is validated below.
*
* @param varrayURI the varray URI
* @param initiatorPortMap map of Network to Vplex StoragePort list
* @param mask the ExportMask to validate
* @param invalidMasks a set of known invalidMask URIs
* @param directorToInitiatorIds a map of directors to initiator port strings
* @param idToInitiatorMap a map of initiator ports to Initiator objects
* @param dbClient a reference to the database client
* @param coordinator the system coordinator client
* @param portWwnToClusterMap a map of port wwns to VPLEX cluster
* @param errorMessages an error message builder
* @return true if the given ExportMask can be used
*/
public static boolean validateExportMask(URI varrayURI, Map<URI, List<StoragePort>> initiatorPortMap, ExportMask mask, Set<URI> invalidMasks, Map<String, Set<String>> directorToInitiatorIds, Map<String, Initiator> idToInitiatorMap, DbClient dbClient, CoordinatorClient coordinator, Map<String, String> portWwnToClusterMap, StringBuilder errorMessages) {
boolean passed = true;
Integer directorMinPortCount = Integer.valueOf(ControllerUtils.getPropertyValueFromCoordinator(coordinator, DIRECTOR_MIN_PORT_COUNT_SETTING));
// This is a warning if the ExportMask is non-ViPR.
for (String director : directorToInitiatorIds.keySet()) {
int portsInDirector = 0;
for (String initiatorId : directorToInitiatorIds.get(director)) {
Initiator initiator = idToInitiatorMap.get(initiatorId);
String initiatorPortWwn = Initiator.normalizePort(initiator.getInitiatorPort());
if (mask.hasExistingInitiator(initiatorPortWwn)) {
portsInDirector++;
} else if (mask.hasUserInitiator(initiatorPortWwn)) {
portsInDirector++;
} else if (mask.hasInitiator(initiatorId)) {
portsInDirector++;
}
}
if (portsInDirector < directorMinPortCount) {
if (mask.getCreatedBySystem()) {
// ViPR created
String msg = String.format("ExportMask %s disqualified because it only has %d back-end ports from %s (requires two). \n", mask.getMaskName(), portsInDirector, director);
_log.info(msg);
if (errorMessages != null) {
errorMessages.append(msg);
}
if (null != invalidMasks) {
invalidMasks.add(mask.getId());
}
passed = false;
} else {
// non ViPR created
String msg = String.format("ExportMask %s only has %d back-end ports from %s (should have at least two). \n", mask.getMaskName(), portsInDirector, director);
_log.info(msg);
if (errorMessages != null) {
errorMessages.append(msg);
}
}
}
}
// Rule 2. The Export Mask should have at least two ports. Four are recommended.
Set<String> usablePorts = new StringSet();
if (mask.getStoragePorts() != null) {
for (String portId : mask.getStoragePorts()) {
StoragePort port = dbClient.queryObject(StoragePort.class, URI.create(portId));
if (port == null || port.getInactive() || NullColumnValueGetter.isNullURI(port.getNetwork())) {
continue;
}
// Validate port network overlaps Initiators and port is tagged for Varray
StringSet taggedVarrays = port.getTaggedVirtualArrays();
if (ConnectivityUtil.checkNetworkConnectedToAtLeastOneNetwork(port.getNetwork(), initiatorPortMap.keySet(), dbClient) && taggedVarrays != null && taggedVarrays.contains(varrayURI.toString())) {
usablePorts.add(port.getLabel());
}
}
}
if (usablePorts.size() < 2) {
String msg = String.format("ExportMask %s disqualified because it has less than two usable target ports;" + " usable ports: %s \n", mask.getMaskName(), usablePorts.toString());
_log.warn(msg);
if (errorMessages != null) {
errorMessages.append(msg);
}
passed = false;
} else if (usablePorts.size() < 4) {
// This is a warning
String msg = String.format("Warning: ExportMask %s has only %d usable target ports (best practice is at least four);" + " usable ports: %s \n", mask.getMaskName(), usablePorts.size(), usablePorts.toString());
_log.warn(msg);
if (errorMessages != null) {
errorMessages.append(msg);
}
}
// Rule 3. No mixing of WWNs from both VPLEX clusters.
// Add the clusters for all existingInitiators to the sets computed from initiators above.
Set<String> clusters = new HashSet<String>();
for (String portWwn : portWwnToClusterMap.keySet()) {
if (mask.hasExistingInitiator(portWwn) || mask.hasUserInitiator(portWwn)) {
clusters.add(portWwnToClusterMap.get(portWwn));
}
}
if (clusters.size() > 1) {
String msg = String.format("ExportMask %s disqualified because it contains wwns from both VPLEX clusters. \n", mask.getMaskName());
_log.warn(msg);
if (errorMessages != null) {
errorMessages.append(msg);
}
passed = false;
}
// Rule 4. The ExportMask name should not have NO_VIPR in it.
if (mask.getMaskName().toUpperCase().contains(ExportUtils.NO_VIPR)) {
String msg = String.format("ExportMask %s disqualified because the name contains %s (in upper or lower case) to exclude it. \n", mask.getMaskName(), ExportUtils.NO_VIPR);
_log.warn(msg);
if (errorMessages != null) {
errorMessages.append(msg);
}
passed = false;
}
// Rule 5. Every port in the ExportMask must have the varray in its tagged varray set.
StringBuilder portsNotInVarray = new StringBuilder();
if (mask.getStoragePorts() != null) {
for (String portId : mask.getStoragePorts()) {
StoragePort port = dbClient.queryObject(StoragePort.class, URI.create(portId));
if (port == null || port.getInactive()) {
continue;
}
// Validate port is tagged for Varray
StringSet taggedVarrays = port.getTaggedVirtualArrays();
if (taggedVarrays == null || taggedVarrays.isEmpty() || !taggedVarrays.contains(varrayURI.toString())) {
portsNotInVarray.append(port.getPortName() + " ");
}
}
}
if (portsNotInVarray.length() > 0) {
String virtualArrayName = varrayURI.toString();
VirtualArray virtualArray = dbClient.queryObject(VirtualArray.class, varrayURI);
if (virtualArray != null) {
virtualArrayName = virtualArray.getLabel();
}
String msg = String.format("Validation of ExportMask %s failed; the mask has ports which are not in varray %s;\n" + " \tPorts not in varray: %s \n", mask.getMaskName(), virtualArrayName, portsNotInVarray);
_log.warn(msg);
if (errorMessages != null) {
errorMessages.append(msg);
}
passed = false;
}
int volumeCount = (mask.getVolumes() != null) ? mask.getVolumes().size() : 0;
if (mask.getExistingVolumes() != null) {
volumeCount += mask.getExistingVolumes().keySet().size();
}
if (passed) {
_log.info(String.format("Validation of ExportMask %s passed; it has %d volumes", mask.getMaskName(), volumeCount));
} else {
if (null != invalidMasks) {
invalidMasks.add(mask.getId());
}
}
return passed;
}
use of com.emc.storageos.db.client.model.VirtualArray in project coprhd-controller by CoprHD.
the class PlacementManager method getRecommendationsForVirtualPool.
/**
* A call that can return multiple placement results, one for the ROOT level Vpool, but also others
* for example for SRDF_COPY. The output is a map of Vpool use to the list of recommendations for that Vpool.
* @param virtualArray - Virtual Array object
* @param project - Project object
* @param virtualPool- Virtual Pool object
* @param capabilities - VirtualPoolCapabilityValuesWrapper contains parameters
* @return Map of VpoolUse to List of Recommendations for that use.
*/
public Map<VpoolUse, List<Recommendation>> getRecommendationsForVirtualPool(VirtualArray virtualArray, Project project, VirtualPool virtualPool, VirtualPoolCapabilityValuesWrapper capabilities) {
Map<VpoolUse, List<Recommendation>> recommendationMap = new HashMap<VpoolUse, List<Recommendation>>();
// Invoke scheduling on the top level Virtual Pool (termed ROOT). This virtual pool
// may have within it other virtual pools that may need to be separately scheduled.
// the apisvc vpool
VpoolUse use = VpoolUse.ROOT;
Scheduler scheduler = getNextScheduler(null, virtualPool, use);
List<Recommendation> newRecommendations = scheduler.getRecommendationsForVpool(virtualArray, project, virtualPool, use, capabilities, recommendationMap);
if (newRecommendations.isEmpty()) {
return recommendationMap;
}
recommendationMap.put(use, newRecommendations);
// Loop over the SRDF Copies, invoking a scheduler on them.
if (VirtualPool.vPoolSpecifiesSRDF(virtualPool)) {
Map<URI, VpoolRemoteCopyProtectionSettings> remoteCopyMap = VirtualPool.getRemoteProtectionSettings(virtualPool, dbClient);
for (Map.Entry<URI, VpoolRemoteCopyProtectionSettings> entry : remoteCopyMap.entrySet()) {
// Invoke scheduler on SRDF copies
use = VpoolUse.SRDF_COPY;
URI vArrayURI = entry.getValue().getVirtualArray();
VirtualArray vArray = dbClient.queryObject(VirtualArray.class, vArrayURI);
URI vPoolURI = entry.getValue().getVirtualPool();
VirtualPool vPool = dbClient.queryObject(VirtualPool.class, vPoolURI);
scheduler = getNextScheduler(null, vPool, use);
newRecommendations = scheduler.getRecommendationsForVpool(vArray, project, vPool, use, capabilities, recommendationMap);
if (recommendationMap.containsKey(use)) {
recommendationMap.get(use).addAll(newRecommendations);
} else {
recommendationMap.put(use, newRecommendations);
}
}
}
logRecommendations(recommendationMap);
return recommendationMap;
}
use of com.emc.storageos.db.client.model.VirtualArray 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;
}
use of com.emc.storageos.db.client.model.VirtualArray 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));
}
Aggregations