- 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.
396 lines
8.6 KiB
PHP
396 lines
8.6 KiB
PHP
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<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>Infra Reports IT</title>
|
|
|
|
<link rel="shortcut icon" type="image/png" href="/include/favicon-32x32.png">
|
|
|
|
<!-- Bootstrap -->
|
|
<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" defer></script>
|
|
<script src="/js/jquery-3.6.1.min.js" defer></script>
|
|
</head>
|
|
|
|
<body class="bg-light text-dark">
|
|
|
|
<?php
|
|
|
|
include $_SERVER['DOCUMENT_ROOT'] . "/include/all.php";
|
|
|
|
/**
|
|
* Récupère une valeur dans un tableau sans dépendre de la casse
|
|
* utilisée par le pilote ODBC.
|
|
*/
|
|
function getRowValue(array $row, string $key, $default = null)
|
|
{
|
|
if (array_key_exists($key, $row)) {
|
|
return $row[$key];
|
|
}
|
|
|
|
$upperKey = strtoupper($key);
|
|
|
|
if (array_key_exists($upperKey, $row)) {
|
|
return $row[$upperKey];
|
|
}
|
|
|
|
$lowerKey = strtolower($key);
|
|
|
|
if (array_key_exists($lowerKey, $row)) {
|
|
return $row[$lowerKey];
|
|
}
|
|
|
|
return $default;
|
|
}
|
|
|
|
/**
|
|
* Génère les listes de serveurs OK et en erreur.
|
|
*/
|
|
function buildHeartbeatStatus(
|
|
array $servers,
|
|
string $hostnameKey,
|
|
string $heartbeatKey,
|
|
string $previousHeartbeatKey,
|
|
string $limit
|
|
): array {
|
|
$okItems = [];
|
|
$koItems = [];
|
|
$issueCount = 0;
|
|
|
|
foreach ($servers as $server) {
|
|
$hostname = trim((string)getRowValue($server, $hostnameKey, ''));
|
|
|
|
if ($hostname === '') {
|
|
continue;
|
|
}
|
|
|
|
$heartbeat = getRowValue($server, $heartbeatKey);
|
|
$previousHeartbeat = getRowValue(
|
|
$server,
|
|
$previousHeartbeatKey,
|
|
$heartbeat
|
|
);
|
|
|
|
$hostnameDisplay = htmlspecialchars(
|
|
strtoupper($hostname),
|
|
ENT_QUOTES,
|
|
'UTF-8'
|
|
);
|
|
|
|
/*
|
|
* Une date absente est considérée comme une erreur.
|
|
* Les dates au format Y-m-d H:i:s peuvent être comparées
|
|
* directement sous forme de chaînes.
|
|
*/
|
|
$isKo = empty($heartbeat) || $heartbeat < $limit;
|
|
|
|
if ($isKo) {
|
|
$previousDisplay = 'unknown';
|
|
|
|
if (!empty($previousHeartbeat)) {
|
|
$previousDisplay = explode('.', (string)$previousHeartbeat)[0];
|
|
$previousDisplay = htmlspecialchars(
|
|
$previousDisplay,
|
|
ENT_QUOTES,
|
|
'UTF-8'
|
|
);
|
|
}
|
|
|
|
$koItems[] = "
|
|
<div class=\"col-12 col-md-6 mb-1\">
|
|
<span class=\"badge bg-danger text-wrap\">
|
|
{$hostnameDisplay} since {$previousDisplay}
|
|
</span>
|
|
</div>
|
|
";
|
|
|
|
$issueCount++;
|
|
} else {
|
|
$okItems[] = "
|
|
<div class=\"col-6 col-md-4 col-xl-2 mb-1\">
|
|
<span class=\"badge bg-success text-wrap\">
|
|
{$hostnameDisplay}
|
|
</span>
|
|
</div>
|
|
";
|
|
}
|
|
}
|
|
|
|
return [
|
|
'ok' => implode('', $okItems),
|
|
'ko' => implode('', $koItems),
|
|
'issues' => $issueCount
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Affiche une section de l'accordéon.
|
|
*/
|
|
function displayHeartbeatSection(
|
|
string $id,
|
|
string $title,
|
|
array $servers,
|
|
array $status,
|
|
string $deviceLabel
|
|
): void {
|
|
$count = count($servers);
|
|
$issues = $status['issues'];
|
|
|
|
$backgroundColor = $issues > 0 ? 'DarkOrange' : 'green';
|
|
|
|
$message = $issues > 0
|
|
? "<strong> → {$issues} issue(s)</strong>"
|
|
: 'OK';
|
|
|
|
?>
|
|
<div class="card mb-3" style="background-color: <?= $backgroundColor ?>;">
|
|
<h4 class="card-header">
|
|
<button
|
|
class="btn text-white fs-3 text-start w-100"
|
|
type="button"
|
|
data-bs-toggle="collapse"
|
|
data-bs-target="#<?= htmlspecialchars($id, ENT_QUOTES, 'UTF-8') ?>"
|
|
aria-expanded="false"
|
|
aria-controls="<?= htmlspecialchars($id, ENT_QUOTES, 'UTF-8') ?>"
|
|
>
|
|
<strong>
|
|
<?= htmlspecialchars($title, ENT_QUOTES, 'UTF-8') ?> :
|
|
<?= $count ?>
|
|
<?= htmlspecialchars($deviceLabel, ENT_QUOTES, 'UTF-8') ?>
|
|
<?= $message ?>
|
|
</strong>
|
|
</button>
|
|
</h4>
|
|
</div>
|
|
|
|
<div
|
|
id="<?= htmlspecialchars($id, ENT_QUOTES, 'UTF-8') ?>"
|
|
class="accordion-collapse collapse"
|
|
data-bs-parent="#accordion"
|
|
>
|
|
<div class="card card-body mb-3 bg-light">
|
|
<?php if ($issues > 0): ?>
|
|
<h5 class="mb-3">Issues</h5>
|
|
|
|
<div class="row">
|
|
<?= $status['ko'] ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($status['ok'] !== ''): ?>
|
|
<?php if ($issues > 0): ?>
|
|
<hr>
|
|
<?php endif; ?>
|
|
|
|
<h5 class="mb-3">OK</h5>
|
|
|
|
<div class="row">
|
|
<?= $status['ok'] ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
/*
|
|
* Seuils de heartbeat.
|
|
*/
|
|
$unixHeartbeatLimit = date(
|
|
'Y-m-d H:i:s',
|
|
time() - (11 * 60)
|
|
);
|
|
|
|
$windowsHeartbeatLimit = date(
|
|
'Y-m-d H:i:s',
|
|
time() - (16 * 60)
|
|
);
|
|
|
|
/*
|
|
* Serveurs Windows.
|
|
*/
|
|
$windows = Invoke_Infra("
|
|
SELECT
|
|
c.hostname,
|
|
c.heartbeat
|
|
FROM cmdb_srvall c
|
|
WHERE c.decom IS NULL
|
|
AND c.hostname <> ''
|
|
AND NOT EXISTS (
|
|
SELECT 1
|
|
FROM maintenance_status m
|
|
WHERE m.server = c.hostname
|
|
AND (
|
|
m.scom = 'Y'
|
|
OR m.zabbix = 'Y'
|
|
)
|
|
)
|
|
ORDER BY c.hostname ASC
|
|
");
|
|
|
|
/*
|
|
* Linux, AIX et autres :
|
|
* une seule requête au lieu de trois.
|
|
*/
|
|
$unixServers = Invoke_aixcmdb("
|
|
SELECT
|
|
h.hostname,
|
|
h.hbtime,
|
|
h.prevtime,
|
|
s.os_type
|
|
FROM heartbeat h
|
|
LEFT JOIN srvall s
|
|
ON s.hostname = h.hostname
|
|
WHERE h.mainttime IS NULL
|
|
AND h.decomtime IS NULL
|
|
AND (
|
|
s.os_type IN ('LINUX', 'AIX')
|
|
OR s.os_type IS NULL
|
|
)
|
|
ORDER BY h.hostname ASC
|
|
");
|
|
|
|
/*
|
|
* Répartition des résultats Unix.
|
|
*/
|
|
$linux = [];
|
|
$aix = [];
|
|
$other = [];
|
|
|
|
foreach ($unixServers as $server) {
|
|
$osType = strtoupper(
|
|
trim((string)getRowValue($server, 'os_type', ''))
|
|
);
|
|
|
|
switch ($osType) {
|
|
case 'LINUX':
|
|
$linux[] = $server;
|
|
break;
|
|
|
|
case 'AIX':
|
|
$aix[] = $server;
|
|
break;
|
|
|
|
default:
|
|
$other[] = $server;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Génération des états.
|
|
*/
|
|
$windowsStatus = buildHeartbeatStatus(
|
|
$windows,
|
|
'hostname',
|
|
'heartbeat',
|
|
'heartbeat',
|
|
$windowsHeartbeatLimit
|
|
);
|
|
|
|
$linuxStatus = buildHeartbeatStatus(
|
|
$linux,
|
|
'hostname',
|
|
'hbtime',
|
|
'prevtime',
|
|
$unixHeartbeatLimit
|
|
);
|
|
|
|
$aixStatus = buildHeartbeatStatus(
|
|
$aix,
|
|
'hostname',
|
|
'hbtime',
|
|
'prevtime',
|
|
$unixHeartbeatLimit
|
|
);
|
|
|
|
$otherStatus = buildHeartbeatStatus(
|
|
$other,
|
|
'hostname',
|
|
'hbtime',
|
|
'prevtime',
|
|
$unixHeartbeatLimit
|
|
);
|
|
|
|
?>
|
|
|
|
<div class="container-fluid" id="content">
|
|
<div class="row flex-nowrap">
|
|
|
|
<!-- Left navbar -->
|
|
<div
|
|
class="col-auto col-md-2 col-xl-2 px-sm-2 px-0 bg-dark vh-100 position-sticky top-0"
|
|
style="-ms-flex: 0 0 230px; flex: 0 0 230px;"
|
|
>
|
|
<?php include $_SERVER['DOCUMENT_ROOT'] . "/navbar.html"; ?>
|
|
</div>
|
|
|
|
<!-- Display -->
|
|
<main class="col py-3">
|
|
|
|
<!-- Page title -->
|
|
<h1>
|
|
<span
|
|
class="badge text-bg-secondary fw-bold"
|
|
style="width: 100%;"
|
|
>
|
|
<?= htmlspecialchars((string)$ti_17, ENT_QUOTES, 'UTF-8') ?>
|
|
</span>
|
|
</h1>
|
|
|
|
<!-- Main content -->
|
|
<div class="container">
|
|
<div class="accordion" id="accordion">
|
|
|
|
<?php
|
|
displayHeartbeatSection(
|
|
'windows',
|
|
'Windows',
|
|
$windows,
|
|
$windowsStatus,
|
|
$w_devices
|
|
);
|
|
|
|
displayHeartbeatSection(
|
|
'linux',
|
|
'Linux',
|
|
$linux,
|
|
$linuxStatus,
|
|
$w_devices
|
|
);
|
|
|
|
displayHeartbeatSection(
|
|
'aix',
|
|
'AIX',
|
|
$aix,
|
|
$aixStatus,
|
|
$w_devices
|
|
);
|
|
|
|
displayHeartbeatSection(
|
|
'other',
|
|
'Other',
|
|
$other,
|
|
$otherStatus,
|
|
$w_devices
|
|
);
|
|
?>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
</main>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="/js/switch.js"></script>
|
|
|
|
</body>
|
|
</html>
|