Public/Get-DMCapacityHistory.ps1
|
function Get-DMCapacityHistory { <# .SYNOPSIS Retrieves historical capacity samples for OceanStor objects. .DESCRIPTION Capacity history is only exposed by the array through the pms/report_task workflow, the same engine Get-DMPerformanceHistory uses: create a Customer-time-segment report task (report_type 'capacity', no performance indicators), run it, wait for the export, download the zip, and parse the CSV inside. This cmdlet is a convenience wrapper around that pipeline (New-DMPerformanceReportTask -ReportType Capacity, Invoke-DMPerformanceReportTask, Save-DMPerformanceReportFile, Import-DMPerformanceReportCsv) for callers who just want capacity-over-time objects for a time range. The report task and its export log are removed automatically afterwards unless -KeepReportTask is specified. The capacity CSV column layout has not been confirmed against a live array and capacity reports carry no caller-authored indicator list to map columns against, so rows are parsed by header: a column whose name looks object-ID-like becomes ObjectId, a time/date-like column becomes Timestamp, and every remaining column is preserved as a property under its own CSV header name (numeric-looking values are converted to double, anything else is kept as-is). .PARAMETER WebSession Optional parameter to define the session to be use on the REST call. If not defined, the module's cached $script:CurrentOceanstorSession session will be used .PARAMETER ObjectType The type of object to retrieve capacity history for. Only System and StoragePool carry capacity reports. .PARAMETER ObjectId One or more object IDs to retrieve capacity history for. Pipeline-able. .PARAMETER StartTime Window start. .PARAMETER EndTime Window end. .PARAMETER TimeoutSec Maximum seconds to wait for the report task's export to finish generating. Defaults to 120. .PARAMETER KeepReportTask Skip removing the underlying report task and export log afterwards. Useful for troubleshooting the raw report task/export/CSV directly. .INPUTS System.String .OUTPUTS System.Collections.ArrayList .EXAMPLE PS> Get-DMCapacityHistory -ObjectType StoragePool -ObjectId '0' -StartTime (Get-Date).AddDays(-1) -EndTime (Get-Date) .EXAMPLE PS> Get-DMCapacityHistory -ObjectType System -ObjectId '1' -StartTime (Get-Date).AddDays(-7) -EndTime (Get-Date) -KeepReportTask .NOTES Filename: Get-DMCapacityHistory.ps1 #> [CmdletBinding()] [OutputType([System.Collections.ArrayList])] param( [Parameter(ValueFromPipelineByPropertyName = $true, Mandatory = $false)] [pscustomobject]$WebSession, [Parameter(Mandatory = $true, Position = 0)] [ValidateSet('System', 'StoragePool')] [string]$ObjectType, [Parameter(Mandatory = $true, Position = 1, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string[]]$ObjectId, [Parameter(Mandatory = $true)] [datetime]$StartTime, [Parameter(Mandatory = $true)] [datetime]$EndTime, [ValidateRange(1, 86400)] [int]$TimeoutSec = 120, [switch]$KeepReportTask ) begin { $session = if ($WebSession) { $WebSession } else { $script:CurrentOceanstorSession } $collectedIds = [System.Collections.Generic.List[string]]::new() } process { foreach ($id in $ObjectId) { $collectedIds.Add($id) } } end { $samples = [System.Collections.ArrayList]::new() if ($collectedIds.Count -eq 0) { return $samples } # 13-char prefix + 18 guid chars = 31, the real pms/report_task name cap # (the documented 32 is off by one on live arrays). $taskName = "DMCapHistory_$([guid]::NewGuid().ToString('N').Substring(0, 18))" $tempZip = Join-Path ([System.IO.Path]::GetTempPath()) "$taskName.zip" $task = $null $log = $null try { $task = New-DMPerformanceReportTask -WebSession $session -Name $taskName -ReportType Capacity ` -TimeSegment 'Customer' -StartTime $StartTime -EndTime $EndTime -Format 'CSV' -RetentionNumber 1 ` -ObjectType $ObjectType -ObjectId @($collectedIds) -Confirm:$false if ($null -eq $task) { throw 'Get-DMCapacityHistory: failed to create the underlying report task.' } $log = Invoke-DMPerformanceReportTask -WebSession $session -Id $task.Id -TimeoutSec $TimeoutSec -Confirm:$false if ($null -eq $log) { throw 'Get-DMCapacityHistory: report task did not produce an export log.' } Save-DMPerformanceReportFile -WebSession $session -LogId $log.LogId -TaskId $task.Id -Path $tempZip -Force | Out-Null $rows = Import-DMPerformanceReportCsv -ZipPath $tempZip # Live arrays export long-format CSVs -- one row per object/metric/timestamp # with headers 'Object Type,Object Instance,Statistical Metric,Value,Time, # Object Type ID,Object Instance ID,Statistical Metric ID' (confirmed on # Dorado V600R005C27; capacity metric IDs observed: 90001 Total capacity(MB), # 90002 Used capacity(MB), 90004 Capacity usage(%)). Pivot into one sample # per object/timestamp keyed by the metric display name. $firstRow = $rows | Select-Object -First 1 $firstRowProps = if ($firstRow) { @($firstRow.PSObject.Properties.Name) } else { @() } if (($firstRowProps -contains 'Statistical Metric') -and ($firstRowProps -contains 'Value')) { foreach ($group in ($rows | Group-Object -Property 'Object Instance ID', 'Time')) { $groupRows = @($group.Group) $firstOfGroup = $groupRows[0] # Times arrive as '2026-07-06 00:00:00 DST'; drop the trailing zone token. $timestamp = [datetime]::MinValue $rawTime = "$($firstOfGroup.Time)" -replace '\s+[A-Z]{2,5}$', '' $parsed = [datetime]::MinValue if ([datetime]::TryParse($rawTime, [ref]$parsed)) { $timestamp = $parsed } $metrics = [ordered]@{} foreach ($entry in $groupRows) { $rawValue = $entry.Value $numeric = 0.0 $metrics["$($entry.'Statistical Metric')"] = if ($null -ne $rawValue -and "$rawValue" -ne '' -and [double]::TryParse("$rawValue", [System.Globalization.NumberStyles]::Float, [System.Globalization.CultureInfo]::InvariantCulture, [ref]$numeric)) { $numeric } else { "$rawValue" } } $sample = New-DMPerformanceSample -ObjectType $ObjectType -ObjectId "$($firstOfGroup.'Object Instance ID')" -Timestamp $timestamp ` -Metrics $metrics -Session $session [void]$samples.Add($sample) } return $samples } # Wide-format fallback (one column per metric), kept for firmware whose # exports differ from the long format observed live. foreach ($row in $rows) { $propNames = @($row.PSObject.Properties.Name | Where-Object { $_ -ne 'SourceFile' }) if ($propNames.Count -eq 0) { continue } $objectIdProp = $propNames | Where-Object { $_ -match '(?i)object.?id|^id$' } | Select-Object -First 1 $timeProp = $propNames | Where-Object { $_ -match '(?i)time|date' } | Select-Object -First 1 $rowObjectId = if ($objectIdProp) { $row.$objectIdProp } else { $null } $timestamp = [datetime]::MinValue if ($timeProp) { $rawTime = $row.$timeProp if ($rawTime -match '^\d+$') { $timestamp = [DateTimeOffset]::FromUnixTimeSeconds([long]$rawTime).UtcDateTime } else { $parsed = [datetime]::MinValue if ([datetime]::TryParse($rawTime, [ref]$parsed)) { $timestamp = $parsed } } } $metrics = [ordered]@{} foreach ($col in $propNames) { if ($col -eq $objectIdProp -or $col -eq $timeProp) { continue } $rawValue = $row.$col if ($null -eq $rawValue -or "$rawValue" -eq '') { $metrics[$col] = $null continue } $numeric = 0.0 $metrics[$col] = if ([double]::TryParse("$rawValue", [System.Globalization.NumberStyles]::Float, [System.Globalization.CultureInfo]::InvariantCulture, [ref]$numeric)) { $numeric } else { "$rawValue" } } $sample = New-DMPerformanceSample -ObjectType $ObjectType -ObjectId $rowObjectId -Timestamp $timestamp ` -Metrics $metrics -Session $session [void]$samples.Add($sample) } return $samples } finally { if (-not $KeepReportTask) { if ($log) { try { Invoke-DeviceManager -WebSession $session -Method 'DELETE' -Resource "pms/report_task/task_log?log_id=$($log.LogId)" -ApiV2 | Out-Null } catch { Write-Warning "Get-DMCapacityHistory: failed to remove export log $($log.LogId): $_" } } if ($task) { try { Remove-DMPerformanceReportTask -WebSession $session -Id $task.Id -Confirm:$false | Out-Null } catch { Write-Warning "Get-DMCapacityHistory: failed to remove report task $($task.Id): $_" } } } if (Test-Path -LiteralPath $tempZip) { Remove-Item -LiteralPath $tempZip -Force -ErrorAction SilentlyContinue } } } } |