Files
arm/install.sh
toros 49b6cf89f4 feat(webui): режим console (только RS232-консоль, питание отключено)
- ATXPI_MODE=console: /api/power/* → 403, кнопки питания скрыты в UI
- /api/status отдаёт mode; env-шаблон и install.sh учитывают ATXPI_MODE
- нужно для безопасного запуска панели на серверах-«управленцах» без риска питания
2026-09-08 23:34:23 +05:00

138 lines
8.1 KiB
Bash
Executable File

#!/bin/bash
# ─────────────────────────────────────────────────────────────────────────────
# atxpi — one-shot installer. Идемпотентный: повторные запуски обновляют репо
# и перезапускают сервис.
#
# # 1) из чекаута репозитория:
# sudo bash install.sh
#
# # 2) curl-установка (публичное репо). URL укажи через ATXPI_GIT_REPO:
# curl -s <repo>/raw/branch/main/install.sh | sudo ATXPI_GIT_REPO=<repo> bash
#
# # 3) закрытое репо — добавь токен:
# curl -s <repo>/raw/branch/main/install.sh \
# | sudo ATXPI_GIT_REPO=<repo> ATXPI_GIT_TOKEN=<tok> bash
#
# Хост репозитория в код не зашит — передаётся через ATXPI_GIT_REPO.
# ─────────────────────────────────────────────────────────────────────────────
set -euo pipefail
# ── конфигурация (переопределяется через env) ───────────────────────────────
ATXPI_TARGET="${ATXPI_TARGET:-/opt/arm}" # куда кладём чекаут репо
ATXPI_USER="${ATXPI_USER:-atxpi}" # системный юзер сервиса
ATXPI_BRANCH="${ATXPI_BRANCH:-main}"
ATXPI_GIT_REPO="${ATXPI_GIT_REPO:-}" # URL репо (для свежего клона обязателен)
ATXPI_GIT_TOKEN="${ATXPI_GIT_TOKEN:-}" # токен для закрытого репо (иначе пусто)
ATXPI_BIND_HOST="${ATXPI_BIND_HOST:-0.0.0.0}" # ⚠️ ограничь до VPN/LAN (см. безопасность)
ATXPI_BIND_PORT="${ATXPI_BIND_PORT:-8443}"
ATXPI_SERIAL="${ATXPI_SERIAL:-/dev/ttyUSB0}"
ATXPI_BAUD="${ATXPI_BAUD:-115200}"
ATXPI_DRIVER="${ATXPI_DRIVER:-real}"
ATXPI_MODE="${ATXPI_MODE:-full}"
log() { echo -e "\e[1;32m[atxpi]\e[0m $*"; }
err() { echo -e "\e[1;31m[atxpi]\e[0m $*" >&2; }
# ── 0. root ──────────────────────────────────────────────────────────────────
if [ "$(id -u)" -ne 0 ]; then
err "Запускай через sudo (или sudo -E для варианта с env-переменными)."
exit 1
fi
# ── 1. системные зависимости ─────────────────────────────────────────────────
log "Устанавливаю системные зависимости (git, curl, python3-venv)..."
export DEBIAN_FRONTEND=noninteractive
apt-get update -y
apt-get install -y git curl ca-certificates python3-venv python3-pip
# ── 2. сервисный пользователь + доступ к железу ──────────────────────────────
if ! id "$ATXPI_USER" >/dev/null 2>&1; then
log "Создаю сервисного пользователя '$ATXPI_USER'..."
useradd --system --create-home --shell /usr/sbin/nologin "$ATXPI_USER"
fi
# I2C (expander-хат в atxctl) и dialout (ttyUSB0 — консоль)
usermod -aG i2c,dialout "$ATXPI_USER" 2>/dev/null || true
# ── 3. клонирование / обновление репо ────────────────────────────────────────
if [ -d "$ATXPI_TARGET/.git" ]; then
log "Репозиторий уже есть: обновляю $ATXPI_TARGET..."
ATXPI_GIT_REPO="${ATXPI_GIT_REPO:-$(git -C "$ATXPI_TARGET" remote get-url origin 2>/dev/null || true)}"
git -C "$ATXPI_TARGET" fetch origin "$ATXPI_BRANCH" || true
git -C "$ATXPI_TARGET" reset --hard "origin/$ATXPI_BRANCH" || true
else
if [ -z "$ATXPI_GIT_REPO" ]; then
err "Укажи ATXPI_GIT_REPO (URL репозитория) для первого клона."
exit 1
fi
log "Клонирую репозиторий в $ATXPI_TARGET..."
if [ -n "$ATXPI_GIT_TOKEN" ]; then
git -c http.extraHeader="Authorization: token $ATXPI_GIT_TOKEN" \
clone -q -b "$ATXPI_BRANCH" "$ATXPI_GIT_REPO" "$ATXPI_TARGET"
# сохранить креды для будущих `git pull` (не оставляя токен в remote URL)
host="$(printf '%s' "$ATXPI_GIT_REPO" \
| sed -E 's#^[a-zA-Z]+://##; s#.*@##; s#^git@##; s#[:/].*$##')"
printf 'protocol=https\nhost=%s\nusername=oauth2\npassword=%s\n\n' \
"$host" "$ATXPI_GIT_TOKEN" | git credential approve || true
else
git clone -q -b "$ATXPI_BRANCH" "$ATXPI_GIT_REPO" "$ATXPI_TARGET"
fi
fi
APP_DIR="$ATXPI_TARGET/atxpi"
# ── 4. venv + зависимости ────────────────────────────────────────────────────
log "Ставлю зависимости в venv..."
VENV="$APP_DIR/venv"
[ -d "$VENV" ] || python3 -m venv "$VENV"
"$VENV/bin/pip" install --upgrade pip >/dev/null
"$VENV/bin/pip" install -q -r "$APP_DIR/requirements.txt"
chown -R "$ATXPI_USER":"$ATXPI_USER" "$VENV"
chown -R "$ATXPI_USER":"$ATXPI_USER" "$APP_DIR" # владелец приложения — сервис-юзер (pyc/tmp/audit)
chown "$ATXPI_USER":"$ATXPI_USER" /etc/atxpi # для /api/history (audit.jsonl внутри)
# ── 5. конфигурация / секреты (generated, НЕ в git) ──────────────────────────
ENV_FILE=/etc/atxpi/atxpi.env
if [ ! -f "$ENV_FILE" ]; then
log "Создаю ${ENV_FILE}..."
mkdir -p /etc/atxpi
cat > "$ENV_FILE" <<EOF
# atxpi — локальная конфигурация (создаётся install.sh, НЕ хранится в git)
# ATXPI_DRIVER: real | mock
ATXPI_DRIVER=$ATXPI_DRIVER
# Режим: full | console (в console питание отключено)
ATXPI_MODE=$ATXPI_MODE
SERIAL_PORT=$ATXPI_SERIAL
SERIAL_BAUD=$ATXPI_BAUD
# токен для REST-API и браузера (генерируется при установке)
ATXPI_WEB_TOKEN=$(python3 -c "import secrets;print(secrets.token_hex(32))")
EOF
chmod 600 "$ENV_FILE"
chown "$ATXPI_USER":"$ATXPI_USER" "$ENV_FILE"
fi
# ── 6. systemd-юнит ──────────────────────────────────────────────────────────
log "Разворачиваю systemd-юнит..."
sed "s|@USER@|$ATXPI_USER|g; s|@TARGET@|$ATXPI_TARGET|g; s|@BIND_HOST@|$ATXPI_BIND_HOST|g; s|@BIND_PORT@|$ATXPI_BIND_PORT|g" \
"$APP_DIR/deploy/systemd/atxpi.service" > /etc/systemd/system/atxpi.service
systemctl daemon-reload
# ── 7. старт ─────────────────────────────────────────────────────────────────
if [ -f "$APP_DIR/webui/server.py" ]; then
log "Веб-приложение на месте: включаю и запускаю сервис."
systemctl enable atxpi.service >/dev/null 2>&1 || true
systemctl restart atxpi.service || true
else
log "Веб-приложение (atxpi/webui/server.py) ещё не готово — юнит установлен, но не запущен."
log "Запуск после появления webui/server.py (шаг ③)."
fi
echo
log "Готово. Сводка:"
echo " Репозиторий : $ATXPI_TARGET"
echo " Пользователь: $ATXPI_USER (группы: $(id -nG "$ATXPI_USER" 2>/dev/null | sed 's/ /,/g'))"
echo " venv : $APP_DIR/venv"
echo " Конфиг : $ENV_FILE (0600)"
echo " Юнит : atxpi.service (bind ${ATXPI_BIND_HOST}:${ATXPI_BIND_PORT})"
[ -f "$APP_DIR/webui/server.py" ] && echo " Статус : $(systemctl is-active atxpi.service 2>/dev/null || echo unknown)"