strtotime('1990-01-01')) ? date('Y-m-d H:i', $ts) : '-'; } function fmt_lastgood($dateStr) { $days = days_since($dateStr); if ($days === null || $days > 365) return 'NEVER'; return date('Y-m-d H:i', strtotime($dateStr)) . " ({$days}J)"; } /* ------------------------------------------------------- active inventory */ $activeRows = Invoke_Infra("SELECT name FROM cmdb_vms WHERE CAST(lastinventory AS DATETIME) > DATEADD(DAY, -2, GETDATE())"); $active = []; foreach ($activeRows as $r) { $active[normalize_host($r['name'])] = true; } /* -------------------------------------------------------------- 1. Veeam */ $veeam = []; $rows = Invoke_Infra("SELECT * FROM Veeam_Reporting"); foreach ($rows as $row) { $key = normalize_host($row['ClientName']); if (!isset($active[$key])) continue; $ageGood = days_since($row['LastSuccess']); $status = trim((string) $row['LastStatus']); if ($status === 'Failed' || $status === 'Unknown' || $status === '') { $cat = 'error'; $cls = 'table-danger'; } elseif ($status === 'Warning') { $cat = 'warning'; $cls = 'table-warning'; } elseif ($ageGood === null || $ageGood >= backup_tolerance_days()) { $cat = 'outdated'; $cls = 'table-info'; } else { $cat = 'ok'; $cls = 'table-success'; } $veeam[$key] = [ 'cat' => $cat, 'row_class' => $cls, 'ts' => strtotime((string) $row['LastRun']) ?: 0, 'vm' => $row['ClientName'], 'last_run' => fmt_datetime($row['LastRun']), 'status' => $status, 'last_good' => fmt_lastgood($row['LastSuccess']), 'size' => $row['SizeGB'], 'extra' => $row['Duration'], 'policy' => $row['PolicyName'], 'message' => $row['ErrorMessage'], ]; } /* ---------------------------------------------------------- 2. NetBackup */ /* Source principale : dbo.NetBackupJobs Master pris en compte : dun-bkp-01 uniquement. Pour chaque client NetBackup : - le dernier FULL/INCREMENTAL donne l'état courant ; - le dernier FULL/INCREMENTAL avec status <= 1 donne "Last Good Backup" ; - dbo.NBRC fournit la description du code retour. La page reste une synthèse VM : seuls les clients présents dans cmdb_vms avec un inventaire récent sont retenus. */ $netbackup = []; $rows = Invoke_Infra(" WITH ScheduledJobs AS ( SELECT j.master, j.job, j.client, j.policy, j.schedule_type, j.status, j.start_date, j.end_date, j.size_kb, COALESCE(j.end_date, j.start_date) AS run_date, MAX( CASE WHEN j.status <= 1 THEN COALESCE(j.end_date, j.start_date) ELSE NULL END ) OVER ( PARTITION BY j.client ) AS last_success, ROW_NUMBER() OVER ( PARTITION BY j.client ORDER BY COALESCE(j.end_date, j.start_date) DESC, j.job DESC ) AS rn FROM dbo.NetBackupJobs j WHERE j.master like 'dun-bkp-01%' AND j.schedule_type IN ('full', 'incremental') ), Latest AS ( SELECT * FROM ScheduledJobs WHERE rn = 1 ) SELECT l.master, l.job, l.client, l.policy, l.schedule_type, l.status, l.start_date, l.end_date, l.run_date, l.last_success, l.size_kb, r.RC_DESC AS status_desc FROM Latest l LEFT JOIN dbo.NBRC r ON r.RC = l.status ORDER BY l.client "); if (!is_array($rows)) $rows = []; foreach ($rows as $row) { $key = normalize_host($row['client']); // This synthesis page is VM-oriented. if ($key === '' || !isset($active[$key])) continue; $statusCode = (int) $row['status']; $ageGood = days_since($row['last_success']); if ($statusCode > 1) { // Same policy as before: // a failed latest run remains only a warning while a recent good copy exists. if ($ageGood === null || $ageGood >= backup_tolerance_days()) { $cat = 'error'; $cls = 'table-danger'; } else { $cat = 'warning'; $cls = 'table-warning'; } } elseif ($ageGood === null || $ageGood >= backup_tolerance_days()) { $cat = 'outdated'; $cls = 'table-info'; } else { $cat = 'ok'; $cls = 'table-success'; } $statusDesc = trim((string)($row['status_desc'] ?? '')); if ($statusCode <= 1) { $statusText = 'OK'; } else { $statusText = 'Error ' . $statusCode; if ($statusDesc !== '') { $statusText .= ' - ' . $statusDesc; } } $runDate = $row['run_date'] ?? $row['start_date'] ?? null; $netbackup[$key] = [ 'cat' => $cat, 'row_class' => $cls, 'excluded' => false, 'ts' => strtotime((string)$runDate) ?: 0, 'vm' => $row['client'], 'last_run' => fmt_datetime($runDate), 'status' => $statusText, 'last_good' => fmt_lastgood($row['last_success']), 'size' => ($row['size_kb'] === null || $row['size_kb'] === '') ? '' : number_format(((float)$row['size_kb']) / 1048576, 1, '.', ''), 'extra' => $row['schedule_type'], 'policy' => $row['policy'], 'message' => ($statusCode > 1) ? $statusDesc : '', ]; } /* Keep only the explicit NoBackup exclusions from the old VMs_Backup table. NetBackupJobs cannot represent a deliberate exclusion because no backup job exists for an intentionally excluded VM. */ $excludedRows = Invoke_Infra(" SELECT name, Exclusion, Owner, Policy FROM VMs_Backup WHERE Exclusion IS NOT NULL AND LTRIM(RTRIM(Exclusion)) <> '' "); if (is_array($excludedRows)) { foreach ($excludedRows as $row) { $key = normalize_host($row['name']); // Do not overwrite a VM that has actual dun-bkp-01 job history. if ($key === '' || isset($netbackup[$key])) continue; $netbackup[$key] = [ 'cat' => 'excluded', 'row_class' => 'table-secondary', 'excluded' => true, 'ts' => 0, 'vm' => $row['name'], 'last_run' => 'Tag NoBackup', 'status' => 'Tag NoBackup', 'last_good' => 'Tag NoBackup', 'size' => '', 'extra' => '', 'policy' => $row['Policy'], 'message' => trim((string)$row['Exclusion']), ]; } } /* ------------------------------------------- 3. Migration de-duplication */ // A VM present on both sides is kept where the most recent backup lives. $migrated = 0; foreach (array_keys($netbackup) as $key) { if (!isset($veeam[$key])) continue; if ($netbackup[$key]['excluded'] || $veeam[$key]['ts'] >= $netbackup[$key]['ts']) { unset($netbackup[$key]); // Veeam has taken over $migrated++; } else { unset($veeam[$key]); // NetBackup is still the live copy } } /* -------------------------------------------------------- 4. Bucketing */ $buckets = [ 'veeam' => ['error' => [], 'warning' => [], 'outdated' => [], 'ok' => []], 'nb' => ['error' => [], 'warning' => [], 'outdated' => [], 'ok' => [], 'excluded' => []], ]; foreach ($veeam as $e) { $buckets['veeam'][$e['cat']][] = $e; } foreach ($netbackup as $e) { $buckets['nb'][$e['cat']][] = $e; } foreach ($buckets as $src => $cats) { foreach ($cats as $cat => $list) { usort($list, fn($a, $b) => strcasecmp($a['vm'], $b['vm'])); $buckets[$src][$cat] = $list; } } $veeamTotal = count($veeam); $nbTotal = count($netbackup); /* -------------------------------------------------------- 5. Rendering */ $blockMeta = [ 'error' => ['label' => 'Error', 'badge' => 'bg-danger', 'icon' => 'bi-x-octagon'], 'warning' => ['label' => 'Warning', 'badge' => 'bg-warning text-dark', 'icon' => 'bi-exclamation-triangle'], 'outdated' => ['label' => 'Outdated', 'badge' => 'bg-info text-dark', 'icon' => 'bi-clock-history'], 'ok' => ['label' => 'OK', 'badge' => 'bg-success', 'icon' => 'bi-check-circle'], 'excluded' => ['label' => 'Excluded', 'badge' => 'bg-secondary', 'icon' => 'bi-slash-circle'], ]; /** * Render one accordion item holding a bootstrap-table. * $extraLabel is "Duration" for Veeam and "Host" for NetBackup. */ function render_block($blockId, $meta, $rows, $extraLabel, $expanded = false) { $count = count($rows); $collapsed = $expanded ? '' : 'collapsed'; $show = $expanded ? 'show' : ''; $aria = $expanded ? 'true' : 'false'; ?>
>
Aucune VM dans cette catégorie.
(GB)
Message
VM Backup —
Veeam
/
NetBackup
—
Error
-
Warning
-
Outdated
VEEAM
VMs
NETBACKUP
VMs