module_fn('pi_control', 'table', $name); $notice = null; $error = null; $terminalNotice = null; $terminalError = null; $terminalUrl = null; $terminalToken = null; $settings = modules()->settings('pi_control'); $ttydUrl = trim((string)($settings['ttyd_url'] ?? '/ttyd')); $defaultProvider = 'ttyd'; $defaultTimeout = (int)($settings['exec_default_timeout'] ?? 300); $defaultTimeout = $defaultTimeout > 0 ? $defaultTimeout : 300; $queueName = (string)($settings['redis']['queue'] ?? 'pi_control:queue'); $tokenTtl = (int)($settings['terminal_token_ttl'] ?? 10); $tokenTtl = $tokenTtl > 0 ? $tokenTtl : 10; $hosts = $pdo->query('SELECT * FROM ' . $table('hosts') . ' ORDER BY name ASC')->fetchAll(PDO::FETCH_ASSOC); $commands = $pdo->query('SELECT * FROM ' . $table('commands') . ' ORDER BY label ASC')->fetchAll(PDO::FETCH_ASSOC); if ($_SERVER['REQUEST_METHOD'] === 'POST') { $action = (string)($_POST['action'] ?? ''); if ($action === 'open_console') { $hostId = (int)($_POST['terminal_host_id'] ?? 0); $provider = 'ttyd'; if ($hostId <= 0) { $terminalError = 'Bitte einen Host wählen.'; } elseif ($ttydUrl === '') { $terminalError = 'ttyd URL fehlt. Bitte im Setup setzen.'; } else { $driver = (string)$pdo->getAttribute(PDO::ATTR_DRIVER_NAME); $expiresSql = $driver === 'pgsql' ? "NOW() + INTERVAL '{$tokenTtl} minutes'" : "DATETIME('now', '+{$tokenTtl} minutes')"; $token = bin2hex(random_bytes(24)); $terminalToken = $token; $stmt = $pdo->prepare( 'INSERT INTO ' . $table('sessions') . ' (token, host_id, provider, created_by, expires_at) VALUES (:token, :host_id, :provider, :created_by, ' . $expiresSql . ')' ); $stmt->execute([ 'token' => $token, 'host_id' => $hostId, 'provider' => $provider, 'created_by' => auth_display_name() ?: null, ]); $sep = str_contains($ttydUrl, '?') ? '&' : '?'; $terminalUrl = rtrim($ttydUrl, '/') . '/' . $sep . 'arg=' . rawurlencode($token); } } else { $hostId = (int)($_POST['host_id'] ?? 0); $commandId = (int)($_POST['command_id'] ?? 0); $rawCommand = trim((string)($_POST['command_text'] ?? '')); $timeoutSec = $defaultTimeout; if ($hostId <= 0) { $error = 'Bitte einen Host wählen.'; } elseif ($commandId <= 0 && $rawCommand === '') { $error = 'Bitte einen Befehl wählen oder einen Befehl eingeben.'; } else { $selectedCommand = ''; if ($commandId > 0) { foreach ($commands as $c) { if ((int)$c['id'] === $commandId) { if (!auth_is_admin() && !empty($c['admin_only'])) { $error = 'Dieser Befehl ist nur für Admins.'; } else { $selectedCommand = (string)$c['command']; if (!empty($c['timeout_sec'])) { $timeoutSec = (int)$c['timeout_sec']; } } break; } } } if (!$error) { $commandText = $selectedCommand !== '' ? $selectedCommand : $rawCommand; $driver = (string)$pdo->getAttribute(PDO::ATTR_DRIVER_NAME); if ($driver === 'pgsql') { $stmt = $pdo->prepare( 'INSERT INTO ' . $table('runs') . ' (host_id, command_id, command_text, status, timeout_sec, created_by) VALUES (:host_id, :command_id, :command_text, :status, :timeout_sec, :created_by) RETURNING id' ); $stmt->execute([ 'host_id' => $hostId, 'command_id' => $commandId > 0 ? $commandId : null, 'command_text' => $commandText, 'status' => 'queued', 'timeout_sec' => $timeoutSec, 'created_by' => auth_display_name() ?: null, ]); $runId = (int)$stmt->fetchColumn(); } else { $stmt = $pdo->prepare( 'INSERT INTO ' . $table('runs') . ' (host_id, command_id, command_text, status, timeout_sec, created_by) VALUES (:host_id, :command_id, :command_text, :status, :timeout_sec, :created_by)' ); $stmt->execute([ 'host_id' => $hostId, 'command_id' => $commandId > 0 ? $commandId : null, 'command_text' => $commandText, 'status' => 'queued', 'timeout_sec' => $timeoutSec, 'created_by' => auth_display_name() ?: null, ]); $runId = (int)$pdo->lastInsertId(); } try { $redis = module_fn('pi_control', 'redis'); $payload = json_encode(['run_id' => $runId], JSON_THROW_ON_ERROR); $redis->command(['RPUSH', $queueName, $payload]); $notice = 'Befehl wurde in die Queue gestellt.'; } catch (\Throwable $e) { $pdo->exec('UPDATE ' . $table('runs') . ' SET status = \'queue_error\' WHERE id = ' . (int)$runId); $notice = 'Befehl gespeichert, aber Queue nicht erreichbar.'; } } } } } $runs = $pdo->query( 'SELECT r.*, h.name AS host_name, h.host AS host_addr FROM ' . $table('runs') . ' r LEFT JOIN ' . $table('hosts') . ' h ON h.id = r.host_id ORDER BY r.id DESC LIMIT 20' )->fetchAll(PDO::FETCH_ASSOC); ?>
Wähle einen Host und führe einen Befehl aus.
= e($terminalToken) ?>
Befehle werden über die Queue ausgeführt.
| ID | Status | Host | Command | Von | Output | Timeout |
|---|---|---|---|---|---|---|
| Noch keine Runs. | ||||||
| = e((string)$r['id']) ?> | = e($r['status'] ?? '') ?> | = e($r['host_name'] ?? $r['host_addr'] ?? '') ?> | = e($r['command_text'] ?? '') ?> |
= e($r['created_by'] ?? '') ?> | = e($snippet) ?> |
= !empty($r['timeout_sec']) ? e((string)$r['timeout_sec']) . 's' : 'default' ?> |