Private/AWS/New-SilkTCOAWSFSxMetrics.ps1
|
function New-SilkTCOAWSFSxMetrics { param( [Parameter()] [int] $days = 1, [Parameter()] [int] $offsetDays = 1, [Parameter(Mandatory)] [array] $fslist ) $StartDate = (Get-Date).ToUniversalTime().AddDays(-($days + $offsetDays)) $EndDate = (Get-Date).ToUniversalTime().AddDays(-$offsetDays) $requiredModules = @('AWS.Tools.FSx', 'AWS.Tools.CloudWatch') foreach ($module in $requiredModules) { if (-not (Get-Module -ListAvailable -Name $module)) { throw "Required module '$module' is not installed. Install it with: Install-Module $module" } if (-not (Get-Module -Name $module)) { Import-Module $module -ErrorAction Stop } } $thelist = @() $periodSeconds = ($EndDate - $StartDate).TotalSeconds # build a CW dimension from a simple name/value hash function New-FSxDimension { param([hashtable] $pairs) $dims = @() foreach ($k in $pairs.Keys) { $d = New-Object Amazon.CloudWatch.Model.Dimension $d.Name = $k $d.Value = $pairs[$k] $dims += $d } return $dims } # pull one AWS/FSx metric. NOTE the DataRead/Write* metrics are SUM counters, not gauges - # asking for Average over one big bucket gives you the avg of the datapoints, not a rate. # so we take Sum and divide by the window ourselves. function Get-FSxMetric { param( [hashtable] $Dimensions, [string] $MetricName, [string[]] $Stats = @('Sum') ) try { $m = Get-CWMetricStatistic -Namespace 'AWS/FSx' -MetricName $MetricName ` -Dimension (New-FSxDimension $Dimensions) -StartTime $StartDate -EndTime $EndDate ` -Period ([int]$periodSeconds) -Statistic $Stats -ErrorAction SilentlyContinue if ($m.Datapoints -and $m.Datapoints.Count -gt 0) { return $m.Datapoints[0] } } catch { Write-Verbose "-> metric $MetricName not available" -Verbose } return $null } foreach ($fs in $fslist) { $fsId = $fs.FileSystemId $ontap = $fs.OntapConfiguration $nameTag = ($fs.Tags | Where-Object { $_.Key -eq 'Name' }).Value $fsName = if ($nameTag) { $nameTag } else { $fsId } Write-Verbose "-> Gathering info for FSx ONTAP - $fsName ($fsId)" -Verbose # gen2 (SINGLE_AZ_2 / MULTI_AZ_2) scales out by HA pair. throughput and ssd capacity # are both PER PAIR, so reading ThroughputCapacity alone understates a multi pair box. $haPairs = if ($ontap.HAPairs) { $ontap.HAPairs } else { 1 } $tputPerPair = if ($ontap.ThroughputCapacityPerHAPair) { $ontap.ThroughputCapacityPerHAPair } else { $ontap.ThroughputCapacity } $totalThroughputMBps = $tputPerPair * $haPairs $provIops = if ($ontap.DiskIopsConfiguration.Iops) { $ontap.DiskIopsConfiguration.Iops } else { 'N/A' } $iopsMode = if ($ontap.DiskIopsConfiguration.Mode) { $ontap.DiskIopsConfiguration.Mode.Value } else { 'N/A' } # zone - single-az has one subnet, multi-az tells us which one is preferred $zone = 'N/A' try { if ($ontap.PreferredSubnetId) { $zone = (Get-EC2Subnet -SubnetId $ontap.PreferredSubnetId -ErrorAction SilentlyContinue).AvailabilityZone } elseif ($fs.SubnetIds) { $zone = (Get-EC2Subnet -SubnetId $fs.SubnetIds[0] -ErrorAction SilentlyContinue).AvailabilityZone } } catch { Write-Verbose "-> could not resolve AZ for $fsId" -Verbose } if (-not $zone) { $zone = 'N/A' } $region = if ($zone -ne 'N/A') { $zone -replace '[a-z]$', '' } else { 'N/A' } $rgTag = ($fs.Tags | Where-Object { $_.Key -eq 'ResourceGroup' -or $_.Key -eq 'Project' -or $_.Key -eq 'Environment' }).Value $resourceGroup = if ($rgTag) { $rgTag } else { 'N/A' } # --- where the data actually sits. with AUTO tiering most of it ends up in the # capacity pool at roughly a sixth of ssd price, so pricing StorageCapacity alone # gets both the capacity and the bill wrong. $ssdUsedGB = $null $poolUsedGB = $null $ssdDp = Get-FSxMetric -Dimensions @{ FileSystemId = $fsId; StorageTier = 'SSD'; DataType = 'All' } -MetricName 'StorageUsed' -Stats @('Average') if ($ssdDp) { $ssdUsedGB = [Math]::Round($ssdDp.Average / 1GB, 2) } $poolDp = Get-FSxMetric -Dimensions @{ FileSystemId = $fsId; StorageTier = 'STANDARD_CAPACITY_POOL'; DataType = 'All' } -MetricName 'StorageUsed' -Stats @('Average') if ($poolDp) { $poolUsedGB = [Math]::Round($poolDp.Average / 1GB, 2) } # filesystem wide perf. sum/period gives us a real rate $readBytes = Get-FSxMetric -Dimensions @{ FileSystemId = $fsId } -MetricName 'DataReadBytes' -Stats @('Sum') $writeBytes = Get-FSxMetric -Dimensions @{ FileSystemId = $fsId } -MetricName 'DataWriteBytes' -Stats @('Sum') $readOps = Get-FSxMetric -Dimensions @{ FileSystemId = $fsId } -MetricName 'DataReadOperations' -Stats @('Sum') $writeOps = Get-FSxMetric -Dimensions @{ FileSystemId = $fsId } -MetricName 'DataWriteOperations' -Stats @('Sum') $fsReadMBps = if ($readBytes) { [Math]::Round(($readBytes.Sum / $periodSeconds) / 1MB, 2) } else { $null } $fsWriteMBps = if ($writeBytes) { [Math]::Round(($writeBytes.Sum / $periodSeconds) / 1MB, 2) } else { $null } $fsReadIops = if ($readOps) { [Math]::Round($readOps.Sum / $periodSeconds, 2) } else { $null } $fsWriteIops = if ($writeOps) { [Math]::Round($writeOps.Sum / $periodSeconds, 2) } else { $null } $vols = @($fs.SilkVolumes) if (-not $vols) { # no volumes carved out yet, still emit the filesystem so it shows in the bill $vols = @($null) } foreach ($v in $vols) { $volId = if ($v) { $v.VolumeId } else { 'N/A' } $volName = if ($v) { $v.Name } else { 'N/A' } $volConf = if ($v) { $v.OntapConfiguration } else { $null } # newer api gives SizeInBytes, older only SizeInMegabytes $volSizeGB = 'N/A' if ($volConf) { if ($volConf.SizeInBytes) { $volSizeGB = [Math]::Round($volConf.SizeInBytes / 1GB, 2) } elseif ($volConf.SizeInMegabytes) { $volSizeGB = [Math]::Round($volConf.SizeInMegabytes / 1024, 2) } } $tiering = if ($volConf.TieringPolicy.Name) { $volConf.TieringPolicy.Name.Value } else { 'N/A' } $coolDays = if ($volConf.TieringPolicy.CoolingPeriod) { $volConf.TieringPolicy.CoolingPeriod } else { 'N/A' } $svmId = if ($volConf.StorageVirtualMachineId) { $volConf.StorageVirtualMachineId } else { 'N/A' } $storageEff = if ($null -ne $volConf.StorageEfficiencyEnabled) { $volConf.StorageEfficiencyEnabled } else { 'N/A' } # per volume perf if the metric exists for this generation, else fall back to fs wide $vReadMBps = $fsReadMBps $vWriteMBps = $fsWriteMBps $vReadIops = $fsReadIops $vWriteIops = $fsWriteIops $perfScope = 'FileSystem' if ($v) { $vrb = Get-FSxMetric -Dimensions @{ FileSystemId = $fsId; VolumeId = $volId } -MetricName 'DataReadBytes' -Stats @('Sum') if ($vrb) { $perfScope = 'Volume' $vwb = Get-FSxMetric -Dimensions @{ FileSystemId = $fsId; VolumeId = $volId } -MetricName 'DataWriteBytes' -Stats @('Sum') $vro = Get-FSxMetric -Dimensions @{ FileSystemId = $fsId; VolumeId = $volId } -MetricName 'DataReadOperations' -Stats @('Sum') $vwo = Get-FSxMetric -Dimensions @{ FileSystemId = $fsId; VolumeId = $volId } -MetricName 'DataWriteOperations' -Stats @('Sum') $vReadMBps = [Math]::Round(($vrb.Sum / $periodSeconds) / 1MB, 2) $vWriteMBps = if ($vwb) { [Math]::Round(($vwb.Sum / $periodSeconds) / 1MB, 2) } else { $null } $vReadIops = if ($vro) { [Math]::Round($vro.Sum / $periodSeconds, 2) } else { $null } $vWriteIops = if ($vwo) { [Math]::Round($vwo.Sum / $periodSeconds, 2) } else { $null } } } $o = New-Object psobject $o | Add-Member -MemberType NoteProperty -Name "FS name" -Value $fsName $o | Add-Member -MemberType NoteProperty -Name "FS Zone" -Value $zone $o | Add-Member -MemberType NoteProperty -Name "FS size" -Value "ONTAP-$($totalThroughputMBps)MBps-$($ontap.DeploymentType.Value)" $o | Add-Member -MemberType NoteProperty -Name "DeploymentType" -Value $ontap.DeploymentType.Value $o | Add-Member -MemberType NoteProperty -Name "HAPairs" -Value $haPairs $o | Add-Member -MemberType NoteProperty -Name "ThroughputCapacityMBps" -Value $totalThroughputMBps $o | Add-Member -MemberType NoteProperty -Name "SSDCapacityGB" -Value $fs.StorageCapacity $o | Add-Member -MemberType NoteProperty -Name "SSDUsedGB" -Value $ssdUsedGB $o | Add-Member -MemberType NoteProperty -Name "CapacityPoolUsedGB" -Value $poolUsedGB $o | Add-Member -MemberType NoteProperty -Name "ProvisionedIOPS" -Value $provIops $o | Add-Member -MemberType NoteProperty -Name "IOPSMode" -Value $iopsMode $o | Add-Member -MemberType NoteProperty -Name "Volume Name" -Value $volName $o | Add-Member -MemberType NoteProperty -Name "VolumeId" -Value $volId $o | Add-Member -MemberType NoteProperty -Name "VolumeSizeGB" -Value $volSizeGB $o | Add-Member -MemberType NoteProperty -Name "TieringPolicy" -Value $tiering $o | Add-Member -MemberType NoteProperty -Name "CoolingPeriodDays" -Value $coolDays $o | Add-Member -MemberType NoteProperty -Name "StorageEfficiency" -Value $storageEff $o | Add-Member -MemberType NoteProperty -Name "SVM" -Value $svmId $o | Add-Member -MemberType NoteProperty -Name "ResourceGroup" -Value $resourceGroup $o | Add-Member -MemberType NoteProperty -Name "Region" -Value $region $o | Add-Member -MemberType NoteProperty -Name "Days" -Value $days $o | Add-Member -MemberType NoteProperty -Name "PerfScope" -Value $perfScope $o | Add-Member -MemberType NoteProperty -Name "ReadMBps-avg" -Value $vReadMBps $o | Add-Member -MemberType NoteProperty -Name "WriteMBps-avg" -Value $vWriteMBps $o | Add-Member -MemberType NoteProperty -Name "ReadIOPS-avg" -Value $vReadIops $o | Add-Member -MemberType NoteProperty -Name "WriteIOPS-avg" -Value $vWriteIops $o | Add-Member -MemberType NoteProperty -Name "FileSystemId" -Value $fsId $thelist += $o } } return $thelist } |