Files
0012/public/ingest.php
T
Frank Schwenk 9b18b11f32 feat: boka push ingest and stale monitoring (todo 04)
Add token- and IP-protected ingest.php, boka status checks in monitor.php,
and document the two-repo push workflow. Todo 04 marked complete.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-12 14:51:19 +02:00

93 lines
2.8 KiB
PHP

<?php
declare(strict_types=1);
/**
* Receive push metrics from boka (POST JSON, token + IP whitelist).
* Usage: POST /ingest.php with JSON body from push-status.sh
*/
$configDir = is_dir(dirname(__DIR__) . '/private/config')
? dirname(__DIR__) . '/private/config'
: dirname(__DIR__) . '/config';
require_once $configDir . '/monitor-lib.php';
header('Content-Type: application/json; charset=utf-8');
function ingestError(int $code, string $message): never
{
http_response_code($code);
echo json_encode(['ok' => false, 'error' => $message], JSON_UNESCAPED_SLASHES);
exit;
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
ingestError(405, 'method not allowed');
}
$allowedIp = env('BOKA_IP');
if ($allowedIp !== null && $allowedIp !== '') {
$remoteAddr = $_SERVER['REMOTE_ADDR'] ?? '';
if (!hash_equals($allowedIp, $remoteAddr)) {
ingestError(403, 'forbidden');
}
}
$raw = file_get_contents('php://input');
if ($raw === false || $raw === '') {
ingestError(400, 'empty body');
}
$data = json_decode($raw, true);
if (!is_array($data)) {
ingestError(400, 'invalid json');
}
$expectedToken = env('MONITOR_INGEST_TOKEN') ?? '';
$token = isset($data['token']) && is_string($data['token']) ? $data['token'] : '';
if ($expectedToken === '' || !hash_equals($expectedToken, $token)) {
ingestError(403, 'forbidden');
}
if (!isset($data['load']) || !is_array($data['load'])) {
ingestError(400, 'missing load');
}
foreach (['disk_percent', 'mem_available_mb', 'containers_running', 'containers_unhealthy'] as $field) {
if (!isset($data[$field]) || !is_numeric($data[$field])) {
ingestError(400, "missing {$field}");
}
}
$load = array_map(static fn (mixed $v): float => (float) $v, $data['load']);
$backupLastSuccess = null;
if (isset($data['backup_last_success']) && is_string($data['backup_last_success']) && $data['backup_last_success'] !== '') {
$backupLastSuccess = $data['backup_last_success'];
}
$host = isset($data['host']) && is_string($data['host']) ? $data['host'] : 'boka';
$clientTimestamp = isset($data['timestamp']) && is_string($data['timestamp']) ? $data['timestamp'] : null;
$status = [
'last_push' => gmdate('c'),
'received_from' => $_SERVER['REMOTE_ADDR'] ?? null,
'host' => $host,
'client_timestamp' => $clientTimestamp,
'load' => $load,
'disk_percent' => (int) $data['disk_percent'],
'mem_available_mb' => (int) $data['mem_available_mb'],
'containers_running' => (int) $data['containers_running'],
'containers_unhealthy' => (int) $data['containers_unhealthy'],
'backup_last_success' => $backupLastSuccess,
];
try {
writeJsonFile(privateDataDir() . '/boka-status.json', $status);
} catch (Throwable $e) {
ingestError(500, 'storage error');
}
echo json_encode(['ok' => true], JSON_UNESCAPED_SLASHES);