Private/get-clusterHealthScore.ps1
function Get-ClusterHealthScore { param ( [object]$Checks ) $weights = @{ "nodeConditions" = 8 "nodeResources" = 8 "emptyNamespace" = 1 "resourceQuotas" = 2 "namespaceLimitRanges" = 2 "daemonSetIssues" = 2 "HPA" = 1 "missingResourceLimits" = 3 "PDB" = 2 "missingProbes" = 4 "podsRestart" = 3 "podLongRunning" = 2 "podFail" = 3 "podPending" = 3 "crashloop" = 3 "leftoverDebug" = 1 "stuckJobs" = 2 "jobFail" = 3 "servicesWithoutEndpoints" = 2 "publicServices" = 4 "unmountedPV" = 1 "rbacMisconfig" = 3 "rbacOverexposure" = 4 "orphanedRoles" = 1 "orphanedServiceAccounts" = 1 "orphanedConfigMaps" = 1 "orphanedSecrets" = 2 "podsRoot" = 3 "privilegedContainers" = 4 "hostPidNet" = 3 "eventSummary" = 2 "deploymentIssues" = 3 "statefulSetIssues" = 2 "ingressHealth" = 2 } $score = 100 foreach ($checkName in $Checks.Keys) { if (-not $weights.ContainsKey($checkName)) { Write-Host "Skipping $checkName (no weight defined)" -ForegroundColor Yellow continue } $weight = $weights[$checkName] $check = $Checks[$checkName] $deduction = 0 if ($check -is [string]) { $rows = $check | Select-String -Pattern "<tr>.*?<td>.*?</td>.*?</tr>" -AllMatches $headerRow = if ($rows) { $rows.Matches | Where-Object { $_.Value -match "<th>" } } else { $null } $dataRows = if ($rows) { $rows.Matches | Where-Object { $_.Value -notmatch "<th>" } } else { @() } $total = if ($dataRows) { $dataRows.Count } else { 1 } if ($checkName -eq "nodeConditions" -and $check -match '<p(?:>|.*?>.*?)<strong>[✅⚠️].*?Not Ready Nodes.*?</strong>\s*(\d+)</p>') { $issues = [int]$matches[1] $total = if ($rows) { $rows.Matches.Count } else { 1 } $deduction = ($issues / $total) * $weight if ($deduction -gt $weight) { $deduction = $weight } } elseif ($checkName -eq "nodeResources" -and $check -match '<p(?:>|.*?>.*?)<strong>[✅⚠️].*?Resource Warnings.*?</strong>\s*(\d+)</p>') { $issues = [int]$matches[1] $total = if ($rows) { $rows.Matches.Count * 3 } else { 1 } # 3 resources per node $deduction = ($issues / $total) * $weight if ($deduction -gt $weight) { $deduction = $weight } } else { $issues = $dataRows.Count $deduction = ($issues / $total) * $weight if ($deduction -gt $weight) { $deduction = $weight } } } else { if ($checkName -eq "nodeConditions" -and $check.NotReady -is [int]) { $total = if ($check.Total -gt 0) { $check.Total } else { 1 } $deduction = ($check.NotReady / $total) * $weight if ($deduction -gt $weight) { $deduction = $weight } } elseif ($checkName -eq "nodeResources" -and $check.Warnings -is [int]) { $total = if ($check.Total -gt 0) { $check.Total * 3 } else { 1 } $deduction = ($check.Warnings / $total) * $weight if ($deduction -gt $weight) { $deduction = $weight } } elseif ($checkName -eq "emptyNamespace" -and $check.TotalEmptyNamespaces -is [int]) { $issues = $check.TotalEmptyNamespaces $total = if ($issues -gt 0) { $issues } else { 1 } $deduction = ($issues / $total) * $weight if ($deduction -gt $weight) { $deduction = $weight } } elseif ($checkName -eq "eventSummary" -and $check.Events) { $warnings = ($check.Events | Where-Object { $_.Type -eq "Warning" }).Count $errors = ($check.Events | Where-Object { $_.Type -eq "Error" }).Count $totalIssues = $warnings + $errors $total = if ($totalIssues -gt 0) { $totalIssues } else { 1 } $deduction = ($totalIssues / $total) * $weight if ($deduction -gt $weight) { $deduction = $weight } } else { $total = if ($check.Total -is [int] -and $check.Total -gt 0) { $check.Total } else { 1 } $issues = if ($check.Items -is [array]) { $check.Items.Count } elseif ($check.Items -and $check.Items.PSObject.Properties) { 1 } else { 0 } $deduction = ($issues / $total) * $weight if ($deduction -gt $weight) { $deduction = $weight } } } $score -= $deduction } if ($score -lt 0) { $score = 0 } if ($score -gt 100) { $score = 100 } return [math]::Round($score, 1) } |