use of com.emc.storageos.db.client.model.ExportPathParams in project coprhd-controller by CoprHD.
the class BlockStorageScheduler method calculateExportPathParamForExportMask.
/**
* Calculates the path parameters for an existing ExportMask.
* This has to be calculated per host, since maxPaths is per host.
*
* @param dbClient
* @param mask
* @return ExportPathParams with calculated values
*/
public static ExportPathParams calculateExportPathParamForExportMask(DbClient dbClient, ExportMask mask) {
Map<String, Integer> hostInitiatorCounts = new HashMap<String, Integer>();
// Calculate the path parameters.
ExportPathParams param = new ExportPathParams(0, 0, 0);
// If there is a zoningMap, use that.
if (mask.getZoningMap() != null) {
for (String initiatorId : mask.getZoningMap().keySet()) {
Initiator initiator = dbClient.queryObject(Initiator.class, URI.create(initiatorId));
if (initiator == null || initiator.getInactive()) {
continue;
}
String host = (initiator.getHost() != null) ? initiator.getHost().toString() : "<unknown>";
if (hostInitiatorCounts.get(host) == null) {
hostInitiatorCounts.put(host, 0);
}
Set<String> portIds = mask.getZoningMap().get(initiatorId);
if (portIds == null) {
continue;
}
int ppi = 0;
for (String portId : portIds) {
Integer newValue = hostInitiatorCounts.get(host) + 1;
hostInitiatorCounts.put(host, newValue);
ppi++;
}
if (ppi > param.getPathsPerInitiator()) {
param.setPathsPerInitiator(ppi);
}
}
// Return the maximum of any host.
for (Integer value : hostInitiatorCounts.values()) {
if (value > param.getMaxPaths()) {
param.setMaxPaths(value);
}
}
} else {
// If there is not a zoning map, we won't change things.
_log.info(String.format("No zoning map for mask %s (%s), will not change zoning", mask.getMaskName(), mask.getId()));
param.setMaxPaths(Integer.MAX_VALUE);
}
return param;
}
use of com.emc.storageos.db.client.model.ExportPathParams in project coprhd-controller by CoprHD.
the class BlockStorageScheduler method assignPrezonedStoragePorts.
/**
* Find the existing zones for a list of initiators. The initiators can be for a mask
* that is being created or for a mask to which new initiators are added. In the latter
* case the list of initiators would include only what is being added to the mask.
* <p>
* This existing zoning map returned by this function will be used by the port allocation code to give already zoned port priority over
* other ports.
* <p>
* This function will only do its work if the config item controller_port_alloc_by_metrics_only is set to false. The default value of
* the config is true.
* <p>
* This function will find existing zones for the list of initiators on the network system for all the storage system assignable ports.
* If duplicate zones are found for an initiator-port pair, the existing zone selection algorithm is applied.
* <p>
* If zones were found on the network systems for the initiators and ports, there can be 3 possible scenarios
* <ol>
* <li>the number of existing paths is equal that what is requested in the vpool, in this case the port allocation/assignment code would
* still be invoked but it will return no additional assignments</li>
* <li>the number of existing paths is less that what is requested in the vpool, additional assignments will be made by the port
* allocation/assignment code</li>
* <li>Not all existing paths should be used, for example there are more paths than requested by the vpool or it could be that some
* initiators have more paths that requested. The port allocation code is invoked to select the most favorable paths of the existing
* ones.</li>
* </ol>
* Note that by using existing zones, the path-per-initiator may be violated.
*
* @param storage the storage system where the mask will be or was created
* @param exportGroup the export group of the mask
* @param initiators the initiators being added to the mask.
* @param existingZoningMap this is the zoning map for an existing mask to which
* initiators are being added. It is null for new masks.
* @param pathParams the export group aggregated path parameter
* @param volumeURIs the volumes in the export mask
* @param virtualArrayUri the URI of the export virtual array
* @param token the workflow step Id
* @return a map of existing zones paths between the storage system ports and the
* mask initiators.
*/
public StringSetMap assignPrezonedStoragePorts(StorageSystem storage, ExportGroup exportGroup, List<Initiator> initiators, StringSetMap existingZoningMap, ExportPathParams pathParams, Collection<URI> volumeURIs, NetworkDeviceController networkDeviceController, URI virtualArrayUri, String token) {
// Prime the new zoning map with existing ones
StringSetMap newZoningMap = new StringSetMap();
if (existingZoningMap != null) {
newZoningMap.putAll(existingZoningMap);
}
// check if this is a backend export
boolean backend = ExportMaskUtils.areBackendInitiators(initiators);
// Adjust the paths param based on whether at the end of this call the ports selected should meet the paths requirement
ExportPathParams prezoningPathParams = getPrezoningPathParam(virtualArrayUri, pathParams, storage, backend);
try {
if (networkDeviceController == null) {
return newZoningMap;
}
if (!NetworkUtil.areNetworkSystemDiscovered(_dbClient)) {
_log.info("Cannot discover existing zones. There are no network systems discovered.");
return newZoningMap;
}
if (!_networkScheduler.portAllocationUseExistingZones(storage.getSystemType(), backend)) {
_log.info("The system configuration requests port selection to be based on metrics only " + "i.e. ignore existing zones when selecting ports.");
return newZoningMap;
}
_log.info("Checking for existing zoned ports for export {} before invoking port allocation.", exportGroup.getGeneratedName());
List<Initiator> newInitiators = new ArrayList<Initiator>();
for (Initiator initiator : initiators) {
if (!newZoningMap.containsKey(initiator.getId().toString())) {
newInitiators.add(initiator);
}
}
Map<Initiator, List<StoragePort>> assignments = new HashMap<Initiator, List<StoragePort>>();
Map<Initiator, List<StoragePort>> existingAssignments = generateInitiatorsToStoragePortsMap(existingZoningMap, virtualArrayUri);
if (!newInitiators.isEmpty()) {
// discover existing zones that are for the storage system and varray
// At this time we are not discovering routed zones but we will take care of this
Collection<StoragePort> ports = ExportUtils.getStorageSystemAssignablePorts(_dbClient, storage.getId(), virtualArrayUri, pathParams);
Map<NetworkLite, List<Initiator>> initiatorsByNetwork = NetworkUtil.getInitiatorsByNetwork(newInitiators, _dbClient);
Map<Initiator, NetworkLite> initiatorToNetworkLiteMap = getInitiatorToNetworkLiteMap(initiatorsByNetwork);
Map<NetworkLite, List<StoragePort>> portByNetwork = ExportUtils.mapStoragePortsToNetworks(ports, initiatorsByNetwork.keySet(), _dbClient);
Map<NetworkLite, StringSetMap> zonesByNetwork = new HashMap<NetworkLite, StringSetMap>();
// get all the prezoned ports for the initiators
Map<NetworkLite, List<StoragePort>> preZonedPortsByNetwork = getPrezonedPortsForInitiators(networkDeviceController, portByNetwork, initiatorsByNetwork, zonesByNetwork, token);
if (!preZonedPortsByNetwork.isEmpty()) {
// trim the initiators to the pre-zoned ports
StringMapUtil.retainAll(initiatorsByNetwork, preZonedPortsByNetwork);
Map<NetworkLite, List<StoragePort>> allocatedPortsByNetwork = allocatePorts(storage, virtualArrayUri, initiatorsByNetwork, preZonedPortsByNetwork, volumeURIs, prezoningPathParams, existingZoningMap);
Map<URI, List<StoragePort>> allocatedPortsMap = getAllocatedPortsMap(allocatedPortsByNetwork);
// Get a map of Host to Network to Initiators
Map<URI, Map<URI, List<Initiator>>> hostsToNetToInitiators = getHostInitiatorsMapFromNetworkLite(initiatorsByNetwork);
// Compute the number of Ports needed for each Network
StoragePortsAssigner assigner = StoragePortsAssignerFactory.getAssignerForZones(storage.getSystemType(), zonesByNetwork);
// Assign the storage ports on a per host basis.
for (Map.Entry<URI, Map<URI, List<Initiator>>> entry : hostsToNetToInitiators.entrySet()) {
URI hostURI = entry.getKey();
// The map of switch name to Initiators per network
Map<URI, Map<String, List<Initiator>>> switchInitiatorsByNet = new HashMap<URI, Map<String, List<Initiator>>>();
// The map of swtich name to storage ports per network
Map<URI, Map<String, List<StoragePort>>> switchStoragePortsByNet = new HashMap<URI, Map<String, List<StoragePort>>>();
Map<URI, List<Initiator>> initiatorByNetMap = entry.getValue();
PlacementUtils.getSwitchfoForInititaorsStoragePorts(initiatorByNetMap, allocatedPortsMap, _dbClient, storage, switchInitiatorsByNet, switchStoragePortsByNet);
assigner.assignPortsToHost(assignments, entry.getValue(), allocatedPortsMap, prezoningPathParams, existingAssignments, hostURI, initiatorToNetworkLiteMap, switchInitiatorsByNet, switchStoragePortsByNet);
}
addAssignmentsToZoningMap(assignments, newZoningMap);
}
// if manual zoning is on, then make sure the paths discovered meet the path requirement
if (allocateFromPrezonedPortsOnly(virtualArrayUri, storage.getSystemType(), backend)) {
try {
validateMinPaths(storage, prezoningPathParams, existingAssignments, assignments, newInitiators);
} catch (PlacementException pex) {
_log.error("There are fewer pre-zoned paths than required by the virtual pool." + " Please either add the needed paths or enable automatic SAN zoning in the virtual array" + " so that the additional paths can be added by the application.", pex);
throw pex;
}
}
}
_log.info("Zoning map after the assignment of pre-zoned ports: {}", newZoningMap);
} catch (Exception ex) {
_log.error("Failed to assign from pre-zoned storage ports because: ", ex);
if (allocateFromPrezonedPortsOnly(virtualArrayUri, storage.getSystemType(), backend)) {
_log.error("The virtual array is configured for manual zoning and the application " + "cannot assign from other storage ports. Failing the workflow.");
throw ex;
} else {
_log.info("The virtual array is configured for auto zoning and the application " + "will attempt to assign from other storage ports. Resuming the workflow.");
}
}
return newZoningMap;
}
use of com.emc.storageos.db.client.model.ExportPathParams in project coprhd-controller by CoprHD.
the class StoragePortsAssignerTest method testAllocationAssignmentWithSwitchAffinity.
public static Map<Initiator, List<StoragePort>> testAllocationAssignmentWithSwitchAffinity(PortAllocationContext[] contexts, Map<URI, Map<URI, List<Initiator>>> hostToNetToInitiators, int maxPaths, int minPaths, int pathsPerInitiator, int initiatorsPerPort, String arrayType, Map<Initiator, List<StoragePort>> existingAssignments) throws Exception {
Map<URI, List<Initiator>> net2InitiatorsMap = makeNet2InitiatorsMap(hostToNetToInitiators);
Map<Initiator, List<StoragePort>> assignments = new HashMap<Initiator, List<StoragePort>>();
if (pathsPerInitiator > maxPaths) {
return assignments;
}
ExportPathParams pathParams = new ExportPathParams(maxPaths, minPaths, pathsPerInitiator);
pathParams.setMaxInitiatorsPerPort(initiatorsPerPort);
try {
for (int i = 0; i < contexts.length; i++) {
contexts[i].reinitialize();
}
Map<URI, PortAllocationContext> net2ContextMap = new HashMap<URI, PortAllocationContext>();
for (int i = 0; i < contexts.length; i++) {
PortAllocationContext context = contexts[i];
net2ContextMap.put(context._initiatorNetwork.getId(), context);
}
// Map the existing (already allocated) StoragePorts to their Networks.
Map<URI, Set<StoragePort>> existingPortsMap = generateNetworkToStoragePortsMap(existingAssignments);
// Make a Map of Network to existing Initiators
Map<URI, Set<Initiator>> existingInitiatorsMap = generateNetworkToInitiatorsMap(existingAssignments);
// Compute the number of Ports needed for each Network
StoragePortsAssigner assigner = StoragePortsAssignerFactory.getAssigner(arrayType);
List<URI> networkOrder = new ArrayList<URI>();
Map<URI, Integer> net2PortsNeeded = assigner.getPortsNeededPerNetwork(net2InitiatorsMap, pathParams, existingPortsMap, existingInitiatorsMap, true, networkOrder);
// For each Network, allocate the ports required, and then assign the ports.
StoragePortsAllocator allocator = new StoragePortsAllocator();
Map<URI, List<StoragePort>> netToPortsAllocated = new HashMap<URI, List<StoragePort>>();
PortAllocationContext previousContext = null;
for (URI netURI : networkOrder) {
Integer portsNeeded = net2PortsNeeded.get(netURI);
if (portsNeeded == 0) {
System.out.println("No ports to be assigned for net: " + netURI);
continue;
}
// Get the context for this network.
PortAllocationContext context = net2ContextMap.get(netURI);
// Copy context from the previous allocation.
if (previousContext != null) {
context.copyPreviousNetworkContext(previousContext);
}
previousContext = context;
Map<String, Integer> switchMap = new HashMap<String, Integer>();
List<Initiator> inits = net2InitiatorsMap.get(netURI);
int number = inits.size() * pathsPerInitiator / 2;
System.out.println("Number ports in the switch: " + number);
switchMap.put("mds-a", number);
switchMap.put("mds-b", number);
List<StoragePort> portsAllocated = allocator.allocatePortsForNetwork(portsNeeded, context, false, existingPortsMap.get(netURI), true, switchMap);
netToPortsAllocated.put(netURI, portsAllocated);
}
// Now for each host, do the port assignment.
Map<URI, Map<String, List<StoragePort>>> switchStoragePortsByNet = getSwitchPortsByNetMap(netToPortsAllocated, net2ContextMap);
for (Map.Entry<URI, Map<URI, List<Initiator>>> entry : hostToNetToInitiators.entrySet()) {
Map<URI, Map<String, List<Initiator>>> switchInitiatorsByNet = getSwitchInitiatorByNetMap(entry.getValue());
System.out.println("Assign ports for host " + entry.getKey());
assigner.assignPortsToHost(assignments, entry.getValue(), netToPortsAllocated, pathParams, existingAssignments, entry.getKey(), null, switchInitiatorsByNet, switchStoragePortsByNet);
}
List<String> assignmentStrings = new ArrayList<String>();
for (Initiator initiator : assignments.keySet()) {
StringBuilder buf = new StringBuilder();
buf.append(String.format("%s - %s/%s -> ", initiator.getHostName(), initiator.getInitiatorPort(), getInitiatorSwitch(initiator)));
List<StoragePort> ports = assignments.get(initiator);
if (ports == null) {
buf.append("<ignored>");
} else {
for (StoragePort port : assignments.get(initiator)) {
buf.append(port.getPortName() + "/" + getPortSwitch(port, switchStoragePortsByNet) + " ");
}
}
buf.append(" ");
assignmentStrings.add(buf.toString());
}
Collections.sort(assignmentStrings);
for (String line : assignmentStrings) {
System.out.println(line);
}
verifyAssignments(assignments, arrayType, maxPaths, pathsPerInitiator, initiatorsPerPort, net2InitiatorsMap, existingAssignments);
} catch (PlacementException ex) {
System.out.println("PlacementException: " + ex.getMessage());
} catch (Exception ex) {
System.out.println("ERROR: " + ex.getMessage());
throw ex;
}
return assignments;
}
use of com.emc.storageos.db.client.model.ExportPathParams in project coprhd-controller by CoprHD.
the class HostMapper method map.
public static ExportGroupRestRep map(ExportGroup from, List<Initiator> initiators, Map<String, Integer> volumes, List<Host> hosts, List<Cluster> clusters, List<ExportPathParams> exportPathParams) {
if (from == null) {
return null;
}
ExportGroupRestRep to = new ExportGroupRestRep();
mapDataObjectFields(from, to);
if (initiators != null) {
for (Initiator initiator : initiators) {
to.getInitiators().add(map(initiator));
}
}
if (volumes != null) {
for (Map.Entry<String, Integer> entry : volumes.entrySet()) {
ExportBlockParam volume = new ExportBlockParam();
volume.setId(URI.create(entry.getKey()));
Integer lun = entry.getValue();
if (lun != null && lun != ExportGroup.LUN_UNASSIGNED) {
volume.setLun(lun);
}
to.getVolumes().add(volume);
}
}
if (hosts != null) {
for (Host host : hosts) {
to.getHosts().add(map(host));
}
}
if (clusters != null) {
for (Cluster cluster : clusters) {
to.getClusters().add(map(cluster));
}
}
if (exportPathParams != null && !exportPathParams.isEmpty()) {
for (ExportPathParams pathParam : exportPathParams) {
ExportPathParametersRep pathParamRep = map(pathParam);
for (Map.Entry<String, String> entry : from.getPathParameters().entrySet()) {
if (entry.getValue().equals(pathParam.getId().toString())) {
pathParamRep.getBlockObjects().add(entry.getKey());
}
}
to.getPathParams().add(pathParamRep);
}
}
if (from.getProject() != null) {
to.setProject(toRelatedResource(ResourceTypeEnum.PROJECT, from.getProject().getURI()));
}
if (from.getTenant() != null) {
to.setTenant(toRelatedResource(ResourceTypeEnum.TENANT, from.getTenant().getURI()));
}
to.setVirtualArray(toRelatedResource(ResourceTypeEnum.VARRAY, from.getVirtualArray()));
if (from.getType() != null) {
to.setType(from.getType());
}
to.setGeneratedName(from.getGeneratedName());
if (from.getAltVirtualArrays() != null && !from.getAltVirtualArrays().isEmpty()) {
// The alternate virtual array is a map from Storage System URI to Virtual Array URI
List<StringHashMapEntry> toVirtualArrays = new ArrayList<StringHashMapEntry>();
for (Map.Entry<String, String> entry : from.getAltVirtualArrays().entrySet()) {
StringHashMapEntry toEntry = new StringHashMapEntry();
toEntry.setName(entry.getKey());
toEntry.setValue(entry.getValue());
toVirtualArrays.add(toEntry);
}
to.setAltVirtualArrays(toVirtualArrays);
}
return to;
}
Aggregations