204 lines
7.6 KiB
PHP
204 lines
7.6 KiB
PHP
<?php
|
||
|
||
namespace App\Console\Commands;
|
||
|
||
use Illuminate\Console\Command;
|
||
use App\Models\Setting;
|
||
|
||
class StorageProbe extends Command
|
||
{
|
||
protected $signature = 'health:probe-disk {target=/}';
|
||
protected $description = 'Speichert Storage-Werte (inkl. Breakdown) in settings:health.disk';
|
||
|
||
public function handle(): int
|
||
{
|
||
$target = $this->argument('target') ?: '/';
|
||
$data = $this->probe($target);
|
||
|
||
Setting::set('health.disk', $data);
|
||
Setting::set('health.disk_updated_at', now()->toIso8601String());
|
||
|
||
$this->info(sprintf(
|
||
'Storage %s → total:%dGB used:%dGB free_user:%dGB free+5%%:%dGB (%%used:%d) breakdown: system=%.1fGB mails=%.1fGB backups=%.1fGB',
|
||
$data['mount'],
|
||
$data['total_gb'],
|
||
$data['used_gb'],
|
||
$data['free_gb'],
|
||
$data['free_plus_reserve_gb'],
|
||
$data['percent_used_total'],
|
||
$data['breakdown_bytes']['system'],
|
||
$data['breakdown_bytes']['mails'],
|
||
$data['breakdown_bytes']['backup'],
|
||
));
|
||
|
||
return self::SUCCESS;
|
||
}
|
||
|
||
protected function probe(string $target): array
|
||
{
|
||
// --- df: Gesamtdaten des Filesystems (inkl. Reserve) -----------------
|
||
$line = trim((string)@shell_exec('LC_ALL=C df -kP ' . escapeshellarg($target) . ' 2>/dev/null | tail -n1'));
|
||
|
||
$device = $mount = '';
|
||
$totalKb = $usedKb = $availKb = 0;
|
||
|
||
if ($line !== '') {
|
||
$p = preg_split('/\s+/', $line);
|
||
if (count($p) >= 6) {
|
||
$device = $p[0];
|
||
$totalKb = (int)$p[1]; // TOTAL (inkl. Reserve)
|
||
$usedKb = (int)$p[2]; // Used
|
||
$availKb = (int)$p[3]; // Avail (User-sicht)
|
||
$mount = $p[5];
|
||
}
|
||
}
|
||
|
||
$toGiB_i = static fn($kb) => (int)round(max(0, (int)$kb) / (1024 * 1024)); // ganzzahlig (UI: Gesamt/Genutzt/Frei)
|
||
$toGiB_f = static fn($kb) => round(max(0, (int)$kb) / (1024 * 1024), 1); // eine Nachkommastelle (Breakdown/Legende)
|
||
|
||
$totalGb = $toGiB_i($totalKb);
|
||
$freeGb = $toGiB_i($availKb); // user-verfügbar
|
||
$usedGb = max(0, $totalGb - $freeGb); // belegt inkl. Reserve
|
||
$res5Gb = (int)round($totalGb * 0.05); // 5% von Gesamt
|
||
$freePlusReserveGb = min($totalGb, $freeGb + $res5Gb);
|
||
$percentUsed = $totalGb > 0 ? (int)round($usedGb * 100 / $totalGb) : 0;
|
||
|
||
// --- du: reale Verbräuche bestimmter Bäume (KB) -----------------------
|
||
// $duKb = function (string $path): int {
|
||
// if (!is_dir($path)) return 0;
|
||
// $kb = (int)trim((string)@shell_exec('LC_ALL=C du -sk --apparent-size ' . escapeshellarg($path) . ' 2>/dev/null | cut -f1'));
|
||
// return max(0, $kb);
|
||
// };
|
||
//
|
||
// $kbMails = $duKb('/var/mail/vhosts');
|
||
// $kbBackup = $duKb('/var/backups/mailwolt');
|
||
//
|
||
// // „System“ = alles übrige, was nicht Mails/Backups ist (OS, App, Logs, DB-Daten, …)
|
||
// $gbMails = $toGiB_f($kbMails);
|
||
// $gbBackup = $toGiB_f($kbBackup);
|
||
//
|
||
// // system_gb aus „usedGb – (mails+backup)“, nie negativ
|
||
// $gbSystem = max(0, round($usedGb - ($gbMails + $gbBackup), 1));
|
||
|
||
$duBytes = function (string $path): int {
|
||
if (!is_dir($path)) return 0;
|
||
$b = (int) trim((string) @shell_exec(
|
||
'LC_ALL=C du -sb --apparent-size ' . escapeshellarg($path) . ' 2>/dev/null | cut -f1'
|
||
));
|
||
return max(0, $b);
|
||
};
|
||
|
||
$bytesMails = $duBytes('/var/mail/vhosts');
|
||
$bytesBackup = $duBytes('/var/backups/mailwolt');
|
||
|
||
// used_gb in Bytes nachrechnen (aus df)
|
||
$totalBytes = (int) $totalKb * 1024;
|
||
$freeBytes = (int) $availKb * 1024;
|
||
$usedBytes = max(0, $totalBytes - $freeBytes);
|
||
|
||
// „System“ = Rest
|
||
$bytesSystem = max(0, $usedBytes - ($bytesMails + $bytesBackup));
|
||
|
||
return [
|
||
'device' => $device ?: 'unknown',
|
||
'mount' => $mount ?: $target,
|
||
|
||
'total_gb' => $totalGb,
|
||
'used_gb' => $usedGb, // inkl. Reserve
|
||
'free_gb' => $freeGb, // User-sicht
|
||
'reserve5_gb' => $res5Gb, // Info
|
||
'free_plus_reserve_gb' => $freePlusReserveGb, // Anzeige „Frei“
|
||
|
||
'percent_used_total' => $percentUsed,
|
||
|
||
// Reale Breakdown-Werte
|
||
'breakdown_bytes' => [
|
||
'system' => $bytesSystem,
|
||
'mails' => $bytesMails,
|
||
'backup' => $bytesBackup,
|
||
],
|
||
];
|
||
}
|
||
}
|
||
|
||
//
|
||
//namespace App\Console\Commands;
|
||
//
|
||
//use Illuminate\Console\Command;
|
||
//use App\Models\Setting;
|
||
//
|
||
//class StorageProbe extends Command
|
||
//{
|
||
// protected $signature = 'health:probe-disk {target=/}';
|
||
// protected $description = 'Speichert Storage-Werte (inkl. Frei+5%) in settings:health.disk';
|
||
//
|
||
// public function handle(): int
|
||
// {
|
||
// $target = $this->argument('target') ?: '/';
|
||
// $data = $this->probe($target);
|
||
//
|
||
// // Persistiert (DB + Redis) über dein Settings-Model
|
||
// Setting::set('health.disk', $data);
|
||
// Setting::set('health.disk_updated_at', now()->toIso8601String());
|
||
//
|
||
// $this->info(sprintf(
|
||
// 'Storage %s → total:%dGB used:%dGB free_user:%dGB free+5%%:%dGB (%%used:%d)',
|
||
// $data['mount'],
|
||
// $data['total_gb'],
|
||
// $data['used_gb'],
|
||
// $data['free_gb'],
|
||
// $data['free_plus_reserve_gb'],
|
||
// $data['percent_used_total'],
|
||
// ));
|
||
//
|
||
// return self::SUCCESS;
|
||
// }
|
||
//
|
||
// protected function probe(string $target): array
|
||
// {
|
||
// $line = trim((string) @shell_exec('df -kP ' . escapeshellarg($target) . ' 2>/dev/null | tail -n1'));
|
||
//
|
||
// $device = $mount = '';
|
||
// $totalKb = $usedKb = $availKb = 0;
|
||
//
|
||
// if ($line !== '') {
|
||
// $p = preg_split('/\s+/', $line);
|
||
// if (count($p) >= 6) {
|
||
// $device = $p[0];
|
||
// $totalKb = (int) $p[1]; // TOTAL (inkl. Reserve)
|
||
// $usedKb = (int) $p[2]; // Used
|
||
// $availKb = (int) $p[3]; // Avail (User-sicht)
|
||
// $mount = $p[5];
|
||
// }
|
||
// }
|
||
//
|
||
// $toGiB = static fn($kb) => (int) round(max(0, (int)$kb) / (1024*1024));
|
||
//
|
||
// $totalGb = $toGiB($totalKb);
|
||
// $freeGb = $toGiB($availKb); // user-verfügbar
|
||
// $usedGb = max(0, $totalGb - $freeGb); // belegt inkl. Reserve
|
||
// $res5Gb = (int) round($totalGb * 0.05); // 5% von Gesamt
|
||
// $freePlusReserveGb = min($totalGb, $freeGb + $res5Gb);
|
||
//
|
||
// $percentUsed = $totalGb > 0 ? (int) round($usedGb * 100 / $totalGb) : 0;
|
||
//
|
||
// return [
|
||
// 'device' => $device ?: 'unknown',
|
||
// 'mount' => $mount ?: $target,
|
||
//
|
||
// 'total_gb' => $totalGb,
|
||
// 'used_gb' => $usedGb, // inkl. Reserve
|
||
// 'free_gb' => $freeGb, // User-sicht
|
||
// 'reserve5_gb' => $res5Gb, // Info
|
||
// 'free_plus_reserve_gb' => $freePlusReserveGb, // ← das willst du anzeigen
|
||
//
|
||
// 'percent_used_total' => $percentUsed, // fürs Donut (~15%)
|
||
// 'breakdown' => [
|
||
// 'system_gb' => 5.2, // OS, App, Logs …
|
||
// 'mails_gb' => 2.8, // /var/mail/vhosts
|
||
// 'backup_gb' => 1.0, // /var/backups/mailwolt (oder wohin du sicherst)
|
||
// ],
|
||
// ];
|
||
// }
|
||
//}
|