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."";
}
?>
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.