/* * Copyright (c) 2013 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.plugins.metering.isilon; import java.net.URI; import java.util.ArrayList; 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.ContainmentConstraint; import com.emc.storageos.db.client.constraint.URIQueryResultList; import com.emc.storageos.db.client.model.FileShare; import com.emc.storageos.db.client.model.Snapshot; import com.emc.storageos.db.client.model.Stat; import com.emc.storageos.db.exceptions.DatabaseException; import com.emc.storageos.isilon.restapi.IsilonApi; import com.emc.storageos.isilon.restapi.IsilonException; import com.emc.storageos.isilon.restapi.IsilonSmartQuota; import com.emc.storageos.isilon.restapi.IsilonSmartQuota.Thresholds; import com.emc.storageos.isilon.restapi.IsilonSnapshot; import com.emc.storageos.plugins.common.Constants; import com.emc.storageos.volumecontroller.impl.plugins.metering.CassandraInsertion; import com.emc.storageos.volumecontroller.impl.plugins.metering.ZeroRecordGenerator; /** * Class for creating Stat objects from IsilonStats */ public class IsilonStatsRecorder { private Logger _log = LoggerFactory.getLogger(IsilonStatsRecorder.class); private ZeroRecordGenerator zeroRecordGenerator; private CassandraInsertion statsColumnInjector; class HostStat { public long reads = 0; public long writes = 0; ArrayList<Float> outBw = new ArrayList<Float>(); ArrayList<Float> inBw = new ArrayList<Float>(); private float getAvg(ArrayList<Float> inArray) { float sum = 0; for (float f : inArray) { sum += f; } return sum / inArray.size(); } public float getOutBWAvg() { return getAvg(outBw); } public float getInBWAvg() { return getAvg(inBw); } } /** * Constructor. * * @param zeroRecordGenerator * @param statsColumnInjector */ public IsilonStatsRecorder(ZeroRecordGenerator zeroRecordGenerator, CassandraInsertion statsColumnInjector) { this.zeroRecordGenerator = zeroRecordGenerator; this.statsColumnInjector = statsColumnInjector; } /** * Adds a Stat for usage from the IsilonQuota. * * @param quota * @param keyMap * @param fsNativeGuid native Guid of the file share * @param isilonApi * @return the stat */ public Stat addUsageStat(IsilonSmartQuota quota, Map<String, Object> keyMap, String fsNativeGuid, IsilonApi isilonApi) { Stat stat = zeroRecordGenerator.injectattr(keyMap, fsNativeGuid, FileShare.class); if (stat != null) { try { DbClient dbClient = (DbClient) keyMap.get(Constants.dbClient); stat.setTimeInMillis((Long) keyMap.get(Constants._TimeCollected)); stat.setTimeCollected((Long) keyMap.get(Constants._TimeCollected)); statsColumnInjector.injectColumns(stat, dbClient); long provisionedCapacity = 0L; Thresholds threshold = quota.getThresholds(); if (threshold != null && threshold.getHard() != null) { provisionedCapacity = threshold.getHard(); } stat.setProvisionedCapacity(provisionedCapacity); long usedCapacity = quota.getUsagePhysical(); stat.setAllocatedCapacity(usedCapacity); URIQueryResultList snapURIList = new URIQueryResultList(); dbClient.queryByConstraint(ContainmentConstraint.Factory.getFileshareSnapshotConstraint(stat.getResourceId()), snapURIList); // Set snapshot count. // Set snapshot size. Get current data for snapshot size (snapshot size changes dynamically). int snapCount = 0; long fsSnapshotSize = 0; IsilonSnapshot isiSnap; for (URI snapURI : snapURIList) { Snapshot snap = dbClient.queryObject(Snapshot.class, snapURI); // Filter out deleted Snapshot if (snap != null && (!snap.getInactive())) { String nativeId = snap.getNativeId(); try { isiSnap = isilonApi.getSnapshot(nativeId); } catch (IsilonException iex) { _log.error(String.format("Stat: %s: can not get snapshot size for snapshot: %s", fsNativeGuid, nativeId), iex); continue; } snapCount++; fsSnapshotSize += Long.valueOf(isiSnap.getSize()); } } stat.setSnapshotCount(snapCount); _log.debug(String.format("Stat: %s: snapshot count: %s", fsNativeGuid, snapCount)); stat.setSnapshotCapacity(fsSnapshotSize); _log.debug(String.format("Stat: %s: snapshot size: %s", fsNativeGuid, fsSnapshotSize)); _log.debug(String.format("Stat: %s: %s: provisioned capacity(%s): used capacity(%s)", stat.getResourceId(), fsNativeGuid, provisionedCapacity, usedCapacity)); } catch (DatabaseException ex) { _log.error("Query to db failed for FileShare id {}, skipping recording usage stat.", stat.getResourceId(), ex); } } return stat; } /** * Adds client operation stats to Stat objects * Creates one stat object per client, for the timestamp * * @param current */ // TODO: Bandwidth in/out and Read/Write statistics count for file systems are unavailable. Waiting for Isilon API support. // public void addOperationStatsCurrent(ArrayList<IsilonStats.StatsClientProto> current, long timestamp) { // for (IsilonStats.StatsClientProto value: current) { // String client = value.getClientAddr(); // float outBw = value.getOutBW(); // float inBw = value.getInBW(); // long readOps = value.getReadOps(); // long writeOps = value.getWriteOps(); // _log.info(String.format("%s: outBW(%s), inBW(%s), ops(%s)", // client, outBw, inBw, readOps+writeOps).toString()); // _statRecorder.createFSOperationStat(timestamp, client, outBw, inBw, readOps, writeOps); // } // } /** * Adds client operation stats to Stat objects * Creates one stat object per client, per the whole interval * * @param history */ // TODO: Bandwidth in/out and Read/Write statistics count for file systems are unavailable. Waiting for Isilon API support. // public long addOperationStatsHistory(HashMap<Long, ArrayList<IsilonStats.StatsClientProto>> history, long lastTS) { // HashMap<String, HostStat> hostStats = new HashMap<String, HostStat>(); // long latest = lastTS; // save the last timestamp from stats // Iterator<Map.Entry<Long, ArrayList<IsilonStats.StatsClientProto>>> it = // history.entrySet().iterator(); // while(it.hasNext()) { // Map.Entry <Long, ArrayList<IsilonStats.StatsClientProto>> entry = it.next(); // if (entry.getKey() <= lastTS) { // // older sample, pass // continue; // } else if (entry.getKey() > latest) { // // keep the highest timestamp we have seen so far // latest = entry.getKey(); // } // ArrayList<IsilonStats.StatsClientProto> entryValues = entry.getValue(); // for (IsilonStats.StatsClientProto value: entryValues) { // String client = value.getClientAddr(); // float outBw = value.getOutBW(); // float inBw = value.getInBW(); // if (!hostStats.containsKey(client)) { // hostStats.put(client, new HostStat()); // } // HostStat stat = hostStats.get(client); // if (outBw > 0) // stat.outBw.add(outBw); // if (inBw > 0) // stat.inBw.add(inBw); // stat.reads += value.getReadOps(); // stat.writes += value.getWriteOps(); // } // } // Iterator<Map.Entry <String, HostStat>> resultsIt = hostStats.entrySet().iterator(); // while(resultsIt.hasNext()){ // Map.Entry <String, HostStat> result = resultsIt.next(); // _log.info(String.format("%s: OutBW(%s), InBW(%s), ops(%s)", // result.getKey(), result.getValue().getOutBWAvg(), result.getValue().getInBWAvg(), // result.getValue().reads + result.getValue().writes).toString()); // _statRecorder.createFSOperationStat(latest, result.getKey(), result.getValue().getOutBWAvg(), // result.getValue().getInBWAvg(), result.getValue().reads, result.getValue().writes); // } // return latest; // } }