Public/Get-HDTConsoleMonitorNode.ps1
|
function Get-HDTConsoleMonitorNode { <# .SYNOPSIS The Monitoring category and the rows beneath it, built on its own. .DESCRIPTION THE TAILING HALF OF THE MONITORING VIEW. A view that reads the directory once and then shows an hour-old answer is a report rather than a monitor - and worse, a report that LOOKS like a monitor, which is how somebody comes to believe a machine is fine. The console re-runs this on a timer and swaps the node it returns into the tree. IT IS A SEPARATE BUILDER SO THE REFRESH READS ONE DIRECTORY. Rebuilding the whole share subtree would re-read workspace.yaml, every sequence document and the boot image manifest - over SMB, every few seconds, for a number that lives in one small folder. It would also throw away the expansion and the selection an administrator had arranged. This reads Logs\_active\ and nothing else. THE NODE IS REPLACED, NOT MUTATED. A PSCustomObject raises no change notification, so editing Text on a row already on screen changes nothing anybody can see. Handing WPF a NEW object inside an ObservableCollection is what makes the branch redraw - which is why this returns a whole category rather than a list of runs, and why New-HDTConsoleNode's Children is observable. GET-HDTConsoleShareNode CALLS THIS TOO, so the tree as first drawn and the tree as refreshed cannot drift into disagreeing about what a monitoring row looks like. EVERY JUDGEMENT IS Get-HDTConsoleMonitor'S. Nothing here re-reads a heartbeat or works out an age; this arranges what that command decided into rows. .PARAMETER Path The deployment share's root. .PARAMETER Header The banner these rows carry. Built from the share when there is one; a refresh passes the header the existing rows already had. .PARAMETER StaleMinute How long a heartbeat may go unwritten before its run is called stalled. Twenty minutes by default, as Get-HDTConsoleMonitor. .PARAMETER FileSystem An IFileSystem. Defaults to the real one. .PARAMETER Clock An IClockService. Defaults to the real one. .INPUTS None. This command does not accept pipeline input. .OUTPUTS System.Management.Automation.PSCustomObject - one console node, with its run rows already in Children. .EXAMPLE Get-HDTConsoleMonitorNode -Path 'C:\HDTLab\Share' .EXAMPLE $category = Get-HDTConsoleMonitorNode -Path $root -Header $header $category.Children | ForEach-Object { $_.Text } #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Builds display rows in memory; it changes no state.')] [CmdletBinding()] [OutputType([pscustomobject])] param( [Parameter(Mandatory = $true, Position = 0)] [ValidateNotNullOrEmpty()] [string] $Path, [Parameter(Position = 1)] [AllowNull()] [object] $Header, [Parameter()] [ValidateRange(1, 1440)] [int] $StaleMinute = 20, # A READING SOMEBODY ELSE HAS ALREADY TAKEN. Get-HDTConsoleWorkspace # reads Logs\_active\ while it opens the share, so the first draw hands # that result straight over rather than reading the directory twice in # the same second. A refresh omits it and this reads for itself. [Parameter()] [AllowNull()] [object] $Monitor, [Parameter()] [AllowNull()] [object] $FileSystem, [Parameter()] [AllowNull()] [object] $Clock ) Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' if ($null -eq $FileSystem) { $FileSystem = New-HDTFileSystem } if ($null -eq $Clock) { $Clock = New-HDTClock } # A refresh has the header the rows already carried; a first build passes # the share's. Neither is worth making the caller assemble, and a monitoring # row that lost its banner would blank the top of the window when selected. if ($null -eq $Header) { $Header = [pscustomobject] @{ Title = 'Monitoring'; Root = $Path; DeployRoot = $Path } } $monitor = $Monitor if ($null -eq $monitor) { $monitor = Get-HDTConsoleMonitor -Path $Path -StaleMinute $StaleMinute ` -FileSystem $FileSystem -Clock $Clock } $command = "Get-HDTConsoleMonitorNode -Path '{0}'" -f $Path $category = New-HDTConsoleNode -Depth 2 -Kind 'MonitorCategory' -Status 'Ok' ` -Text $monitor.Caption ` -Field @( New-HDTConsoleField -Label 'Watching' -Value $monitor.ActivePath New-HDTConsoleField -Label 'Running' -Value ([string] $monitor.LiveCount) New-HDTConsoleField -Label 'Stalled' -Value ([string] $monitor.StalledCount) New-HDTConsoleField -Label 'Finished' -Value ([string] $monitor.FinishedCount) New-HDTConsoleField -Label 'Unreadable' -Value ([string] $monitor.UnreadableCount) ) ` -Command $command -Header $Header foreach ($current in @($monitor.Run)) { # A stalled or unreadable run is drawn the way every other broken thing # in this tree is drawn, which is what makes it findable by somebody who # has never used this screen before. $runStatus = 'Ok' if ($current.Health -eq 'Stalled' -or $current.Health -eq 'Unreadable') { $runStatus = 'Error' } $runRow = New-HDTConsoleNode -Depth 3 -Kind 'MonitorRun' -Status $runStatus ` -Text $current.Text -Name $current.RunId ` -Field @( New-HDTConsoleField -Label 'Run' -Value $current.RunId New-HDTConsoleField -Label 'Health' -Value $current.Health New-HDTConsoleField -Label 'Phase' -Value (Get-HDTConsoleDisplayText -Text $current.Phase -Fallback '(unknown)') New-HDTConsoleField -Label 'Status' -Value (Get-HDTConsoleDisplayText -Text $current.RunStatus -Fallback '(unknown)') New-HDTConsoleField -Label 'Step' -Value (Get-HDTConsoleDisplayText -Text $current.StepName -Fallback '(no step yet)') New-HDTConsoleField -Label 'Step type' -Value (Get-HDTConsoleDisplayText -Text $current.StepType -Fallback '(unknown)') New-HDTConsoleField -Label 'Step number' -Value (Get-HDTConsoleDisplayText -Text $current.StepText -Fallback '(not started)') New-HDTConsoleField -Label 'Last heartbeat' -Value (Get-HDTConsoleDisplayText -Text $current.SinceText -Fallback '(never)') New-HDTConsoleField -Label 'Heartbeat file' -Value $current.Path ) ` -Command $current.Command -Header $Header [void] $category.Children.Add($runRow) } # An empty category reads as a broken one. This says which it is. if (@($monitor.Run).Count -eq 0) { $empty = New-HDTConsoleNode -Depth 3 -Kind 'Empty' -Status 'Ok' ` -Text $monitor.Summary ` -Field @( New-HDTConsoleField -Label 'Watching' -Value $monitor.ActivePath New-HDTConsoleField -Label '' -Value ('The engine writes a heartbeat here for each step of each running deployment. Nothing is running on this share, or nothing has run since this folder was last cleared.') ) ` -Command $command -Header $Header [void] $category.Children.Add($empty) } return $category } |