Private/Checks/SddcManager/Test-VcfSddcCheckVlcmVum.ps1

# Copyright (c) 2026 Broadcom. All Rights Reserved.
# Broadcom Confidential. The term "Broadcom" refers to Broadcom Inc.
# and/or its subsidiaries.
#
# =============================================================================
#
# SOFTWARE LICENSE AGREEMENT
#
# Copyright (c) CA, Inc. All rights reserved.
#
# You are hereby granted a non-exclusive, worldwide, royalty-free license
# under CA, Inc.'s copyrights to use, copy, modify, and distribute this
# software in source code or binary form for use in connection with CA, Inc.
# products.
#
# This copyright notice shall be included in all copies or substantial
# portions of the software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
#
# =============================================================================
function Test-VcfSddcCheckVlcmVum {

    <#
        .SYNOPSIS
        Checks that every cluster, in every vCenter domain attached to SDDC Manager, has vSphere Lifecycle Manager (vLCM) image management enabled instead of baselines (VUM).

        .DESCRIPTION
        Enumerates every cluster across all vCenter domains known to SDDC Manager and checks its
        software enablement status via Invoke-GetClusterEnablementSoftware
        (GET /api/esx/settings/clusters/{id}/enablement/software).

        Evaluates cluster software management mode:
        - Pass: All clusters in the domain are managed by vLCM images.
        - Warning: One or more clusters are managed by vLCM baselines (VUM).
        - Skipped: No clusters are found in the vCenter domain.
        - Error: Execution or connection failure occurs.

        Returns results per vCenter domain using New-VcfCheckPerDomainResults, containing a
        tabular breakdown of cluster names and their software management mode.

        .PARAMETER Context
        The VcfCheck.Context object. Must already be connected to SDDC Manager.

        .PARAMETER DisplayName
        Optional friendly display name for the check result.

        .OUTPUTS
        [PSObject[]] Array of per-domain result objects generated by New-VcfCheckPerDomainResults.
    #>


    [CmdletBinding()]
    [OutputType([PSObject[]])]
    Param (
        [Parameter(Mandatory = $true)] [PSObject]$Context,
        [Parameter(Mandatory = $false)] [String]$DisplayName = ''
    )

    $startedAt = Get-Date
    $checkId = 'sddc_check_vlcm_vum'
    $catalogEntry = (Get-VcfCheckCatalog)[$checkId]
    $displayName = if ([String]::IsNullOrEmpty($DisplayName)) { $catalogEntry.displayName } else { $DisplayName }

    try {
        $vcenterFqdns = Get-VcfCheckAllVCenterFqdns -Context $Context
    } catch {
        return New-VcfCheckResult -CheckId $checkId -Status Error `
            -Exception $_.Exception.Message -StartedAt $startedAt -CompletedAt (Get-Date) -DisplayName $displayName
    }

    $outcomes = foreach ($vcenterFqdn in $vcenterFqdns) {
        $iterationStartedAt = Get-Date
        $outcome = & {
            try {
                Connect-VcfCheckVCenter -Context $Context -Fqdn $vcenterFqdn
                $clusters = @(Get-VcfCheckClusterInventory -Server $vcenterFqdn)

                if ($clusters.Count -eq 0) {
                    return [PSCustomObject]@{ VCenterFqdn = $vcenterFqdn; Status = 'Skipped'; Detail = 'No clusters found.'; SkipReasonTag = 'no clusters'; Rows = @() }
                }

                $rows = [System.Collections.Generic.List[PSObject]]::new()
                $vumCount = 0
                foreach ($cluster in $clusters) {
                    $moRef = $cluster.ExtensionData.MoRef.Value
                    $clusterStartedAt = Get-Date
                    $enablement = Get-VcfCheckClusterEnablementSoftware -Server $vcenterFqdn -Cluster $moRef
                    $clusterMs = ((Get-Date) - $clusterStartedAt).TotalMilliseconds
                    Write-LogMessage -Type DEBUG -Message "[$vcenterFqdn] Enablement-software query for cluster `"$($cluster.Name)`" took $(Format-VcfCheckDuration -Milliseconds $clusterMs)."
                    $enabled = [Boolean]$enablement.Enabled
                    if (-not $enabled) { $vumCount++ }
                    $rows.Add([PSCustomObject]@{
                        Cluster = $cluster.Name
                        Status  = if ($enabled) { 'vLCM Image Managed' } else { 'vLCM Baseline (VUM) Managed' }
                    })
                }
                $rows = @($rows | Sort-Object -Property Cluster)

                if ($vumCount -gt 0) {
                    return [PSCustomObject]@{ VCenterFqdn = $vcenterFqdn; Status = 'Warning'; Detail = "$vumCount of $($clusters.Count) cluster(s) still managed by vLCM baselines (VUM)."; Rows = $rows }
                }

                return [PSCustomObject]@{ VCenterFqdn = $vcenterFqdn; Status = 'Pass'; Detail = "Checked $($clusters.Count) cluster(s); all are managed by vLCM images."; Rows = $rows }
            } catch {
                return [PSCustomObject]@{ VCenterFqdn = $vcenterFqdn; Status = 'Error'; Detail = $_.Exception.Message; Rows = @() }
            }
        }
        $outcome | Add-Member -NotePropertyName StartedAt -NotePropertyValue $iterationStartedAt -Force
        $outcome | Add-Member -NotePropertyName CompletedAt -NotePropertyValue (Get-Date) -Force
        $outcome
    }

    return New-VcfCheckPerDomainResults -Context $Context -PerVCenterOutcome $outcomes -CheckId $checkId `
        -StartedAt $startedAt
}