deploy
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
<?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 = <<<'SH'
|
||||
if ! command -v apt-get >/dev/null 2>&1; then echo "__ERR__NO_APT"; exit 2; fi;
|
||||
if sudo -n apt update -qq >/dev/null 2>&1; then echo "__APT_UPDATE__=1"; else echo "__APT_UPDATE__=0"; fi;
|
||||
count=$(apt-get -s dist-upgrade 2>/dev/null | grep -c "^Inst ");
|
||||
echo "__COUNT__=$count"
|
||||
SH;
|
||||
$upgradeCmd = <<<'SH'
|
||||
id="$(. /etc/os-release 2>/dev/null && echo "${ID:-}")";
|
||||
current="$(. /etc/os-release 2>/dev/null && echo "${VERSION_CODENAME:-}")";
|
||||
if [ "$id" != "debian" ] || [ -z "$current" ]; then echo "__UPGRADE__=0"; exit 0; fi;
|
||||
latest="$( (command -v curl >/dev/null 2>&1 && curl -fsSL https://deb.debian.org/debian/dists/stable/Release) || (command -v wget >/dev/null 2>&1 && wget -qO- https://deb.debian.org/debian/dists/stable/Release) )";
|
||||
latest="$(printf "%s" "$latest" | awk -F": " "/^Codename:/{print $2}")";
|
||||
if [ -z "$latest" ]; then echo "__UPGRADE__=0"; echo "__RAW__=NO_FETCH"; exit 0; fi;
|
||||
if [ "$current" != "$latest" ]; then echo "__UPGRADE__=1"; else echo "__UPGRADE__=0"; fi
|
||||
SH;
|
||||
|
||||
$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);
|
||||
$updOutStr = (string)$updOut;
|
||||
$updErrStr = (string)$updErr;
|
||||
$updateCount = null;
|
||||
$updatePreview = '';
|
||||
$updateErr = str_contains($updOutStr, '__ERR__NO_APT');
|
||||
if (preg_match('/^__COUNT__=(\d+)$/m', $updOutStr, $m)) {
|
||||
$updateCount = (int)$m[1];
|
||||
}
|
||||
$updatePreview = trim($updOutStr);
|
||||
if (strlen($updatePreview) > 1200) {
|
||||
$updatePreview = substr($updatePreview, 0, 1200);
|
||||
}
|
||||
|
||||
[$upgExit, $upgOut, $upgErr] = runSshCommandCapture($host, $upgradeCmd, $strictHostKey, 25);
|
||||
$upgOutStr = (string)$upgOut;
|
||||
$upgErrStr = (string)$upgErr;
|
||||
$upgradeAvailable = null;
|
||||
$upgradeErr = str_contains($upgOutStr, '__ERR__');
|
||||
if ($upgExit === 0 && !$upgradeErr) {
|
||||
if (preg_match('/^__UPGRADE__=(0|1)$/m', $upgOutStr, $m)) {
|
||||
$upgradeAvailable = $m[1] === '1';
|
||||
}
|
||||
}
|
||||
|
||||
$updErrVal = (!$updateErr && $updateCount !== null) ? null : trim($updErrStr ?: $updOutStr);
|
||||
$upgErrVal = $upgExit === 0 && !$upgradeErr ? null : trim($upgErrStr ?: $upgOutStr);
|
||||
|
||||
$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($upgOutStr) : 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 -o LogLevel=ERROR -o RequestTTY=no';
|
||||
|
||||
$target = escapeshellarg($user . '@' . $hostAddr);
|
||||
$remote = '/bin/sh -c ' . escapeshellarg($command);
|
||||
$cmd = 'ssh -T ' . $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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
set_time_limit(0);
|
||||
|
||||
$root = dirname(__DIR__, 2);
|
||||
chdir($root);
|
||||
$fileload = $root . '/config/fileload.php';
|
||||
if (!file_exists($fileload)) {
|
||||
fwrite(STDERR, "[worker] Missing config: {$fileload}\n");
|
||||
while (true) {
|
||||
sleep(30);
|
||||
}
|
||||
}
|
||||
require $fileload;
|
||||
|
||||
$module = 'pi_control';
|
||||
$pdo = module_fn($module, 'pdo');
|
||||
module_fn($module, 'ensure_schema');
|
||||
$table = fn(string $name) => module_fn($module, 'table', $name);
|
||||
$settingsReloadSec = 30;
|
||||
|
||||
$redis = null;
|
||||
$queueName = 'pi_control:queue';
|
||||
$defaultTimeout = 300;
|
||||
$lastSettingsAt = 0;
|
||||
|
||||
$strictHostKey = getenv('PI_CONTROL_STRICT_HOSTKEY') === '1';
|
||||
|
||||
$driver = (string)$pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
|
||||
$nowExpr = $driver === 'pgsql' ? 'NOW()' : "DATETIME('now')";
|
||||
|
||||
while (true) {
|
||||
if (time() - $lastSettingsAt >= $settingsReloadSec) {
|
||||
$settings = modules()->settings($module);
|
||||
$queueName = (string)($settings['redis']['queue'] ?? ($settings['redis.queue'] ?? (getenv('PI_CONTROL_REDIS_QUEUE') ?: 'pi_control:queue')));
|
||||
$defaultTimeout = (int)($settings['exec_default_timeout'] ?? (getenv('PI_CONTROL_EXEC_DEFAULT_TIMEOUT') !== false ? (int)getenv('PI_CONTROL_EXEC_DEFAULT_TIMEOUT') : 300));
|
||||
$defaultTimeout = $defaultTimeout > 0 ? $defaultTimeout : 300;
|
||||
$settingsReloadSec = (int)($settings['settings_reload_sec'] ?? (getenv('PI_CONTROL_SETTINGS_RELOAD_SEC') !== false ? (int)getenv('PI_CONTROL_SETTINGS_RELOAD_SEC') : 30));
|
||||
$settingsReloadSec = $settingsReloadSec > 0 ? $settingsReloadSec : 30;
|
||||
$strictHostKey = !empty($settings['terminal_strict_hostkey']) || getenv('PI_CONTROL_STRICT_HOSTKEY') === '1';
|
||||
$redis = module_fn($module, 'redis');
|
||||
$lastSettingsAt = time();
|
||||
}
|
||||
|
||||
try {
|
||||
$job = $redis->command(['BLPOP', $queueName, 5]);
|
||||
} catch (\Throwable $e) {
|
||||
fwrite(STDERR, '[worker] Redis error: ' . $e->getMessage() . PHP_EOL);
|
||||
$lastSettingsAt = 0;
|
||||
sleep(5);
|
||||
continue;
|
||||
}
|
||||
if (!$job || !is_array($job) || count($job) < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$payload = (string)$job[1];
|
||||
$data = json_decode($payload, true);
|
||||
if (!is_array($data) || empty($data['run_id'])) {
|
||||
continue;
|
||||
}
|
||||
$runId = (int)$data['run_id'];
|
||||
|
||||
try {
|
||||
$runStmt = $pdo->prepare('SELECT * FROM ' . $table('runs') . ' WHERE id = :id LIMIT 1');
|
||||
$runStmt->execute(['id' => $runId]);
|
||||
$run = $runStmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (!$run || ($run['status'] ?? '') !== 'queued') {
|
||||
continue;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
fwrite(STDERR, '[worker] DB error: ' . $e->getMessage() . PHP_EOL);
|
||||
sleep(2);
|
||||
continue;
|
||||
}
|
||||
|
||||
$hostId = (int)($run['host_id'] ?? 0);
|
||||
if ($hostId <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$timeoutSec = (int)($run['timeout_sec'] ?? 0);
|
||||
$timeoutSec = $timeoutSec > 0 ? $timeoutSec : $defaultTimeout;
|
||||
$lockTtl = max($timeoutSec + 60, 120);
|
||||
|
||||
$lockKey = 'pi_control:lock:host:' . $hostId;
|
||||
try {
|
||||
$lockOk = $redis->command(['SET', $lockKey, (string)$runId, 'NX', 'EX', (string)$lockTtl]);
|
||||
} catch (\Throwable $e) {
|
||||
fwrite(STDERR, '[worker] Redis lock error: ' . $e->getMessage() . PHP_EOL);
|
||||
$lastSettingsAt = 0;
|
||||
sleep(2);
|
||||
continue;
|
||||
}
|
||||
if ($lockOk !== 'OK') {
|
||||
try {
|
||||
$redis->command(['RPUSH', $queueName, $payload]);
|
||||
} catch (\Throwable $e) {
|
||||
fwrite(STDERR, '[worker] Redis requeue error: ' . $e->getMessage() . PHP_EOL);
|
||||
$lastSettingsAt = 0;
|
||||
}
|
||||
usleep(250000);
|
||||
continue;
|
||||
}
|
||||
|
||||
$pdo->exec('UPDATE ' . $table('runs') . ' SET status = \'running\', started_at = ' . $nowExpr . ' WHERE id = ' . (int)$runId);
|
||||
|
||||
$hostStmt = $pdo->prepare('SELECT * FROM ' . $table('hosts') . ' WHERE id = :id LIMIT 1');
|
||||
$hostStmt->execute(['id' => $hostId]);
|
||||
$host = $hostStmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$host) {
|
||||
$pdo->exec('UPDATE ' . $table('runs') . ' SET status = \'failed\', error = \'Host not found\', finished_at = ' . $nowExpr . ' WHERE id = ' . (int)$runId);
|
||||
try {
|
||||
$redis->command(['DEL', $lockKey]);
|
||||
} catch (\Throwable $e) {
|
||||
fwrite(STDERR, '[worker] Redis unlock error: ' . $e->getMessage() . PHP_EOL);
|
||||
$lastSettingsAt = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$commandText = (string)($run['command_text'] ?? '');
|
||||
[$status, $exitCode, $output, $error] = executeSsh($host, $commandText, $timeoutSec, $strictHostKey);
|
||||
|
||||
$output = truncateText($output, 20000);
|
||||
$error = truncateText($error, 20000);
|
||||
|
||||
$stmt = $pdo->prepare(
|
||||
'UPDATE ' . $table('runs') . ' SET status = :status, output = :output, error = :error, exit_code = :exit_code, finished_at = ' . $nowExpr . ' WHERE id = :id'
|
||||
);
|
||||
$stmt->execute([
|
||||
'status' => $status,
|
||||
'output' => $output !== '' ? $output : null,
|
||||
'error' => $error !== '' ? $error : null,
|
||||
'exit_code' => $exitCode,
|
||||
'id' => $runId,
|
||||
]);
|
||||
|
||||
try {
|
||||
$redis->command(['DEL', $lockKey]);
|
||||
} catch (\Throwable $e) {
|
||||
fwrite(STDERR, '[worker] Redis unlock error: ' . $e->getMessage() . PHP_EOL);
|
||||
$lastSettingsAt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function executeSsh(array $host, string $command, int $timeoutSec, bool $strictHostKey): 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';
|
||||
|
||||
$target = escapeshellarg($user . '@' . $hostAddr);
|
||||
$remoteCmd = escapeshellarg($command);
|
||||
|
||||
$cmd = 'ssh ' . $opts . ' -p ' . (int)$port . ' ';
|
||||
if ($authType === 'key' && $keyPath !== '') {
|
||||
$cmd .= '-i ' . escapeshellarg($keyPath) . ' ';
|
||||
}
|
||||
$cmd .= $target . ' -- ' . $remoteCmd;
|
||||
|
||||
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 ['failed', 255, '', 'proc_open failed'];
|
||||
}
|
||||
|
||||
stream_set_blocking($pipes[1], false);
|
||||
stream_set_blocking($pipes[2], false);
|
||||
|
||||
$output = '';
|
||||
$error = '';
|
||||
$start = time();
|
||||
|
||||
while (true) {
|
||||
$status = proc_get_status($process);
|
||||
$output .= stream_get_contents($pipes[1]);
|
||||
$error .= stream_get_contents($pipes[2]);
|
||||
|
||||
if (!$status['running']) {
|
||||
$exitCode = (int)$status['exitcode'];
|
||||
proc_close($process);
|
||||
$finalStatus = $exitCode === 0 ? 'success' : 'failed';
|
||||
return [$finalStatus, $exitCode, $output, $error];
|
||||
}
|
||||
|
||||
if (time() - $start > $timeoutSec) {
|
||||
proc_terminate($process, 9);
|
||||
proc_close($process);
|
||||
return ['timeout', 124, $output, $error];
|
||||
}
|
||||
|
||||
usleep(100000);
|
||||
}
|
||||
}
|
||||
|
||||
function truncateText(string $text, int $limit): string
|
||||
{
|
||||
if (strlen($text) <= $limit) {
|
||||
return $text;
|
||||
}
|
||||
return substr($text, 0, $limit) . "\n...truncated...";
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
TOKEN="${1:-}"
|
||||
ENC_COMMAND="${2:-}"
|
||||
if [[ -z "${TOKEN}" ]]; then
|
||||
echo "Missing token."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
API_BASE="${PI_CONTROL_API_URL:-http://gui_nexus}"
|
||||
API_BASE="${API_BASE%/}"
|
||||
INFO_URL="${API_BASE}/module/pi_control/terminal_info?token=${TOKEN}"
|
||||
|
||||
if [[ -n "${PI_CONTROL_SHARED_SECRET:-}" ]]; then
|
||||
AUTH_HEADER=(-H "X-Terminal-Secret: ${PI_CONTROL_SHARED_SECRET}")
|
||||
else
|
||||
AUTH_HEADER=()
|
||||
fi
|
||||
|
||||
JSON="$(curl -sS "${AUTH_HEADER[@]}" "${INFO_URL}")"
|
||||
OK="$(echo "${JSON}" | jq -r '.ok')"
|
||||
if [[ "${OK}" != "true" ]]; then
|
||||
echo "Invalid or expired token."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
HOST="$(echo "${JSON}" | jq -r '.host.host')"
|
||||
PORT="$(echo "${JSON}" | jq -r '.host.port')"
|
||||
USER="$(echo "${JSON}" | jq -r '.host.username')"
|
||||
AUTH_TYPE="$(echo "${JSON}" | jq -r '.host.auth_type')"
|
||||
KEY_PATH="$(echo "${JSON}" | jq -r '.host.key_path')"
|
||||
PASSWORD="$(echo "${JSON}" | jq -r '.host.password')"
|
||||
STRICT_HOSTKEY="$(echo "${JSON}" | jq -r '.strict_hostkey // false')"
|
||||
TMUX_SESSION_JSON="$(echo "${JSON}" | jq -r '.tmux_session // ""')"
|
||||
|
||||
COMMAND="$(echo "${JSON}" | jq -r '.command // ""')"
|
||||
if [[ -z "${COMMAND}" && -n "${ENC_COMMAND}" ]]; then
|
||||
COMMAND="$(printf '%s' "${ENC_COMMAND}" | base64 -d 2>/dev/null || true)"
|
||||
fi
|
||||
|
||||
if [[ -z "${HOST}" || -z "${USER}" ]]; then
|
||||
echo "Host data incomplete."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SSH_OPTS=()
|
||||
if [[ "${STRICT_HOSTKEY}" == "true" || "${PI_CONTROL_STRICT_HOSTKEY:-}" == "1" ]]; then
|
||||
SSH_OPTS=(-o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=/root/.ssh/known_hosts)
|
||||
else
|
||||
SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null)
|
||||
fi
|
||||
|
||||
SSH_TARGET="${USER}@${HOST}"
|
||||
TMUX_SESSION="${TMUX_SESSION_JSON:-}"
|
||||
if [[ -z "${TMUX_SESSION}" ]]; then
|
||||
TMUX_SESSION="${PI_CONTROL_TMUX_SESSION:-nexus}"
|
||||
fi
|
||||
if [[ -n "${COMMAND}" ]]; then
|
||||
COMMAND_B64="$(printf '%s' "${COMMAND}" | base64)"
|
||||
REMOTE_CMD="CMD_B64='${COMMAND_B64}'; CMD=\"\$(printf '%s' \"\$CMD_B64\" | base64 -d)\"; if command -v tmux >/dev/null 2>&1; then SESSION=\"${TMUX_SESSION}\"; tmux has-session -t \"\$SESSION\" 2>/dev/null || tmux new-session -d -s \"\$SESSION\"; tmux send-keys -t \"\$SESSION\" \"\$CMD\" C-m; exec tmux attach -t \"\$SESSION\"; else eval \"\$CMD\"; exec /bin/bash -il; fi"
|
||||
REMOTE_CMD_Q=$(printf "%s" "$REMOTE_CMD" | sed "s/'/'\\\\''/g")
|
||||
if [[ "${AUTH_TYPE}" == "key" && -n "${KEY_PATH}" ]]; then
|
||||
ssh "${SSH_OPTS[@]}" -i "${KEY_PATH}" -p "${PORT:-22}" -tt "${SSH_TARGET}" -- /bin/bash -lc "'${REMOTE_CMD_Q}'" || \
|
||||
ssh "${SSH_OPTS[@]}" -i "${KEY_PATH}" -p "${PORT:-22}" -tt "${SSH_TARGET}" -- /bin/sh -lc "'${REMOTE_CMD_Q}'"
|
||||
elif [[ "${AUTH_TYPE}" == "pass" && -n "${PASSWORD}" ]]; then
|
||||
sshpass -p "${PASSWORD}" ssh "${SSH_OPTS[@]}" -p "${PORT:-22}" -tt "${SSH_TARGET}" -- /bin/bash -lc "'${REMOTE_CMD_Q}'" || \
|
||||
sshpass -p "${PASSWORD}" ssh "${SSH_OPTS[@]}" -p "${PORT:-22}" -tt "${SSH_TARGET}" -- /bin/sh -lc "'${REMOTE_CMD_Q}'"
|
||||
else
|
||||
ssh "${SSH_OPTS[@]}" -p "${PORT:-22}" -tt "${SSH_TARGET}" -- /bin/bash -lc "'${REMOTE_CMD_Q}'" || \
|
||||
ssh "${SSH_OPTS[@]}" -p "${PORT:-22}" -tt "${SSH_TARGET}" -- /bin/sh -lc "'${REMOTE_CMD_Q}'"
|
||||
fi
|
||||
exit $?
|
||||
else
|
||||
REMOTE_CMD="if command -v tmux >/dev/null 2>&1; then exec tmux new -A -s \"${TMUX_SESSION}\"; else exec /bin/bash -il; fi"
|
||||
REMOTE_CMD_Q=$(printf "%s" "$REMOTE_CMD" | sed "s/'/'\\\\''/g")
|
||||
if [[ "${AUTH_TYPE}" == "key" && -n "${KEY_PATH}" ]]; then
|
||||
exec ssh "${SSH_OPTS[@]}" -i "${KEY_PATH}" -p "${PORT:-22}" -tt "${SSH_TARGET}" -- /bin/bash -lc "'${REMOTE_CMD_Q}'" || \
|
||||
exec ssh "${SSH_OPTS[@]}" -i "${KEY_PATH}" -p "${PORT:-22}" -tt "${SSH_TARGET}" -- /bin/sh -lc "'${REMOTE_CMD_Q}'"
|
||||
elif [[ "${AUTH_TYPE}" == "pass" && -n "${PASSWORD}" ]]; then
|
||||
exec sshpass -p "${PASSWORD}" ssh "${SSH_OPTS[@]}" -p "${PORT:-22}" -tt "${SSH_TARGET}" -- /bin/bash -lc "'${REMOTE_CMD_Q}'" || \
|
||||
exec sshpass -p "${PASSWORD}" ssh "${SSH_OPTS[@]}" -p "${PORT:-22}" -tt "${SSH_TARGET}" -- /bin/sh -lc "'${REMOTE_CMD_Q}'"
|
||||
else
|
||||
exec ssh "${SSH_OPTS[@]}" -p "${PORT:-22}" -tt "${SSH_TARGET}" -- /bin/bash -lc "'${REMOTE_CMD_Q}'" || \
|
||||
exec ssh "${SSH_OPTS[@]}" -p "${PORT:-22}" -tt "${SSH_TARGET}" -- /bin/sh -lc "'${REMOTE_CMD_Q}'"
|
||||
fi
|
||||
fi
|
||||
@@ -0,0 +1,17 @@
|
||||
FROM alpine:3.20
|
||||
|
||||
RUN apk add --no-cache \
|
||||
ttyd \
|
||||
bash \
|
||||
openssh-client \
|
||||
curl \
|
||||
jq \
|
||||
sshpass
|
||||
|
||||
WORKDIR /app
|
||||
COPY tools/pi_control/terminal_entry.sh /app/tools/pi_control/terminal_entry.sh
|
||||
RUN chmod +x /app/tools/pi_control/terminal_entry.sh
|
||||
|
||||
EXPOSE 7681
|
||||
|
||||
ENTRYPOINT ["ttyd", "--url-arg", "--base-path", "/ttyd", "/app/tools/pi_control/terminal_entry.sh"]
|
||||
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env sh
|
||||
set -eu
|
||||
|
||||
APP_ENV="${APP_ENV:-staging}"
|
||||
|
||||
if [ "$APP_ENV" = "live" ]; then
|
||||
SCRIPT="/app/live/tools/pi_control/terminal_entry.sh"
|
||||
else
|
||||
SCRIPT="/app/staging/tools/pi_control/terminal_entry.sh"
|
||||
fi
|
||||
|
||||
if [ ! -f "$SCRIPT" ]; then
|
||||
echo "terminal_entry.sh not found at $SCRIPT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec ttyd --writable --url-arg "$SCRIPT"
|
||||
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env sh
|
||||
set -eu
|
||||
|
||||
APP_ENV="${APP_ENV:-staging}"
|
||||
|
||||
if [ "$APP_ENV" = "live" ]; then
|
||||
# NOTE: Renamed from worker.php due to CIFS/SMB invalid argument errors on rename/open.
|
||||
SCRIPT="/app/live/tools/pi_control/pi_worker.php"
|
||||
else
|
||||
# NOTE: Renamed from worker.php due to CIFS/SMB invalid argument errors on rename/open.
|
||||
SCRIPT="/app/staging/tools/pi_control/pi_worker.php"
|
||||
fi
|
||||
|
||||
if [ ! -f "$SCRIPT" ]; then
|
||||
echo "pi_worker.php not found at $SCRIPT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec php "$SCRIPT"
|
||||
Reference in New Issue
Block a user