Add checksum validation for archived media
This commit is contained in:
@@ -46,6 +46,12 @@ class MonitorStorageCommand extends Command
|
||||
|
||||
$assetStats = $this->buildAssetStatistics();
|
||||
$thresholds = $this->capacityThresholds();
|
||||
$checksumConfig = $this->checksumAlertConfig();
|
||||
$checksumWindowMinutes = $checksumConfig['window_minutes'];
|
||||
$checksumThresholds = $checksumConfig['thresholds'];
|
||||
$checksumMismatches = $checksumConfig['enabled'] && $checksumWindowMinutes > 0
|
||||
? $this->checksumMismatchCounts($checksumWindowMinutes)
|
||||
: [];
|
||||
$alerts = [];
|
||||
$snapshotTargets = [];
|
||||
|
||||
@@ -78,6 +84,7 @@ class MonitorStorageCommand extends Command
|
||||
];
|
||||
}
|
||||
|
||||
$targetChecksumMismatches = $checksumMismatches[$target->id] ?? 0;
|
||||
$snapshotTargets[] = [
|
||||
'id' => $target->id,
|
||||
'key' => $target->key,
|
||||
@@ -85,13 +92,35 @@ class MonitorStorageCommand extends Command
|
||||
'is_hot' => (bool) $target->is_hot,
|
||||
'capacity' => $capacity,
|
||||
'assets' => $assets,
|
||||
'checksum_mismatches' => [
|
||||
'count' => $targetChecksumMismatches,
|
||||
'window_minutes' => $checksumWindowMinutes,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
if ($checksumConfig['enabled'] && $checksumWindowMinutes > 0) {
|
||||
$totalMismatches = array_sum($checksumMismatches);
|
||||
$checksumSeverity = $this->determineChecksumSeverity($totalMismatches, $checksumThresholds);
|
||||
|
||||
if ($checksumSeverity !== 'ok') {
|
||||
$alerts[] = [
|
||||
'type' => 'checksum_mismatch',
|
||||
'severity' => $checksumSeverity,
|
||||
'count' => $totalMismatches,
|
||||
'window_minutes' => $checksumWindowMinutes,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$snapshot = [
|
||||
'generated_at' => now()->toIso8601String(),
|
||||
'targets' => $snapshotTargets,
|
||||
'alerts' => $alerts,
|
||||
'checksum' => [
|
||||
'window_minutes' => $checksumWindowMinutes,
|
||||
'mismatch_total' => array_sum($checksumMismatches),
|
||||
],
|
||||
];
|
||||
|
||||
$ttlMinutes = max(1, (int) config('storage-monitor.monitor.cache_minutes', 15));
|
||||
@@ -191,4 +220,62 @@ class MonitorStorageCommand extends Command
|
||||
|
||||
return 'ok';
|
||||
}
|
||||
|
||||
private function checksumAlertConfig(): array
|
||||
{
|
||||
$enabled = (bool) config('storage-monitor.checksum_validation.enabled', true);
|
||||
$windowMinutes = max(0, (int) config('storage-monitor.checksum_validation.alert_window_minutes', 60));
|
||||
$warning = (int) config('storage-monitor.checksum_validation.thresholds.warning', 1);
|
||||
$critical = (int) config('storage-monitor.checksum_validation.thresholds.critical', 5);
|
||||
|
||||
if ($warning > $critical && $critical > 0) {
|
||||
[$warning, $critical] = [$critical, $warning];
|
||||
}
|
||||
|
||||
return [
|
||||
'enabled' => $enabled,
|
||||
'window_minutes' => $windowMinutes,
|
||||
'thresholds' => [
|
||||
'warning' => $warning,
|
||||
'critical' => $critical,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
private function checksumMismatchCounts(int $windowMinutes): array
|
||||
{
|
||||
$query = EventMediaAsset::query()
|
||||
->selectRaw('media_storage_target_id, COUNT(*) as total_count')
|
||||
->where('status', 'failed')
|
||||
->where('meta->checksum_status', 'mismatch');
|
||||
|
||||
if ($windowMinutes > 0) {
|
||||
$query->where('updated_at', '>=', now()->subMinutes($windowMinutes));
|
||||
}
|
||||
|
||||
return $query->groupBy('media_storage_target_id')
|
||||
->get()
|
||||
->mapWithKeys(fn ($row) => [(int) $row->media_storage_target_id => (int) $row->total_count])
|
||||
->all();
|
||||
}
|
||||
|
||||
private function determineChecksumSeverity(int $count, array $thresholds): string
|
||||
{
|
||||
$warning = (int) ($thresholds['warning'] ?? 1);
|
||||
$critical = (int) ($thresholds['critical'] ?? 5);
|
||||
|
||||
if ($count <= 0) {
|
||||
return 'ok';
|
||||
}
|
||||
|
||||
if ($critical > 0 && $count >= $critical) {
|
||||
return 'critical';
|
||||
}
|
||||
|
||||
if ($warning > 0 && $count >= $warning) {
|
||||
return 'warning';
|
||||
}
|
||||
|
||||
return 'ok';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user