- Introduced `Storage/VIO.php` for monitoring VIO Fibre Channel status with client balancing checks and table sorting. - Updated `/include/en.php` and `/include/fr.php` to include new translations for ServiceNow and VIO-related navigation elements. - Improved SQL query and filtering logic in `/X/Inventory.php` to exclude VIO entries and add XenSam version data. - Enhanced `/reports/heartbeat.php` with a new mechanism for handling server heartbeat status, allowing better granularity and readability.
222 lines
8.6 KiB
PHP
222 lines
8.6 KiB
PHP
<!DOCTYPE html>
|
|
<html lang="fr">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
|
|
<title>Web Infra Reports OT</title>
|
|
|
|
<script src="/js/jquery-3.6.1.min.js"></script>
|
|
<link rel="stylesheet" href="/css/bootstrap.min.css">
|
|
<link rel="stylesheet" href="/css/bootstrap-icons/bootstrap-icons.css">
|
|
<link rel="stylesheet" href="/css/preloader.css">
|
|
<script src="/js/bootstrap.bundle.min.js"></script>
|
|
<link rel="stylesheet" href="/css/bootstrap-table.min.css">
|
|
<script src="/js/bootstrap-table.min.js"></script>
|
|
<script src="/js/bootstrap-table-fr-FR.min.js"></script>
|
|
<script src="/js/tableExport.min.js"></script>
|
|
<script src="/js/bootstrap-table-export.min.js"></script>
|
|
<script src="/js/libs/js-xlsx/xlsx.core.min.js"></script>
|
|
|
|
<style>
|
|
code.sig { font-size: .85em; }
|
|
.table td { vertical-align: middle; }
|
|
.pivot th, .pivot td { text-align: center; }
|
|
.pivot td.comp { text-align: left; font-weight: 500; }
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<?php include $_SERVER['DOCUMENT_ROOT']."/include/all.php" ; ?>
|
|
<div class="container-fluid">
|
|
<div class="row flex-nowrap">
|
|
<div class="col-auto col-md-2 col-xl-2 px-sm-2 px-0 bg-dark" style="-ms-flex: 0 0 230px;flex: 0 0 230px;">
|
|
<?php include $_SERVER['DOCUMENT_ROOT']."/navbar.html" ; ?>
|
|
</div>
|
|
<div class="col py-3">
|
|
<?php
|
|
// -----------------------------------------------------------
|
|
// Helpers
|
|
// -----------------------------------------------------------
|
|
function majority($arr) {
|
|
if (count($arr) == 0) { return null; }
|
|
$c = array_count_values($arr);
|
|
arsort($c);
|
|
return key($c);
|
|
}
|
|
|
|
$cluster = isset($_GET['cluster']) ? $_GET['cluster'] : '';
|
|
$run = isset($_GET['run']) ? $_GET['run'] : '';
|
|
|
|
$conn = DB_INFRA();
|
|
|
|
$nodes = array();
|
|
$delta = array();
|
|
$runDate = '-';
|
|
|
|
if ($cluster !== '' && $run !== '') {
|
|
// --- Node facts (parameterized to avoid injection) -------
|
|
$sqlNodes = "SELECT NodeName, OsName, MsPatchLevel, LastHotfix,
|
|
CONVERT(VARCHAR(10), LastHotfixOn, 120) AS LastHotfixOn,
|
|
SppSignature, Reachable, MsDrift, SppDrift, ErrorMessage,
|
|
CONVERT(VARCHAR(16), RunDate, 120) AS RunDate
|
|
FROM dbo.ClusterComplianceResults
|
|
WHERE ClusterName = ? AND RunId = ?
|
|
ORDER BY NodeName";
|
|
$stmt = odbc_prepare($conn, $sqlNodes);
|
|
if ($stmt && odbc_execute($stmt, array($cluster, $run))) {
|
|
while ($r = odbc_fetch_array($stmt)) {
|
|
if ($runDate === '-' && !empty($r['RunDate'])) { $runDate = $r['RunDate']; }
|
|
$nodes[] = $r;
|
|
}
|
|
}
|
|
|
|
// --- SPP component delta ---------------------------------
|
|
$sqlDelta = "SELECT ComponentName, NodeName, ComponentVersion
|
|
FROM dbo.ClusterComplianceSppDelta
|
|
WHERE ClusterName = ? AND RunId = ?
|
|
ORDER BY ComponentName, NodeName";
|
|
$stmt2 = odbc_prepare($conn, $sqlDelta);
|
|
if ($stmt2 && odbc_execute($stmt2, array($cluster, $run))) {
|
|
while ($r = odbc_fetch_array($stmt2)) { $delta[] = $r; }
|
|
}
|
|
}
|
|
|
|
// Build the delta pivot : component x node
|
|
$deltaNodes = array();
|
|
$comps = array();
|
|
$matrix = array();
|
|
foreach ($delta as $d) {
|
|
$cp = $d['ComponentName'];
|
|
$nd = $d['NodeName'];
|
|
if (!in_array($nd, $deltaNodes)) { $deltaNodes[] = $nd; }
|
|
$comps[$cp] = true;
|
|
$matrix[$cp][$nd] = $d['ComponentVersion'];
|
|
}
|
|
sort($deltaNodes);
|
|
$comps = array_keys($comps);
|
|
sort($comps);
|
|
|
|
// MS majority for highlighting
|
|
$msVals = array();
|
|
foreach ($nodes as $n) {
|
|
if ($n['Reachable'] == 1 && $n['MsPatchLevel'] !== '' && $n['MsPatchLevel'] !== null) {
|
|
$msVals[] = $n['MsPatchLevel'];
|
|
}
|
|
}
|
|
$msMajority = majority($msVals);
|
|
?>
|
|
|
|
<h1>
|
|
<span class="badge text-bg-secondary" style="width:100%;">
|
|
Détail cluster : <?php echo htmlspecialchars($cluster); ?>
|
|
<small><small>(<?php echo htmlspecialchars($runDate); ?>)</small></small>
|
|
</span>
|
|
</h1>
|
|
|
|
<a href="cluster_compliance.php" class="btn btn-sm btn-outline-secondary mb-3">
|
|
<i class="bi bi-arrow-left"></i> Retour au tableau de bord
|
|
</a>
|
|
|
|
<?php if (count($nodes) == 0): ?>
|
|
<div class="alert alert-warning">Aucune donnée pour ce cluster / ce run.</div>
|
|
<?php else: ?>
|
|
|
|
<!-- ============ Node facts ============ -->
|
|
<h4 class="mt-3">État des nœuds</h4>
|
|
<table class="table table-bordered table-sm">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th>Nœud</th>
|
|
<th>OS</th>
|
|
<th>Niveau MS</th>
|
|
<th>Signature SPP</th>
|
|
<th>État</th>
|
|
<th>Erreur</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($nodes as $n): ?>
|
|
<?php
|
|
$msCls = '';
|
|
if ($n['Reachable'] == 1 && $msMajority !== null && $n['MsPatchLevel'] !== $msMajority) {
|
|
$msCls = 'table-warning';
|
|
}
|
|
?>
|
|
<tr>
|
|
<td><?php echo htmlspecialchars($n['NodeName']); ?></td>
|
|
<td><?php echo htmlspecialchars($n['OsName']); ?></td>
|
|
<td class="<?php echo $msCls; ?>"><?php echo htmlspecialchars($n['MsPatchLevel']); ?></td>
|
|
<td><code class="sig"><?php echo htmlspecialchars($n['SppSignature']); ?></code></td>
|
|
<td>
|
|
<?php if ($n['Reachable'] == 1): ?>
|
|
<span class="badge text-bg-success">Joignable</span>
|
|
<?php else: ?>
|
|
<span class="badge text-bg-danger">Injoignable</span>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td><small class="text-muted"><?php echo htmlspecialchars($n['ErrorMessage']); ?></small></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
|
|
<!-- ============ SPP delta pivot ============ -->
|
|
<h4 class="mt-4">Delta SPP HP (composants divergents)</h4>
|
|
<?php if (count($comps) == 0): ?>
|
|
<div class="alert alert-info mb-0">
|
|
Aucun écart de composant HP relevé (drift Microsoft uniquement, ou signatures identiques).
|
|
</div>
|
|
<?php else: ?>
|
|
<div class="table-responsive">
|
|
<table class="table table-bordered table-sm pivot">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th class="comp">Composant</th>
|
|
<?php foreach ($deltaNodes as $nd): ?>
|
|
<th><?php echo htmlspecialchars($nd); ?></th>
|
|
<?php endforeach; ?>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($comps as $cp): ?>
|
|
<?php
|
|
$rowVals = array();
|
|
foreach ($deltaNodes as $nd) {
|
|
$rowVals[] = isset($matrix[$cp][$nd]) ? $matrix[$cp][$nd] : '<absent>';
|
|
}
|
|
$maj = majority($rowVals);
|
|
?>
|
|
<tr>
|
|
<td class="comp"><?php echo htmlspecialchars($cp); ?></td>
|
|
<?php foreach ($deltaNodes as $nd): ?>
|
|
<?php
|
|
$v = isset($matrix[$cp][$nd]) ? $matrix[$cp][$nd] : '<absent>';
|
|
$cls = '';
|
|
if ($v === '<absent>') { $cls = 'table-danger'; }
|
|
elseif ($v !== $maj) { $cls = 'table-warning'; }
|
|
?>
|
|
<td class="<?php echo $cls; ?>"><?php echo htmlspecialchars($v); ?></td>
|
|
<?php endforeach; ?>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div class="small text-muted mt-1">
|
|
<span class="badge text-bg-warning text-dark">jaune</span> version différente de la majorité
|
|
<span class="badge text-bg-danger">rouge</span> composant absent du nœud
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php endif; /* nodes exist */ ?>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="/js/switch.js"></script>
|
|
</body>
|
|
</html>
|