cron und module

This commit is contained in:
2026-03-08 02:31:08 +01:00
parent 0b53d7756e
commit f52bb684ce
5 changed files with 466 additions and 2 deletions

View File

@@ -0,0 +1,121 @@
<?php
declare(strict_types=1);
$root = dirname(__DIR__, 2);
chdir($root);
require $root . '/config/fileload.php';
$module = 'pi_control';
$pdo = module_fn($module, 'pdo');
module_fn($module, 'ensure_schema');
$table = fn(string $name) => module_fn($module, 'table', $name);
$settings = modules()->settings($module);
$strictHostKey = !empty($settings['terminal_strict_hostkey']);
$updateCmd = "apt-get -s upgrade | grep '^Inst'";
$upgradeCmd = 'current="$(. /etc/os-release && echo "$VERSION_CODENAME")"; latest="$(curl -fsSL https://deb.debian.org/debian/dists/stable/Release | awk -F\': \' \'/^Codename:/{print $2}\')"; echo "Installed: $current"; echo "Latest stable: $latest"; [ "$current" != "$latest" ] && echo "OS UPGRADE AVAILABLE" || echo "NO OS UPGRADE AVAILABLE"';
$driver = (string)$pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
$nowExpr = $driver === 'pgsql' ? 'NOW()' : "DATETIME('now')";
$hosts = $pdo->query('SELECT * FROM ' . $table('hosts'))->fetchAll(PDO::FETCH_ASSOC);
foreach ($hosts as $host) {
$id = (int)($host['id'] ?? 0);
if ($id <= 0) continue;
[$updExit, $updOut, $updErr] = runSshCommandCapture($host, $updateCmd, $strictHostKey, 20);
$lines = array_values(array_filter(preg_split('/\r?\n/', (string)$updOut)));
$updateCount = $updExit === 0 ? count($lines) : null;
$updatePreview = $updateCount ? implode("\n", array_slice($lines, 0, 6)) : '';
[$upgExit, $upgOut, $upgErr] = runSshCommandCapture($host, $upgradeCmd, $strictHostKey, 25);
$upgradeAvailable = null;
if ($upgExit === 0) {
$upgradeAvailable = str_contains($upgOut, 'OS UPGRADE AVAILABLE');
}
$updErrVal = $updExit === 0 ? null : trim($updErr ?: $updOut);
$upgErrVal = $upgExit === 0 ? null : trim($upgErr ?: $upgOut);
$stmt = $pdo->prepare(
'UPDATE ' . $table('hosts') . ' SET update_checked_at = ' . $nowExpr . ',
update_count = :update_count,
update_preview = :update_preview,
update_error = :update_error,
upgrade_available = :upgrade_available,
upgrade_raw = :upgrade_raw,
upgrade_error = :upgrade_error
WHERE id = :id'
);
$stmt->execute([
'update_count' => $updateCount,
'update_preview' => $updatePreview !== '' ? $updatePreview : null,
'update_error' => $updErrVal,
'upgrade_available' => $upgradeAvailable === null ? null : ($upgradeAvailable ? 1 : 0),
'upgrade_raw' => $upgExit === 0 ? trim($upgOut) : null,
'upgrade_error' => $upgErrVal,
'id' => $id,
]);
}
echo "OK\n";
function runSshCommandCapture(array $host, string $command, bool $strictHostKey, int $timeoutSec): array
{
$hostAddr = (string)($host['host'] ?? '');
$user = (string)($host['username'] ?? '');
$port = (int)($host['port'] ?? 22);
$authType = (string)($host['auth_type'] ?? 'key');
$keyPath = (string)($host['key_path'] ?? '');
$password = (string)($host['password'] ?? '');
$opts = $strictHostKey
? '-o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=/root/.ssh/known_hosts'
: '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null';
$opts .= ' -o ConnectTimeout=6 -o NumberOfPasswordPrompts=1';
$target = escapeshellarg($user . '@' . $hostAddr);
$remote = '/bin/bash -lc ' . escapeshellarg($command);
$cmd = 'ssh ' . $opts . ' -p ' . (int)$port . ' ';
if ($authType === 'key' && $keyPath !== '') {
$cmd .= '-i ' . escapeshellarg($keyPath) . ' -o BatchMode=yes ';
} elseif ($authType === 'key') {
$cmd .= '-o BatchMode=yes ';
}
$cmd .= $target . ' -- ' . $remote;
if ($authType === 'pass' && $password !== '') {
$cmd = 'sshpass -p ' . escapeshellarg($password) . ' ' . $cmd;
}
$descriptors = [
1 => ['pipe', 'w'],
2 => ['pipe', 'w'],
];
$process = proc_open($cmd, $descriptors, $pipes);
if (!is_resource($process)) {
return [255, '', 'proc_open failed'];
}
stream_set_blocking($pipes[1], false);
stream_set_blocking($pipes[2], false);
$out = '';
$err = '';
$start = time();
while (true) {
$status = proc_get_status($process);
$out .= stream_get_contents($pipes[1]);
$err .= stream_get_contents($pipes[2]);
if (!$status['running']) {
$exit = (int)$status['exitcode'];
proc_close($process);
return [$exit, $out, $err];
}
if (time() - $start > $timeoutSec) {
proc_terminate($process, 9);
proc_close($process);
return [124, $out, $err];
}
usleep(100000);
}
}