1 ) ) ORDER BY ClusterName, NodeName"; $rs = odbc_exec($conn, $sql); $runId = ""; $runDate = "-"; $clusters = array(); if ($rs) { while ($row = odbc_fetch_array($rs)) { if ($runId === "") { $runId = $row['RunId']; $runDate = $row['RunDate']; } $c = $row['ClusterName']; if (!isset($clusters[$c])) { $clusters[$c] = array( 'name'=>$c, 'nodes'=>array(), 'build'=>false, 'ms'=>false, 'spp'=>false, 'unreach'=>false, 'ubrgap'=>0 ); } $clusters[$c]['nodes'][] = $row; // Conformity fail = build drift. MS (Build.UBR) kept as info only. if ($row['BuildDrift'] == 1) { $clusters[$c]['build'] = true; } if ($row['MsDrift'] == 1) { $clusters[$c]['ms'] = true; } if ($row['SppDrift'] == 1) { $clusters[$c]['spp'] = true; } if ($row['Reachable'] == 0) { $clusters[$c]['unreach'] = true; } // UbrGap is stored identically on every node row of the run. $clusters[$c]['ubrgap'] = max($clusters[$c]['ubrgap'], (int)$row['UbrGap']); } } // Classify each cluster: DRIFT > UNREACHABLE > OK // DRIFT is now build-drift OR SPP-drift (NOT a pure UBR/KB gap). $ok = array(); $drift = array(); $unreach = array(); $ubrgap_list = array(); foreach ($clusters as $name => $cl) { if ($cl['build'] || $cl['spp']) { $clusters[$name]['status'] = 'DRIFT'; if (count($cl['nodes']) > 1) { $drift[] = $name; } } elseif ($cl['unreach']) { $clusters[$name]['status'] = 'UNREACHABLE'; $unreach[] = $name; } else { if (count($cl['nodes']) > 1){ // Build + SPP aligned and fully reachable. A non-zero // UBR gap means "conform at cluster level, but KB behind" // -> isolated in its own priority list, out of the OK set. if ((int)$clusters[$name]['ubrgap'] > 0) { $clusters[$name]['status'] = 'UBR_GAP'; $ubrgap_list[] = $name; } else { $clusters[$name]['status'] = 'OK'; $ok[] = $name; } } else { $clusters[$name]['status'] = 'OK'; } } } $count_ok = count($ok); $count_drift = count($drift); $count_unreach = count($unreach); $count_ubrgap = count($ubrgap_list); // Biggest gaps first, so the priority list is correct regardless // of any client-side sorting applied afterwards. usort($ubrgap_list, function($a, $b) use ($clusters) { return (int)$clusters[$b]['ubrgap'] <=> (int)$clusters[$a]['ubrgap']; }); // Per-cluster summary (distinct MS levels, builds, SPP signatures, // hardware facts, unreachable nodes, errors). function cluster_summary($cl) { $ms = array(); $builds = array(); $spp = array(); $models = array(); $bios = array(); $biosdates = array(); $unodes = array(); $errs = array(); foreach ($cl['nodes'] as $n) { if ($n['Reachable'] == 1) { if ($n['MsPatchLevel'] !== '' && $n['MsPatchLevel'] !== null) { $ms[] = $n['MsPatchLevel']; } if ($n['MsBuild'] !== '' && $n['MsBuild'] !== null) { $builds[] = $n['MsBuild']; } if ($n['SppSignature'] !== '' && $n['SppSignature'] !== null) { $spp[] = $n['SppSignature']; } if ($n['ServerModel'] !== '' && $n['ServerModel'] !== null) { $models[] = $n['ServerModel']; } if ($n['BiosVersion'] !== '' && $n['BiosVersion'] !== null) { $bios[] = $n['BiosVersion']; } if ($n['BiosDate'] !== '' && $n['BiosDate'] !== null) { $biosdates[] = $n['BiosDate']; } } else { $unodes[] = $n['NodeName']; if (!empty($n['ErrorMessage'])) { $errs[] = $n['ErrorMessage']; } } } $bios_u = array_values(array_unique($bios)); return array( 'ms' => array_values(array_unique($ms)), 'builds' => array_values(array_unique($builds)), 'spp' => array_values(array_unique($spp)), 'models' => array_values(array_unique($models)), 'bios' => $bios_u, 'biosdates' => array_values(array_unique($biosdates)), 'bios_drift' => (count($bios_u) > 1), 'ubrgap' => (int)$cl['ubrgap'], 'unodes' => $unodes, 'errs' => array_values(array_unique($errs)), 'nodecount' => count($cl['nodes']) ); } // Small helper: a coloured badge for the UBR gap value. function ubrgap_badge($gap) { $gap = (int)$gap; if ($gap <= 0) { return "0"; } $cls = ($gap >= 100) ? 'text-bg-danger' : 'text-bg-info'; return "".$gap.""; } ?>

Conformité des Clusters — Build MS / SPP HP / Matériel ()

Clusters en drift

Cluster Écart Nœuds Build(s) Gap UBR Niveau(x) MS Modèle(s) BIOS Date BIOS Signature(s) SPP Détail
BUILD"; } ?> SPP"; } ?> BIOS"; } ?> Détail

Écart UBR — même build, KB à rattraper

Ces clusters sont conformes au niveau cluster (build aligné), mais un ou plusieurs nœuds sont en retard de correctif. Triés par écart décroissant — les plus gros à corriger en priorité.

Cluster Gap UBR Nœuds Build Niveau(x) MS Modèle BIOS Détail
BIOS"; } ?> Détail

Clusters OK

Cluster Nœuds Build Gap UBR Niveau(x) MS Modèle BIOS Signature SPP
BIOS"; } ?>

Aucun cluster injoignable sur ce run.

  • —