205 lines
6.4 KiB
Bash
205 lines
6.4 KiB
Bash
|
|
#!/bin/bash
|
||
|
|
|
||
|
|
# ============================================================
|
||
|
|
# setup.sh - Automated Deployment Script for ATS-Doku
|
||
|
|
# Compatible with Linux environments
|
||
|
|
# ============================================================
|
||
|
|
|
||
|
|
set -e # Exit on error
|
||
|
|
|
||
|
|
# --- Colors ---
|
||
|
|
RED='\033[0;31m'
|
||
|
|
GREEN='\033[0;32m'
|
||
|
|
YELLOW='\033[1;33m'
|
||
|
|
NC='\033[0m'
|
||
|
|
|
||
|
|
log() { echo -e "${GREEN}[INFO]${NC} $1"; }
|
||
|
|
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||
|
|
error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; }
|
||
|
|
|
||
|
|
# --- Configuration ---
|
||
|
|
APP_NAME="ats-doku"
|
||
|
|
APP_USER="ats"
|
||
|
|
APP_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
|
|
VENV_DIR="$APP_DIR/.venv"
|
||
|
|
PYTHON_MIN="3.12"
|
||
|
|
PORT=9000
|
||
|
|
SERVICE_FILE="/etc/systemd/system/${APP_NAME}.service"
|
||
|
|
|
||
|
|
# ============================================================
|
||
|
|
# 1. Root check for system-level operations
|
||
|
|
# ============================================================
|
||
|
|
if [ "$EUID" -ne 0 ]; then
|
||
|
|
error "Please run as root or with sudo: sudo ./setup.sh"
|
||
|
|
fi
|
||
|
|
|
||
|
|
# ============================================================
|
||
|
|
# 2. Check Python version
|
||
|
|
# ============================================================
|
||
|
|
log "Checking Python version..."
|
||
|
|
|
||
|
|
if ! command -v python3 &>/dev/null; then
|
||
|
|
error "Python3 not found. Please install Python $PYTHON_MIN or higher."
|
||
|
|
fi
|
||
|
|
|
||
|
|
PYTHON_VERSION=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')
|
||
|
|
ACTUAL_MAJOR=$(echo "$PYTHON_VERSION" | cut -d. -f1)
|
||
|
|
ACTUAL_MINOR=$(echo "$PYTHON_VERSION" | cut -d. -f2)
|
||
|
|
|
||
|
|
if [ "$ACTUAL_MAJOR" -lt 3 ] || ([ "$ACTUAL_MAJOR" -eq 3 ] && [ "$ACTUAL_MINOR" -lt 12 ]); then
|
||
|
|
error "Python $PYTHON_MIN or higher required. Found: $PYTHON_VERSION"
|
||
|
|
fi
|
||
|
|
|
||
|
|
log "Python $PYTHON_VERSION found ✓"
|
||
|
|
|
||
|
|
# ============================================================
|
||
|
|
# 3. Check system dependencies
|
||
|
|
# ============================================================
|
||
|
|
log "Checking system dependencies..."
|
||
|
|
|
||
|
|
for cmd in pip3 sqlite3; do
|
||
|
|
if ! command -v "$cmd" &>/dev/null; then
|
||
|
|
warn "$cmd not found. Attempting installation..."
|
||
|
|
if command -v apt-get &>/dev/null; then
|
||
|
|
apt-get install -y python3-pip sqlite3
|
||
|
|
elif command -v dnf &>/dev/null; then
|
||
|
|
dnf install -y python3-pip sqlite
|
||
|
|
elif command -v pacman &>/dev/null; then
|
||
|
|
pacman -S --noconfirm python-pip sqlite
|
||
|
|
else
|
||
|
|
error "Package manager not recognized. Please install $cmd manually."
|
||
|
|
fi
|
||
|
|
fi
|
||
|
|
done
|
||
|
|
|
||
|
|
log "System dependencies OK ✓"
|
||
|
|
|
||
|
|
# ============================================================
|
||
|
|
# 4. Create 'ats' system user if not exists
|
||
|
|
# ============================================================
|
||
|
|
log "Checking for system user '$APP_USER'..."
|
||
|
|
|
||
|
|
if id "$APP_USER" &>/dev/null; then
|
||
|
|
warn "User '$APP_USER' already exists. Skipping creation."
|
||
|
|
else
|
||
|
|
log "Creating system user '$APP_USER'..."
|
||
|
|
useradd \
|
||
|
|
--system \
|
||
|
|
--no-create-home \
|
||
|
|
--shell /usr/sbin/nologin \
|
||
|
|
--comment "ATS Doku Service User" \
|
||
|
|
"$APP_USER"
|
||
|
|
log "User '$APP_USER' created ✓"
|
||
|
|
fi
|
||
|
|
|
||
|
|
# ============================================================
|
||
|
|
# 5. Set directory ownership
|
||
|
|
# ============================================================
|
||
|
|
log "Setting ownership of $APP_DIR to '$APP_USER'..."
|
||
|
|
chown -R "$APP_USER":"$APP_USER" "$APP_DIR"
|
||
|
|
log "Ownership set ✓"
|
||
|
|
|
||
|
|
# ============================================================
|
||
|
|
# 6. Create virtual environment
|
||
|
|
# ============================================================
|
||
|
|
log "Creating virtual environment in $VENV_DIR..."
|
||
|
|
|
||
|
|
if [ -d "$VENV_DIR" ]; then
|
||
|
|
warn "Virtual environment already exists. Skipping creation."
|
||
|
|
else
|
||
|
|
python3 -m venv "$VENV_DIR"
|
||
|
|
chown -R "$APP_USER":"$APP_USER" "$VENV_DIR"
|
||
|
|
log "Virtual environment created ✓"
|
||
|
|
fi
|
||
|
|
|
||
|
|
# ============================================================
|
||
|
|
# 7. Install Python dependencies
|
||
|
|
# ============================================================
|
||
|
|
log "Installing Python dependencies..."
|
||
|
|
|
||
|
|
sudo -u "$APP_USER" "$VENV_DIR/bin/pip" install --upgrade pip --quiet
|
||
|
|
|
||
|
|
if [ -f "$APP_DIR/requirements.txt" ]; then
|
||
|
|
sudo -u "$APP_USER" "$VENV_DIR/bin/pip" install -r "$APP_DIR/requirements.txt" --quiet
|
||
|
|
log "requirements.txt installed ✓"
|
||
|
|
else
|
||
|
|
warn "No requirements.txt found. Installing NiceGUI directly..."
|
||
|
|
sudo -u "$APP_USER" "$VENV_DIR/bin/pip" install nicegui --quiet
|
||
|
|
log "NiceGUI installed ✓"
|
||
|
|
fi
|
||
|
|
|
||
|
|
# ============================================================
|
||
|
|
# 8. Ensure data directory exists
|
||
|
|
# ============================================================
|
||
|
|
log "Checking data directory..."
|
||
|
|
|
||
|
|
DATA_DIR="$APP_DIR/data"
|
||
|
|
|
||
|
|
if [ ! -d "$DATA_DIR" ]; then
|
||
|
|
mkdir -p "$DATA_DIR"
|
||
|
|
chown "$APP_USER":"$APP_USER" "$DATA_DIR"
|
||
|
|
log "Directory 'data' created ✓"
|
||
|
|
fi
|
||
|
|
|
||
|
|
DB_FILE="$APP_DIR/ats_doku.db"
|
||
|
|
if [ ! -f "$DB_FILE" ]; then
|
||
|
|
warn "Database file not found. It will be created automatically on first start."
|
||
|
|
else
|
||
|
|
chown "$APP_USER":"$APP_USER" "$DB_FILE"
|
||
|
|
fi
|
||
|
|
|
||
|
|
# ============================================================
|
||
|
|
# 9. Open firewall port (optional)
|
||
|
|
# ============================================================
|
||
|
|
if command -v ufw &>/dev/null; then
|
||
|
|
log "Opening port $PORT in UFW firewall..."
|
||
|
|
ufw allow "$PORT"/tcp &>/dev/null || warn "Could not set UFW rule."
|
||
|
|
fi
|
||
|
|
|
||
|
|
# ============================================================
|
||
|
|
# 10. Create and enable systemd service
|
||
|
|
# ============================================================
|
||
|
|
log "Creating systemd service: $SERVICE_FILE"
|
||
|
|
|
||
|
|
cat > "$SERVICE_FILE" <<EOF
|
||
|
|
[Unit]
|
||
|
|
Description=ATS Traeger Dokumentation (NiceGUI)
|
||
|
|
After=network.target
|
||
|
|
|
||
|
|
[Service]
|
||
|
|
Type=simple
|
||
|
|
User=$APP_USER
|
||
|
|
Group=$APP_USER
|
||
|
|
WorkingDirectory=$APP_DIR
|
||
|
|
ExecStart=$VENV_DIR/bin/python $APP_DIR/main.py
|
||
|
|
Restart=on-failure
|
||
|
|
RestartSec=5
|
||
|
|
Environment=PYTHONUNBUFFERED=1
|
||
|
|
|
||
|
|
# Security hardening
|
||
|
|
NoNewPrivileges=true
|
||
|
|
PrivateTmp=true
|
||
|
|
ProtectSystem=strict
|
||
|
|
ReadWritePaths=$APP_DIR
|
||
|
|
|
||
|
|
[Install]
|
||
|
|
WantedBy=multi-user.target
|
||
|
|
EOF
|
||
|
|
|
||
|
|
systemctl daemon-reload
|
||
|
|
systemctl enable "$APP_NAME"
|
||
|
|
systemctl restart "$APP_NAME"
|
||
|
|
|
||
|
|
log "Service '$APP_NAME' started and enabled ✓"
|
||
|
|
|
||
|
|
# ============================================================
|
||
|
|
# Done
|
||
|
|
# ============================================================
|
||
|
|
echo ""
|
||
|
|
echo -e "${GREEN}============================================${NC}"
|
||
|
|
echo -e "${GREEN} Setup complete!${NC}"
|
||
|
|
echo -e "${GREEN} App available at: http://localhost:$PORT${NC}"
|
||
|
|
echo -e "${GREEN} Service status: sudo systemctl status $APP_NAME${NC}"
|
||
|
|
echo -e "${GREEN} Live logs: sudo journalctl -u $APP_NAME -f${NC}"
|
||
|
|
echo -e "${GREEN}============================================${NC}"
|