package com.emc.storageos.volumecontroller.impl.plugins.metering.vnxfile.processor; import java.math.BigInteger; import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.commons.httpclient.methods.PostMethod; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.nas.vnxfile.xmlapi.MoverNetStats; import com.emc.nas.vnxfile.xmlapi.ResponsePacket; 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.Stat; import com.emc.storageos.db.client.model.StoragePort; import com.emc.storageos.db.client.model.StorageSystem; import com.emc.storageos.plugins.AccessProfile; import com.emc.storageos.plugins.BaseCollectionException; import com.emc.storageos.plugins.common.Constants; import com.emc.storageos.plugins.common.domainmodel.Operation; import com.emc.storageos.plugins.metering.vnxfile.VNXFileConstants; import com.emc.storageos.volumecontroller.impl.NativeGUIDGenerator; import com.emc.storageos.volumecontroller.impl.plugins.metering.smis.processor.PortMetricsProcessor; import com.emc.storageos.volumecontroller.impl.plugins.metering.vnxfile.VNXFileProcessor; /** * VNXStoragePortStatsProcessor is responsible to process the result received from * XML API Server during VNX Storage Port Stats stream processing. This extracts the * session information from response packet and uses the session id in the * subsequent requests. */ public class VNXStoragePortStatsProcessor extends VNXFileProcessor { private final Logger _logger = LoggerFactory.getLogger(VNXFileProcessor.class); private PortMetricsProcessor portMetricsProcessor; @Override public void processResult(Operation operation, Object resultObj, Map<String, Object> keyMap) throws BaseCollectionException { final PostMethod result = (PostMethod) resultObj; _logger.info("processing moversStats response" + resultObj); try { List<Stat> newstatsList = null; Map<String, List<String>> interPortMap = null; AccessProfile profile = (AccessProfile) keyMap.get(Constants.ACCESSPROFILE); List<Stat> statsList = (List<Stat>) keyMap.get(VNXFileConstants.STATS); final DbClient dbClient = (DbClient) keyMap.get(VNXFileConstants.DBCLIENT); /* * step --> 1 get the interface map for mover and interface map contain values as storage ports * <MoverId, Map<interfaceIP, list<physicalPortName>> */ Map<String, Map<String, List<String>>> moverInterMap = (Map<String, Map<String, List<String>>>) keyMap .get(VNXFileConstants.INTREFACE_PORT_MAP); ResponsePacket responsePacket = (ResponsePacket) _unmarshaller .unmarshal(result.getResponseBodyAsStream()); List<Object> moversStats = getQueryStatsResponse(responsePacket); Iterator<Object> iterator = moversStats.iterator(); // get the storagesystem from db StorageSystem storageSystem = dbClient.queryObject(StorageSystem.class, profile.getSystemId()); // process Mover stats contains samples for each data mover and calculate port metrics while (iterator.hasNext()) { MoverNetStats moverNetStats = (MoverNetStats) iterator.next(); // process mover stats per data mover String moverId = moverNetStats.getMover(); // get interfaces and their list ports for mover id interPortMap = moverInterMap.get(moverId); // get the sample data of mover or VDM List<MoverNetStats.Sample> sampleList = moverNetStats.getSample(); Map<String, BigInteger> stringMapPortIOs = new HashMap<String, BigInteger>(); /* * step -->2 get the io-ops of physical ports from samples * <physicalPortName, Big(input + output band)> */ getPortIOTraffic(sampleList, stringMapPortIOs); // stats sample time long sampleTime = sampleList.get(0).getTime(); /* step -->3 process the port metrics and update storageport object and store in db */ newstatsList = processPortStatsInfo(interPortMap, stringMapPortIOs, storageSystem, dbClient, sampleTime); // finally add to stat object statsList.addAll(newstatsList); } // calculate the avg port utilization for VDM and store in db portMetricsProcessor.dataMoverAvgPortMetrics(profile.getSystemId()); } catch (final Exception ex) { _logger.error( "Exception occurred while processing the volume stats response due to {}", ex.getMessage()); } finally { result.releaseConnection(); } } /** * Process the Port metrics which are received from XMLAPI server. * * @param interPortMap * @param stringMapPortIOs * @param storageSystem * @param dbClient * @param sampleTime * @return list of Port stats */ private List<Stat> processPortStatsInfo(Map<String, List<String>> interPortMap, Map<String, BigInteger> stringMapPortIOs, StorageSystem storageSystem, DbClient dbClient, Long sampleTime) { // get the interfaces and corresponding port List<Stat> stat = new ArrayList<Stat>(); Stat fePortStat = null; for (Entry<String, List<String>> entry : interPortMap.entrySet()) { String interfaceIP = entry.getKey(); List<String> portList = entry.getValue(); // get the port information String portNativeGuid = NativeGUIDGenerator.generateNativeGuid( storageSystem, interfaceIP, NativeGUIDGenerator.PORT); StoragePort storagePort = findExistingPort(portNativeGuid, dbClient); _logger.info( "interface {} and port details {}", interfaceIP, storagePort.getPortName()); // calculate traffic per interface- total traffic all ports/no of ports BigInteger iovalue = new BigInteger("0"); for (String physicalName : portList) { iovalue = iovalue.add(stringMapPortIOs.get(physicalName)); } // get Average port IO by adding and dividing the number. Long iopes = iovalue.longValue() / portList.size(); Long kbytes = iopes / 1024; _logger.info("processIPPortMetrics input data iops{} and time details {} iopes", iopes.toString(), sampleTime.toString()); // set Ethernet port speed to 1Gbps storagePort.setPortSpeed(1L); // send port metrics processor to store the content portMetricsProcessor.processIPPortMetrics(kbytes, iopes, storagePort, sampleTime); // finally add above value to stat object fePortStat = preparePortStatInfo(portNativeGuid, storagePort.getId(), iopes, sampleTime); stat.add(fePortStat); } return stat; } /** * Get IO traffic(in + out) from sample list * * @param sampleList * @param stringMapPortIOs * @return map of Port IO traffic */ private Map<String, BigInteger> getPortIOTraffic(List<MoverNetStats.Sample> sampleList, Map<String, BigInteger> stringMapPortIOs) { // process Mover stats sample for (MoverNetStats.Sample sample : sampleList) { // get device traffic stats List<MoverNetStats.Sample.DeviceTraffic> deviceTrafficList = sample.getDeviceTraffic(); Iterator<MoverNetStats.Sample.DeviceTraffic> deviceTrafficIterator = deviceTrafficList.iterator(); while (deviceTrafficIterator.hasNext()) { MoverNetStats.Sample.DeviceTraffic deviceTraffic = deviceTrafficIterator.next(); // add in + out io traffic BigInteger totalIOs = deviceTraffic.getIn().add(deviceTraffic.getOut()); stringMapPortIOs.put(deviceTraffic.getDevice(), totalIOs); } } return stringMapPortIOs; } /** * Find the port for given portGuid * * @param portGuid * @param dbClient * @return storage port */ private StoragePort findExistingPort(String portGuid, DbClient dbClient) { URIQueryResultList results = new URIQueryResultList(); StoragePort port = null; dbClient.queryByConstraint( AlternateIdConstraint.Factory.getStoragePortByNativeGuidConstraint(portGuid), results); Iterator<URI> iter = results.iterator(); while (iter.hasNext()) { StoragePort tmpPort = dbClient.queryObject(StoragePort.class, iter.next()); if (tmpPort != null && !tmpPort.getInactive()) { port = tmpPort; _logger.info("found port {}", tmpPort.getNativeGuid() + ":" + tmpPort.getPortName()); break; } } return port; } /** * Prepare the Port stat information * * @param nativeId * @param resourceId * @param iops * @param timeSample * @return ipPortStat */ private Stat preparePortStatInfo(String nativeId, URI resourceId, long iops, long timeSample) { Stat ipPortStat = new Stat(); ipPortStat.setServiceType(Constants._File); ipPortStat.setTimeCollected(timeSample); ipPortStat.setResourceId(resourceId); ipPortStat.setNativeGuid(nativeId); ipPortStat.setTotalIOs(iops); return ipPortStat; } /** * Set Port Metrics processor * * @param portMetricsProcessor */ public void setPortMetricsProcessor(PortMetricsProcessor portMetricsProcessor) { this.portMetricsProcessor = portMetricsProcessor; } }