#!/usr/bin/perl -w ######################################################################## # Copyright (C) 2015 - 2020, All Rights Reserved, by # EMC Corporation, Hopkinton MA. # # This software is furnished under a license and may be used and copied # only in accordance with the terms of such license and with the # inclusion of the above copyright notice. This software or any other # copies thereof may not be provided or otherwise made available to any # other person. No title to and ownership of the software is hereby # transferred. # # The information in this software is subject to change without notice # and should not be construed as a commitment by EMC Corporation. # # EMC assumes no responsibility for the use or reliability of its # software on equipment which is not supplied by EMC. ######################################################################## use warnings; use strict; use Text::ParseWords; use File::Basename; use Getopt::Long qw(GetOptions); use Data::Dumper; use REST::Client; use JSON; use POSIX; # Remember to update the script version when making changes my $SCRIPT_VERSION = "12"; my $SCRIPT_NAME = basename($0); my $SCRIPT_ARGS = "@ARGV"; # which category of metrics to collect {5min, daily} my $CATEGORY = "5min"; GetOptions('category=s' => \$CATEGORY); # get system info to distinguish between physical (Unity) and virtual (UnityVSA/simulator) platforms my ($systemModel, $platform) = getModelAndPlatform(); # list of metrics collected as part of "5min" category (default category) # (note difference if physical vs. virtual platform below) my $METRICS_LIST_5MIN = '[ "sp.*.blockCache.global.summary.cleanPages", "sp.*.blockCache.global.summary.dirtyBytes", "sp.*.blockCache.global.summary.dirtyPages", "sp.*.blockCache.global.summary.flushedBlocks", "sp.*.blockCache.global.summary.flushes", "sp.*.blockCache.global.summary.freePages", "sp.*.blockCache.global.summary.maxPages", "sp.*.blockCache.global.summary.mNumBlocksRdHit", "sp.*.blockCache.global.summary.mNumBlocksRdMiss", "sp.*.blockCache.global.summary.mNumBlocksWrHit", "sp.*.blockCache.global.summary.mNumBlocksWrMiss", "sp.*.blockCache.global.summary.readHits", "sp.*.blockCache.global.summary.readMisses", "sp.*.blockCache.global.summary.writeHits", "sp.*.blockCache.global.summary.writeMisses", "sp.*.cifs.global.basic.readBytes", "sp.*.cifs.global.basic.readIoTime", "sp.*.cifs.global.basic.reads", "sp.*.cifs.global.basic.writeBytes", "sp.*.cifs.global.basic.writeIoTime", "sp.*.cifs.global.basic.writes", "sp.*.cifs.smb1.basic.readBytes", "sp.*.cifs.smb1.basic.reads", "sp.*.cifs.smb1.basic.totalCalls", "sp.*.cifs.smb1.basic.writeBytes", "sp.*.cifs.smb1.basic.writes", "sp.*.cifs.smb1.op.*.calls", "sp.*.cifs.smb1.op.*.totalTime", "sp.*.cifs.smb1.totalCalls", "sp.*.cifs.smb1.trans2.*.calls", "sp.*.cifs.smb1.trans2.*.totalTime", "sp.*.cifs.smb1.trans2TotalCalls", "sp.*.cifs.smb1.transNT.*.calls", "sp.*.cifs.smb1.transNT.*.totalTime", "sp.*.cifs.smb1.transNTTotalCalls", "sp.*.cifs.smb2.ioctl.*.calls", "sp.*.cifs.smb2.ioctl.*.totalTime", "sp.*.cifs.smb2.ioctlTotalCalls", "sp.*.cifs.smb2.op.*.calls", "sp.*.cifs.smb2.op.*.totalTime", "sp.*.cifs.smb2.queryInfo.*.calls", "sp.*.cifs.smb2.queryInfo.*.totalTime", "sp.*.cifs.smb2.queryInfoTotalCalls", "sp.*.cifs.smb2.setInfo.*.calls", "sp.*.cifs.smb2.setInfo.*.totalTime", "sp.*.cifs.smb2.setInfoTotalCalls", "sp.*.cifs.smb2.totalCalls", "sp.*.cpu.clock.ticksPerUsec", "sp.*.cpu.summary.busyTicks", "sp.*.cpu.summary.idleTicks", "sp.*.cpu.summary.waitTicks", "sp.*.cpu.uptime", "sp.*.iscsi.fePort.*.readBlocks", "sp.*.iscsi.fePort.*.reads", "sp.*.iscsi.fePort.*.writeBlocks", "sp.*.iscsi.fePort.*.writes", "sp.*.iscsi.initiator.*.readBytes", "sp.*.iscsi.initiator.*.reads", "sp.*.iscsi.initiator.*.totalBytes", "sp.*.iscsi.initiator.*.totalCalls", "sp.*.iscsi.initiator.*.totalLogins", "sp.*.iscsi.initiator.*.writeBytes", "sp.*.iscsi.initiator.*.writes", "sp.*.iscsi.target.*.readBytes", "sp.*.iscsi.target.*.reads", "sp.*.iscsi.target.*.totalBytes", "sp.*.iscsi.target.*.totalCalls", "sp.*.iscsi.target.*.totalLogins", "sp.*.iscsi.target.*.writeBytes", "sp.*.iscsi.target.*.writes", "sp.*.memory.summary.buffersBytes", "sp.*.memory.summary.cachedBytes", "sp.*.memory.summary.freeBytes", "sp.*.memory.summary.inPages", "sp.*.memory.summary.outPages", "sp.*.memory.summary.swapFreeBytes", "sp.*.memory.summary.swapInPages", "sp.*.memory.summary.swapOutPages", "sp.*.memory.summary.swapTotalUsedBytes", "sp.*.memory.summary.totalBytes", "sp.*.memory.summary.totalUsedBytes", "sp.*.net.device.*.bytesIn", "sp.*.net.device.*.bytesOut", "sp.*.net.device.*.errorsIn", "sp.*.net.device.*.errorsOut", "sp.*.net.device.*.pktsIn", "sp.*.net.device.*.pktsOut", "sp.*.net.namespace.*.device.*.bytesOut", "sp.*.net.namespace.*.device.*.errorsIn", "sp.*.net.namespace.*.device.*.errorsOut", "sp.*.net.namespace.*.device.*.pktsIn", "sp.*.net.namespace.*.device.*.pktsOut", "sp.*.net.namespace.*.inBytes", "sp.*.net.namespace.*.outBytes", "sp.*.nfs.basic.readBytes", "sp.*.nfs.basic.readIoTime", "sp.*.nfs.basic.reads", "sp.*.nfs.basic.writeBytes", "sp.*.nfs.basic.writeIoTime", "sp.*.nfs.basic.writes", "sp.*.nfs.totalCalls", "sp.*.nfs.v2.io.*.reads", "sp.*.nfs.v2.io.*.writes", "sp.*.nfs.v2.op.*.calls", "sp.*.nfs.v2.op.*.failures", "sp.*.nfs.v2.op.*.totalTime", "sp.*.nfs.v2.totalTime", "sp.*.nfs.v3.io.*.reads", "sp.*.nfs.v3.io.*.writes", "sp.*.nfs.v3.op.*.calls", "sp.*.nfs.v3.op.*.failures", "sp.*.nfs.v3.op.*.totalTime", "sp.*.nfs.v3.totalTime", "sp.*.nfs.v3.vstorage.*.calls", "sp.*.nfs.v3.vstorage.*.maxTime", "sp.*.nfs.v3.vstorage.*.totalTime", "sp.*.nfs.v4.compound.totalCalls", "sp.*.nfs.v4.io.*.reads", "sp.*.nfs.v4.io.*.writes", "sp.*.nfs.v4.op.*.calls", "sp.*.nfs.v4.op.*.failures", "sp.*.nfs.v4.op.*.totalTime", "sp.*.physical.blockSize", "sp.*.physical.coreCount", "sp.*.physical.disk.*.busyTicks", "sp.*.physical.disk.*.idleTicks", "sp.*.physical.disk.*.readBlocks", "sp.*.physical.disk.*.reads", "sp.*.physical.disk.*.sumArrivalQueueLength", "sp.*.physical.disk.*.writeBlocks", "sp.*.physical.disk.*.writes", "sp.*.storage.filesystem.*.readBytes", "sp.*.storage.filesystem.*.reads", "sp.*.storage.filesystem.*.writeBytes", "sp.*.storage.filesystem.*.writes", "sp.*.storage.filesystem.*.clientReadBytes", "sp.*.storage.filesystem.*.clientReadTime", "sp.*.storage.filesystem.*.clientReads", "sp.*.storage.filesystem.*.clientWriteBytes", "sp.*.storage.filesystem.*.clientWriteTime", "sp.*.storage.filesystem.*.clientWrites", "sp.*.storage.filesystemSummary.readBytes", "sp.*.storage.filesystemSummary.reads", "sp.*.storage.filesystemSummary.writeBytes", "sp.*.storage.filesystemSummary.writes", "sp.*.storage.filesystemSummary.clientReadBytes", "sp.*.storage.filesystemSummary.clientReadTime", "sp.*.storage.filesystemSummary.clientReads", "sp.*.storage.filesystemSummary.clientWriteBytes", "sp.*.storage.filesystemSummary.clientWriteTime", "sp.*.storage.filesystemSummary.clientWrites", "sp.*.storage.lun.*.busyTime", "sp.*.storage.lun.*.idleTime", "sp.*.storage.lun.*.others", "sp.*.storage.lun.*.readBlocks", "sp.*.storage.lun.*.readIoTime", "sp.*.storage.lun.*.reads", "sp.*.storage.lun.*.readSize1024BlockPlusOverflow", "sp.*.storage.lun.*.readSize128Block", "sp.*.storage.lun.*.readSize16Block", "sp.*.storage.lun.*.readSize1Block", "sp.*.storage.lun.*.readSize256Block", "sp.*.storage.lun.*.readSize2Block", "sp.*.storage.lun.*.readSize32Block", "sp.*.storage.lun.*.readSize4Block", "sp.*.storage.lun.*.readSize512Block", "sp.*.storage.lun.*.readSize64Block", "sp.*.storage.lun.*.readSize8Block", "sp.*.storage.lun.*.snap.*.readBlocks", "sp.*.storage.lun.*.snap.*.readBytes", "sp.*.storage.lun.*.snap.*.reads", "sp.*.storage.lun.*.snap.*.writeBlocks", "sp.*.storage.lun.*.snap.*.writeBytes", "sp.*.storage.lun.*.snap.*.writes", "sp.*.storage.lun.*.totalIoTime", "sp.*.storage.lun.*.writeBlocks", "sp.*.storage.lun.*.writeIoTime", "sp.*.storage.lun.*.writes", "sp.*.storage.lun.*.writeSize1024BlockPlusOverflow", "sp.*.storage.lun.*.writeSize128Block", "sp.*.storage.lun.*.writeSize16Block", "sp.*.storage.lun.*.writeSize1Block", "sp.*.storage.lun.*.writeSize256Block", "sp.*.storage.lun.*.writeSize2Block", "sp.*.storage.lun.*.writeSize32Block", "sp.*.storage.lun.*.writeSize4Block", "sp.*.storage.lun.*.writeSize512Block", "sp.*.storage.lun.*.writeSize64Block", "sp.*.storage.lun.*.writeSize8Block", "sp.*.storage.pool.*.lun.*.1024PlusOverflowBlockReads", "sp.*.storage.pool.*.lun.*.1024PlusOverflowBlockUnmaps", "sp.*.storage.pool.*.lun.*.1024PlusOverflowBlockWrites", "sp.*.storage.pool.*.lun.*.128BlockReads", "sp.*.storage.pool.*.lun.*.128BlockUnmaps", "sp.*.storage.pool.*.lun.*.128BlockWrites", "sp.*.storage.pool.*.lun.*.16BlockReads", "sp.*.storage.pool.*.lun.*.16BlockUnmaps", "sp.*.storage.pool.*.lun.*.16BlockWrites", "sp.*.storage.pool.*.lun.*.1BlockReads", "sp.*.storage.pool.*.lun.*.1BlockUnmaps", "sp.*.storage.pool.*.lun.*.1BlockWrites", "sp.*.storage.pool.*.lun.*.256BlockRead", "sp.*.storage.pool.*.lun.*.256BlockUnmaps", "sp.*.storage.pool.*.lun.*.256BlockWrites", "sp.*.storage.pool.*.lun.*.2BlockReads", "sp.*.storage.pool.*.lun.*.2BlockUnmaps", "sp.*.storage.pool.*.lun.*.2BlockWrites", "sp.*.storage.pool.*.lun.*.32BlockReads", "sp.*.storage.pool.*.lun.*.32BlockUnmaps", "sp.*.storage.pool.*.lun.*.32BlockWrites", "sp.*.storage.pool.*.lun.*.4BlockReads", "sp.*.storage.pool.*.lun.*.4BlockUnmaps", "sp.*.storage.pool.*.lun.*.4BlockWrites", "sp.*.storage.pool.*.lun.*.512BlockReads", "sp.*.storage.pool.*.lun.*.512BlockWrites", "sp.*.storage.pool.*.lun.*.512BlocksUnmaps", "sp.*.storage.pool.*.lun.*.64BlockReads", "sp.*.storage.pool.*.lun.*.64BlockUnmaps", "sp.*.storage.pool.*.lun.*.64BlockWrites", "sp.*.storage.pool.*.lun.*.8BlockReads", "sp.*.storage.pool.*.lun.*.8BlockUnmaps", "sp.*.storage.pool.*.lun.*.8BlockWrites", "sp.*.storage.pool.*.lun.*.TotalBlockReads", "sp.*.storage.pool.*.lun.*.TotalBlockUnmaps", "sp.*.storage.pool.*.lun.*.TotalBlockWrites", "sp.*.storage.summary.readBlocks", "sp.*.storage.summary.reads", "sp.*.storage.summary.writeBlocks", "sp.*.storage.summary.writes", "sp.*.storage.vvol.block.*.readBlocks", "sp.*.storage.vvol.block.*.readIoTime", "sp.*.storage.vvol.block.*.reads", "sp.*.storage.vvol.block.*.totalIoTime", "sp.*.storage.vvol.block.*.writeBlocks", "sp.*.storage.vvol.block.*.writeIoTime", "sp.*.storage.vvol.block.*.writes", "sp.*.storage.vvol.file.*.readBytes", "sp.*.storage.vvol.file.*.readIoTime", "sp.*.storage.vvol.file.*.reads", "sp.*.storage.vvol.file.*.writeBytes", "sp.*.storage.vvol.file.*.writeIoTime", "sp.*.storage.vvol.file.*.writes", "sp.*.storage.vvol.pool.*.datastore.*.readBytes", "sp.*.storage.vvol.pool.*.datastore.*.reads", "sp.*.storage.vvol.pool.*.datastore.*.totalIoTime", "sp.*.storage.vvol.pool.*.datastore.*.writeBytes", "sp.*.storage.vvol.pool.*.datastore.*.writes"'; # Add in 5-min stats that are NOT available on UnityVSA/simulator if (not isVirtualStorageSystem()) { $METRICS_LIST_5MIN .= ', "sp.*.fibreChannel.blockSize", "sp.*.fibreChannel.fePort.*.readBlocks", "sp.*.fibreChannel.fePort.*.reads", "sp.*.fibreChannel.fePort.*.writeBlocks", "sp.*.fibreChannel.fePort.*.writes", "sp.*.fibreChannel.initiator.*.readBytes", "sp.*.fibreChannel.initiator.*.reads", "sp.*.fibreChannel.initiator.*.totalBytes", "sp.*.fibreChannel.initiator.*.totalCalls", "sp.*.fibreChannel.initiator.*.totalLogins", "sp.*.fibreChannel.initiator.*.writeBytes", "sp.*.fibreChannel.initiator.*.writes", "sp.*.fibreChannel.linkError.*.invalidCRCs", "sp.*.fibreChannel.linkError.*.invalidTransmitsErrors", "sp.*.fibreChannel.linkError.*.linkFailures", "sp.*.fibreChannel.linkError.*.primitiveSequenceErrors", "sp.*.fibreChannel.linkError.*.signalLosses", "sp.*.fibreChannel.linkError.*.syncLosses", "sp.*.fibreChannel.target.*.readBytes", "sp.*.fibreChannel.target.*.reads", "sp.*.fibreChannel.target.*.totalBytes", "sp.*.fibreChannel.target.*.totalCalls", "sp.*.fibreChannel.target.*.totalLogins", "sp.*.fibreChannel.target.*.writeBytes", "sp.*.fibreChannel.target.*.writes"' } $METRICS_LIST_5MIN .= ']'; # list of metrics collected as part of "daily" category (note difference if physical vs. virtual platform below) my $METRICS_LIST_DAILY = '[ "sp.*.blockCache.flu.*.delayedWrites", "sp.*.blockCache.flu.*.fastWrites", "sp.*.blockCache.flu.*.flushBlocks", "sp.*.blockCache.flu.*.flushes", "sp.*.blockCache.flu.*.forcedFlushes", "sp.*.blockCache.flu.*.histogram.*.readReHits", "sp.*.blockCache.flu.*.histogram.*.reads", "sp.*.blockCache.flu.*.histogram.*.writeReHits", "sp.*.blockCache.flu.*.histogram.*.writes", "sp.*.blockCache.flu.*.pageReadHits", "sp.*.blockCache.flu.*.pageReadMisses", "sp.*.blockCache.flu.*.pageWriteHits", "sp.*.blockCache.flu.*.pageWriteMisses", "sp.*.cpu.uptime", "sp.*.fastCache.volume.*.flashReadBlocks", "sp.*.fastCache.volume.*.flashReads", "sp.*.fastCache.volume.*.flashWriteBlocks", "sp.*.fastCache.volume.*.flashWrites", "sp.*.fastCache.volume.*.forceFlushed", "sp.*.fastCache.volume.*.hddReadBlocks", "sp.*.fastCache.volume.*.hddReads", "sp.*.fastCache.volume.*.hddWriteBlocks", "sp.*.fastCache.volume.*.hddWrites", "sp.*.fastCache.volume.*.idleBlocksCleaned", "sp.*.physical.blockSize", "sp.*.physical.disk.*.readBlocks", "sp.*.physical.disk.*.reads", "sp.*.physical.disk.*.writeBlocks", "sp.*.physical.disk.*.writes", "sp.*.storage.LO.*.dataReadBlocks", "sp.*.storage.LO.*.dataReads", "sp.*.storage.LO.*.dataWriteBlocks", "sp.*.storage.LO.*.dataWrites", "sp.*.storage.LO.*.metadataReadBlocks", "sp.*.storage.LO.*.metadataReads", "sp.*.storage.LO.*.metadataWriteBlocks", "sp.*.storage.LO.*.metadataWrites", "sp.*.storage.lun.*.readBlocks", "sp.*.storage.lun.*.reads", "sp.*.storage.lun.*.writeBlocks", "sp.*.storage.lun.*.writes", "sp.*.storage.pool.*.sizeFree", "sp.*.storage.pool.*.sizeSubscribed", "sp.*.storage.pool.*.sizeTotal", "sp.*.storage.pool.*.sizeUsed", "sp.*.storage.pool.*.sizeUsedBlocks", "sp.*.storage.pool.*.snapshotSizeSubscribed", "sp.*.storage.pool.*.snapshotSizeUsed", "sp.*.storage.summary.readBlocks", "sp.*.storage.summary.reads", "sp.*.storage.summary.writeBlocks", "sp.*.storage.summary.writes", "sp.*.storage.vvol.block.*.readSize1024BlockPlusOverflow", "sp.*.storage.vvol.block.*.readSize128Block", "sp.*.storage.vvol.block.*.readSize16Block", "sp.*.storage.vvol.block.*.readSize1Block", "sp.*.storage.vvol.block.*.readSize256Block", "sp.*.storage.vvol.block.*.readSize2Block", "sp.*.storage.vvol.block.*.readSize32Block", "sp.*.storage.vvol.block.*.readSize4Block", "sp.*.storage.vvol.block.*.readSize512Block", "sp.*.storage.vvol.block.*.readSize64Block", "sp.*.storage.vvol.block.*.readSize8Block", "sp.*.storage.vvol.block.*.writeSize1024BlockPlusOverflow", "sp.*.storage.vvol.block.*.writeSize128Block", "sp.*.storage.vvol.block.*.writeSize16Block", "sp.*.storage.vvol.block.*.writeSize1Block", "sp.*.storage.vvol.block.*.writeSize256Block", "sp.*.storage.vvol.block.*.writeSize2Block", "sp.*.storage.vvol.block.*.writeSize32Block", "sp.*.storage.vvol.block.*.writeSize4Block", "sp.*.storage.vvol.block.*.writeSize512Block", "sp.*.storage.vvol.block.*.writeSize64Block", "sp.*.storage.vvol.block.*.writeSize8Block"'; # Add in daily stats that are NOT available on UnityVSA/simulator if (not isVirtualStorageSystem()) { $METRICS_LIST_DAILY .= ', "sp.*.storage.flu.*.core.*.readBlocks", "sp.*.storage.flu.*.core.*.reads", "sp.*.storage.flu.*.core.*.readSize1024BlockPlusOverflow", "sp.*.storage.flu.*.core.*.readSize128Block", "sp.*.storage.flu.*.core.*.readSize16Block", "sp.*.storage.flu.*.core.*.readSize1Block", "sp.*.storage.flu.*.core.*.readSize256Block", "sp.*.storage.flu.*.core.*.readSize2Block", "sp.*.storage.flu.*.core.*.readSize32Block", "sp.*.storage.flu.*.core.*.readSize4Block", "sp.*.storage.flu.*.core.*.readSize512Block", "sp.*.storage.flu.*.core.*.readSize64Block", "sp.*.storage.flu.*.core.*.readSize8Block", "sp.*.storage.flu.*.core.*.rgReadBlocksPosition0", "sp.*.storage.flu.*.core.*.rgReadBlocksPosition1", "sp.*.storage.flu.*.core.*.rgReadBlocksPosition10", "sp.*.storage.flu.*.core.*.rgReadBlocksPosition11", "sp.*.storage.flu.*.core.*.rgReadBlocksPosition12", "sp.*.storage.flu.*.core.*.rgReadBlocksPosition13", "sp.*.storage.flu.*.core.*.rgReadBlocksPosition14", "sp.*.storage.flu.*.core.*.rgReadBlocksPosition15", "sp.*.storage.flu.*.core.*.rgReadBlocksPosition2", "sp.*.storage.flu.*.core.*.rgReadBlocksPosition3", "sp.*.storage.flu.*.core.*.rgReadBlocksPosition4", "sp.*.storage.flu.*.core.*.rgReadBlocksPosition5", "sp.*.storage.flu.*.core.*.rgReadBlocksPosition6", "sp.*.storage.flu.*.core.*.rgReadBlocksPosition7", "sp.*.storage.flu.*.core.*.rgReadBlocksPosition8", "sp.*.storage.flu.*.core.*.rgReadBlocksPosition9", "sp.*.storage.flu.*.core.*.rgWriteBlocksPosition0", "sp.*.storage.flu.*.core.*.rgWriteBlocksPosition1", "sp.*.storage.flu.*.core.*.rgWriteBlocksPosition10", "sp.*.storage.flu.*.core.*.rgWriteBlocksPosition11", "sp.*.storage.flu.*.core.*.rgWriteBlocksPosition12", "sp.*.storage.flu.*.core.*.rgWriteBlocksPosition13", "sp.*.storage.flu.*.core.*.rgWriteBlocksPosition14", "sp.*.storage.flu.*.core.*.rgWriteBlocksPosition15", "sp.*.storage.flu.*.core.*.rgWriteBlocksPosition2", "sp.*.storage.flu.*.core.*.rgWriteBlocksPosition3", "sp.*.storage.flu.*.core.*.rgWriteBlocksPosition4", "sp.*.storage.flu.*.core.*.rgWriteBlocksPosition5", "sp.*.storage.flu.*.core.*.rgWriteBlocksPosition6", "sp.*.storage.flu.*.core.*.rgWriteBlocksPosition7", "sp.*.storage.flu.*.core.*.rgWriteBlocksPosition8", "sp.*.storage.flu.*.core.*.rgWriteBlocksPosition9", "sp.*.storage.flu.*.core.*.stripeCrossings", "sp.*.storage.flu.*.core.*.stripeWrites", "sp.*.storage.flu.*.core.*.writeBlocks", "sp.*.storage.flu.*.core.*.writes", "sp.*.storage.flu.*.core.*.writeSize1024BlockPlusOverflow", "sp.*.storage.flu.*.core.*.writeSize128Block", "sp.*.storage.flu.*.core.*.writeSize16Block", "sp.*.storage.flu.*.core.*.writeSize1Block", "sp.*.storage.flu.*.core.*.writeSize256Block", "sp.*.storage.flu.*.core.*.writeSize2Block", "sp.*.storage.flu.*.core.*.writeSize32Block", "sp.*.storage.flu.*.core.*.writeSize4Block", "sp.*.storage.flu.*.core.*.writeSize512Block", "sp.*.storage.flu.*.core.*.writeSize64Block", "sp.*.storage.flu.*.core.*.writeSize8Block"' } $METRICS_LIST_DAILY .= ']'; #------------------------------------------------------------------------------- # Main execution path #------------------------------------------------------------------------------- my $objectName = ""; my $csvPerformance = ""; my $timestamp = ""; if (uc($CATEGORY) eq '5MIN') { # default case $objectName = 'performance'; ($csvPerformance, $timestamp) = makeMetricRestCall($METRICS_LIST_5MIN); } elsif (uc($CATEGORY) eq 'DAILY') { $objectName = 'performanceDaily'; ($csvPerformance, $timestamp) = makeMetricRestCall($METRICS_LIST_DAILY); } else { error("Invalid category specified ($CATEGORY). Check arguments passed to script."); } # populate the results my %scriptOutput; my @objects = ( { 'object' => $objectName, } ); $objects[0]->{output} = [$csvPerformance]; # need square brackets to make output compatible with parsing $scriptOutput{objectOutput} = \@objects; $scriptOutput{timestamp} = tsToEpoch($timestamp); $scriptOutput{scriptName} = $SCRIPT_NAME; $scriptOutput{scriptArgs} = $SCRIPT_ARGS; $scriptOutput{scriptVersion}= $SCRIPT_VERSION; print jsonString(\%scriptOutput); exit 0; #------------------------------------------------------------------------------- # end of the execution path #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- # SUBROUTINES #------------------------------------------------------------------------------- #=== FUNCTION ================================================================ # NAME: makeMetricRestCall # PURPOSE: use the metricRealTime REST APIs to gather the requested stats #=============================================================================== sub makeMetricRestCall { my ($statPaths, @tag) = @_; my $decoded_req = ""; $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME}=0; my ($cur_sec,$cur_min) = localtime; # We have a 1 minute blackout period before and after the 5 minute boundary, # to avoid gaps in the performance data. So if the current time's minutes # is x0, x4, x5 or x9, we sleep until the minute x1 or x6. if (int($cur_min)%5 == 4) { sleep(60 + 60 - int($cur_sec)); } if (int($cur_min)%5 == 0) { sleep(60 - int($cur_sec)); } my $client = REST::Client->new(); $client->addHeader("Authorization", "LocalInternal/NeoCem007ServiceUser:monitor"); $client->addHeader("Accept", "application/json"); $client->addHeader("Content-Type", "application/json"); $client->addHeader("X-EMC-REST-CLIENT","true"); $client->addHeader("Visibility","ENGINEERING"); # bypasses session limit $client->setFollow(1); $client->getUseragent()->cookie_jar( {} ); $client->getUseragent()->timeout(10); my $url = 'http://localhost:8080/api/types/metricRealTimeQuery/instances'; my $params = '{"interval":300,"maximumSamples":1,"paths":'.$statPaths.'}'; $client->POST($url, $params); $decoded_req = from_json($client->responseContent()); if($decoded_req->{"error"}{"httpStatusCode"}) { my @error = @{$decoded_req->{"error"}{"messages"}}; my $errorMessage = ""; foreach (@error) { $errorMessage = $_->{'en-US'}; } # exit with error error($errorMessage); } my $sessionId = $decoded_req->{'content'}{'id'}; ###### Logic for dynamic wait time to sync with on array time ############# ###### Simplified wait time: wait until the next 5 minute boundary, ###### then add in at least 120 seconds (so the array will be ready ###### to obtain the performance data) ###### and at most 150 seconds (so we do not drift into the next cycle) my $POST_READY_PADDING_SECS_MIN = 120; my $POST_READY_PADDING_SECS_MAX = 150; my ($updated_time) = ($client->responseContent() =~ /updated\":\"([^\"]+)/); my ($min, $sec) = ($updated_time =~ /:(\d\d):(\d\d)/); my $roundUpTime = ((5 - (int($min)%5))*60)-$sec; my $waitTime = $roundUpTime + $POST_READY_PADDING_SECS_MIN + int(rand($POST_READY_PADDING_SECS_MAX - $POST_READY_PADDING_SECS_MIN )); #print "updated_time=$updated_time\nmin=$min\nsec=$sec\nwaitTimeMin=$waitTimeMin\nwaitTimeMax=$waitTimeMax\nwaitTime=$waitTime\n"; sleep($waitTime); $client->GET('http://localhost:8080/api/types/metricQueryResult/instances?compact=true&fields=path,timestamp,values&filter=queryId eq ' . $sessionId); #### Parsing timestamp from rest response and adding it to csv my ($timestampAsString) = ($client->responseContent() =~ /timestamp\":\"([^\"]+)/); # Before returning, delete the real time session, to clean up # and minimize memory useage. # First save away the results from above. my $mySaveContent = $client->responseContent(); $url = 'http://localhost:8080/api/instances/metricRealTimeQuery/'. $sessionId; $client->DELETE($url); # Return the proper content. return ($mySaveContent, $timestampAsString); } sub parseJson { my ($vars, $tag, $tagArray) = @_; if (ref $vars eq "HASH") { while(my ($key, $value) = each(%{$vars})) { # place a check here for the key you are wanting to find if ($key eq $tag) { push (@$tagArray, $value); } if (!ref($value)) { chomp $value; } else { parseJson($value, $tag, $tagArray); } } } elsif (ref $vars eq "ARRAY") { foreach my $value (@$vars) { if (!ref($value)) { chomp $value; } else { parseJson($value, $tag, $tagArray); } } } else { chomp $vars; } } sub jsonString { return JSON->new->allow_nonref()->pretty(1)->encode(@_); } ########################################## # Start #include "includes/time.pl.inc" #included from time.pl.inc use POSIX qw(strftime); use Time::HiRes qw(gettimeofday); use Time::Local; sub tsToEpoch { my $timestamp = shift; my @timeArray = split(/[-T:Z.]/,$timestamp); my $milliseconds = $timeArray[6] || '000'; splice @timeArray, 6, 1; $timeArray[1] -= 1; return timegm(reverse(@timeArray)) . $milliseconds; } sub epochToTs { my $milliseconds = shift; return strftime('%Y-%m-%dT%H:%M:%S',gmtime(int($milliseconds/1000))).'.'.substr($milliseconds,-3).'Z'; } sub timestamp { my ($seconds, $microseconds) = gettimeofday(); return strftime('%Y-%m-%dT%H:%M:%S',gmtime($seconds)).'.'.sprintf('%03d',$microseconds/1000).'Z'; } # End #include "includes/time.pl.inc" ########################################## sub error { my $message = shift; my %error; $error{timestamp} = timestamp(), # timestamp() from includes/time.pl.inc $error{scriptName} = $SCRIPT_NAME, $error{scriptArgs} = $SCRIPT_ARGS, $error{error} = $message, $error{scriptVersion} = $SCRIPT_VERSION; my $jsonErr = jsonString(\%error); # jsonString() from includes/utils.pl.inc print "$jsonErr"; exit 1; } sub makeRestCall { my ($restObject, @tag) = @_; my $decoded_json = ""; $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME}=0; my $client = REST::Client->new(); $client->addHeader("Authorization", "LocalInternal/NeoCem007ServiceUser:monitor"); $client->addHeader("Accept", "application/json"); $client->addHeader("Content-Type", "application/json"); $client->addHeader("X-EMC-REST-CLIENT","true"); $client->setFollow(1); $client->getUseragent()->cookie_jar( {} ); $client->GET("http://localhost:8080/$restObject"); if ($client->responseCode() == 200) { $decoded_json = decode_json($client->responseContent()); } else { error("Unable to get data for call $restObject"); } return $decoded_json; } # # Determines if we're running on a virtual platform (UnityVSA or internal simulator) for platform specific code. # Defaults to physical platform (false). # sub isVirtualStorageSystem { if (uc($systemModel) eq "VVNX" || uc($systemModel) eq "UNITYVSA" || uc($platform) eq "SIMULATOR") { return 1; # true } else { return 0; # false } } #=== FUNCTION ================================================================ # NAME: getModelAndPlatform # PURPOSE: get the model and platform of system. # PARAMETERS: None # RETURNS: model and platform #=============================================================================== sub getModelAndPlatform { my $model = ""; my $platform = ""; my $cmd = ("/api/types/system/instances?visibility=engineering&fields=model,platform&compact=true"); my $decoded_json = makeRestCall($cmd); if($decoded_json ne "") { my $tagToFind = "content"; my @resultArray; parseJson($decoded_json, $tagToFind, \@resultArray); $model = $resultArray[0]->{"model"}; $platform = $resultArray[0]->{"platform"}; } return ($model, $platform); }