/*
* Copyright (c) 2016 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.placement;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.constraint.AlternateIdConstraint;
import com.emc.storageos.db.client.constraint.URIQueryResultList;
import com.emc.storageos.db.client.model.FCEndpoint;
import com.emc.storageos.db.client.model.Initiator;
import com.emc.storageos.db.client.model.StoragePort;
import com.emc.storageos.db.client.model.StorageSystem;
import com.emc.storageos.db.client.util.NullColumnValueGetter;
public class PlacementUtils {
protected static final Logger log = LoggerFactory.getLogger(PlacementUtils.class);
/**
* Get switch names for initiators and storage ports. Those information is needed when switch affinity is enabled for
* port allocation. so it would only get the information if it is turned on.
*
* @param initiatorsByNetMap the map of network to initiators
* @param storagePortsMap the map of network to storage ports
* @param dbClient
* @param system - storage system
* @param switchInitiatorsByNet - OUTPUT the map of switch to initiators by network
* @param switchStoragePortsByNet -- OUTPUT the map of switch to storage ports by network
*/
public static void getSwitchfoForInititaorsStoragePorts(Map<URI, List<Initiator>> initiatorsByNetMap,
Map<URI, List<StoragePort>> storagePortsMap, DbClient dbClient, StorageSystem system,
Map<URI, Map<String, List<Initiator>>> switchInitiatorsByNet,
Map<URI, Map<String, List<StoragePort>>> switchStoragePortsByNet) {
boolean isSwitchAffinityEnabled = BlockStorageScheduler.isSwitchAffinityAllocationEnabled(system.getSystemType());
if (!isSwitchAffinityEnabled) {
log.info("Switch affinity disabled- returning without initiator and port switch information");
return;
}
for (Map.Entry<URI, List<Initiator>> entry : initiatorsByNetMap.entrySet()) {
URI net = entry.getKey();
List <Initiator> initiators = entry.getValue();
Map<String, List<Initiator>> switchInitiatorMap = switchInitiatorsByNet.get(net);
if (switchInitiatorMap == null) {
switchInitiatorMap = new HashMap<String, List<Initiator>>();
switchInitiatorsByNet.put(net, switchInitiatorMap);
}
for (Initiator initiator : initiators) {
String switchName = PlacementUtils.getSwitchName(initiator.getInitiatorPort(), dbClient);
if (switchName == null || switchName.isEmpty()) {
log.info(String.format("The initiator %s does not have switch info", initiator.getInitiatorPort()));
switchName = NullColumnValueGetter.getNullStr();
}
List<Initiator> inits = switchInitiatorMap.get(switchName);
if (inits == null) {
inits = new ArrayList<>();
switchInitiatorMap.put(switchName, inits);
}
inits.add(initiator);
}
}
for (Map.Entry<URI, List<StoragePort>> entry : storagePortsMap.entrySet()) {
URI net = entry.getKey();
List <StoragePort> ports = entry.getValue();
Map<String, List<StoragePort>> switchPortMap = switchStoragePortsByNet.get(net);
if (switchPortMap == null) {
switchPortMap = new HashMap<String, List<StoragePort>>();
switchStoragePortsByNet.put(net, switchPortMap);
}
for (StoragePort port : ports) {
String switchName = PlacementUtils.getSwitchName(port.getPortNetworkId(), dbClient);
if (switchName == null || switchName.isEmpty()) {
switchName = NullColumnValueGetter.getNullStr();
}
List<StoragePort> portsInMap = switchPortMap.get(switchName);
if (portsInMap == null) {
portsInMap = new ArrayList<>();
switchPortMap.put(switchName, portsInMap);
}
portsInMap.add(port);
}
}
}
/**
* Get the name of a SAN switch that is connected to this StoragePort.
* Return null if no SAN switches are connected to this StoragePort.
*
* @param port
* @param dbClient
* @return
*/
public static String getSwitchName(StoragePort port, DbClient dbClient) {
return getSwitchName(port.getPortNetworkId(), dbClient);
}
/**
* Get the name of a SAN switch that is connected to the storage port or initiator with the portWWN.
* Return null if no SAN switches are connected.
*
* @param portWWN portWWN of a storagePort or an initiator
* @param dbClient
* @return the connected switch name
*/
public static String getSwitchName(String portWWN, DbClient dbClient) {
if (portWWN != null && !portWWN.isEmpty()) {
URIQueryResultList uriList = new URIQueryResultList();
dbClient.queryByConstraint(
AlternateIdConstraint.Factory
.getFCEndpointRemotePortNameConstraint(portWWN), uriList);
for (URI uri : uriList) {
FCEndpoint endpoint = dbClient.queryObject(FCEndpoint.class, uri);
if (endpoint != null) {
if (endpoint.getSwitchName() != null) {
// Return the switch name if it is known.
if (endpoint.getAwolCount() == 0) {
return endpoint.getSwitchName();
}
}
}
}
} else {
log.warn("The portWWN is not set");
}
return null;
}
/**
* Get switch name for initiators and storage ports.
*
* @param initiators initiators
* @param storagePorts storage ports
* @param dbClient
* @param system storage system
* @param initiatorSwitchMap OUTPUT map of initiator to switch name
* @param switchStoragePortsMap OUPTUT map of switch name to list of storage ports
* @param portSwitchMap OUTPUT map of port to switch name
*/
public static void getSwitchNameForInititaorsStoragePorts(List<Initiator> initiators,
Map<URI, List<StoragePort>> storagePorts, DbClient dbClient, StorageSystem system,
Map<URI, String> initiatorSwitchMap,
Map<URI, Map<String, List<StoragePort>>> switchStoragePortsByNetMap,
Map<URI, String> portSwitchMap) {
boolean isSwitchAffinityEnabled = BlockStorageScheduler.isSwitchAffinityAllocationEnabled(system.getSystemType());
if (!isSwitchAffinityEnabled) {
return;
}
for (Initiator initiator : initiators) {
String switchName = PlacementUtils.getSwitchName(initiator.getInitiatorPort(), dbClient);
if (switchName == null || switchName.isEmpty()) {
switchName = NullColumnValueGetter.getNullStr();
}
initiatorSwitchMap.put(initiator.getId(), switchName);
}
for (Map.Entry<URI, List<StoragePort>> entry : storagePorts.entrySet()) {
URI net = entry.getKey();
Collection <StoragePort> ports = entry.getValue();
Map<String, List<StoragePort>> switchPortMap = switchStoragePortsByNetMap.get(net);
if (switchPortMap == null) {
switchPortMap = new HashMap<String, List<StoragePort>>();
switchStoragePortsByNetMap.put(net, switchPortMap);
}
for (StoragePort port : ports) {
String switchName = PlacementUtils.getSwitchName(port.getPortNetworkId(), dbClient);
if (switchName == null || switchName.isEmpty()) {
switchName = NullColumnValueGetter.getNullStr();
}
portSwitchMap.put(port.getId(), switchName);
List<StoragePort> portsInMap = switchPortMap.get(switchName);
if (portsInMap == null) {
portsInMap = new ArrayList<>();
switchPortMap.put(switchName, portsInMap);
}
portsInMap.add(port);
}
}
}
}