361 lines
12 KiB
Bash
361 lines
12 KiB
Bash
#!/bin/bash
|
||
|
||
# ===================================================================
|
||
# MYP Druckerverwaltung - Installer für Raspbian Kiosk-System
|
||
# Entwickelt auf Windows, ausführbar auf Raspberry Pi / Debian
|
||
# OHNE virtualenv - verwendet System-Python mit --break-system-packages
|
||
# ===================================================================
|
||
|
||
set -euo pipefail
|
||
|
||
# =========================== KONFIGURATION ===========================
|
||
APP_NAME="MYP Druckerverwaltung"
|
||
APP_DIR="/opt/myp"
|
||
SERVICE_NAME="myp-kiosk"
|
||
CURRENT_DIR="$(pwd)"
|
||
INSTALL_LOG="/var/log/myp-install.log"
|
||
|
||
# Farben für Ausgabe
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
PURPLE='\033[0;35m'
|
||
NC='\033[0m'
|
||
|
||
# ========================== LOGGING-SYSTEM ==========================
|
||
log() {
|
||
echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')] $1${NC}" | tee -a "$INSTALL_LOG"
|
||
}
|
||
|
||
error() {
|
||
echo -e "${RED}[FEHLER] $1${NC}" | tee -a "$INSTALL_LOG"
|
||
exit 1
|
||
}
|
||
|
||
warning() {
|
||
echo -e "${YELLOW}[WARNUNG] $1${NC}" | tee -a "$INSTALL_LOG"
|
||
}
|
||
|
||
info() {
|
||
echo -e "${BLUE}[INFO] $1${NC}" | tee -a "$INSTALL_LOG"
|
||
}
|
||
|
||
progress() {
|
||
echo -e "${PURPLE}[FORTSCHRITT] $1${NC}" | tee -a "$INSTALL_LOG"
|
||
}
|
||
|
||
# ========================== SYSTEM-CHECKS ==========================
|
||
check_root() {
|
||
if [ "$EUID" -ne 0 ]; then
|
||
error "Dieses Skript muss als Root ausgeführt werden: sudo $0"
|
||
fi
|
||
export PATH="/usr/sbin:/sbin:/usr/bin:/bin:/usr/local/bin:$PATH"
|
||
}
|
||
|
||
check_debian_system() {
|
||
if [ ! -f /etc/debian_version ]; then
|
||
error "Dieses Skript ist nur für Debian/Raspbian-Systeme geeignet!"
|
||
fi
|
||
log "✅ Debian/Raspbian-System erkannt"
|
||
}
|
||
|
||
# ========================== ABHÄNGIGKEITEN INSTALLIEREN ==========================
|
||
install_system_dependencies() {
|
||
log "=== INSTALLIERE SYSTEM-ABHÄNGIGKEITEN ==="
|
||
|
||
progress "Aktualisiere Paketlisten..."
|
||
apt-get update -y || error "APT Update fehlgeschlagen"
|
||
|
||
progress "Installiere Python 3 und grundlegende Pakete..."
|
||
apt-get install -y \
|
||
python3 \
|
||
python3-pip \
|
||
python3-dev \
|
||
python3-setuptools \
|
||
build-essential \
|
||
libssl-dev \
|
||
libffi-dev \
|
||
git \
|
||
curl \
|
||
wget \
|
||
nano \
|
||
htop \
|
||
rsync \
|
||
unzip \
|
||
sudo \
|
||
systemd \
|
||
ca-certificates \
|
||
gnupg \
|
||
lsb-release \
|
||
sqlite3 \
|
||
|| error "System-Pakete Installation fehlgeschlagen"
|
||
|
||
progress "Installiere Python-Abhängigkeiten mit --break-system-packages..."
|
||
|
||
# Core Flask Framework
|
||
pip3 install --break-system-packages Flask==3.1.1 || error "Flask Installation fehlgeschlagen"
|
||
pip3 install --break-system-packages Flask-Login==0.6.3 || error "Flask-Login Installation fehlgeschlagen"
|
||
pip3 install --break-system-packages Flask-WTF==1.2.1 || error "Flask-WTF Installation fehlgeschlagen"
|
||
|
||
# Datenbank
|
||
pip3 install --break-system-packages SQLAlchemy==2.0.36 || error "SQLAlchemy Installation fehlgeschlagen"
|
||
|
||
# Sicherheit
|
||
pip3 install --break-system-packages bcrypt==4.2.1 || error "bcrypt Installation fehlgeschlagen"
|
||
pip3 install --break-system-packages cryptography==44.0.0 || error "cryptography Installation fehlgeschlagen"
|
||
pip3 install --break-system-packages Werkzeug==3.1.3 || error "Werkzeug Installation fehlgeschlagen"
|
||
|
||
# Smart Plug Steuerung
|
||
pip3 install --break-system-packages PyP100 || warning "PyP100 Installation fehlgeschlagen (optional)"
|
||
|
||
# HTTP Requests
|
||
pip3 install --break-system-packages requests==2.32.3 || error "requests Installation fehlgeschlagen"
|
||
|
||
# System Monitoring
|
||
pip3 install --break-system-packages psutil==6.1.1 || error "psutil Installation fehlgeschlagen"
|
||
|
||
# Redis (optional)
|
||
pip3 install --break-system-packages redis==5.2.1 || warning "redis Installation fehlgeschlagen (optional)"
|
||
|
||
# Weitere Core-Abhängigkeiten
|
||
pip3 install --break-system-packages MarkupSafe==3.0.2 || error "MarkupSafe Installation fehlgeschlagen"
|
||
|
||
# Produktions-Server
|
||
pip3 install --break-system-packages gunicorn==23.0.0 || error "gunicorn Installation fehlgeschlagen"
|
||
|
||
log "✅ Alle Abhängigkeiten erfolgreich installiert"
|
||
}
|
||
|
||
# ========================== PRODUKTIONS-KIOSK SETUP ==========================
|
||
setup_production_kiosk() {
|
||
log "=== RICHTE PRODUKTIONS-KIOSK-MODUS EIN ==="
|
||
|
||
# Zuerst Abhängigkeiten installieren
|
||
install_system_dependencies
|
||
|
||
progress "Erstelle Zielverzeichnis /opt/myp..."
|
||
mkdir -p "$APP_DIR" || error "Konnte Zielverzeichnis nicht erstellen"
|
||
|
||
progress "Kopiere Projektdateien selektiv nach $APP_DIR..."
|
||
|
||
# Liste der zu kopierenden Dateien/Ordner (ohne unnötige Inhalte)
|
||
declare -a COPY_ITEMS=(
|
||
"app.py"
|
||
"models.py"
|
||
"requirements.txt"
|
||
"blueprints/"
|
||
"config/"
|
||
"database/"
|
||
"docs/"
|
||
"static/"
|
||
"templates/"
|
||
"uploads/"
|
||
"utils/"
|
||
"logs/"
|
||
"certs/"
|
||
)
|
||
|
||
# Sichere selektive Kopie
|
||
for item in "${COPY_ITEMS[@]}"; do
|
||
if [ -e "$CURRENT_DIR/$item" ]; then
|
||
progress "Kopiere: $item"
|
||
cp -r "$CURRENT_DIR/$item" "$APP_DIR/" || warning "Fehler beim Kopieren von $item"
|
||
else
|
||
info "Überspringe nicht vorhandenes Element: $item"
|
||
fi
|
||
done
|
||
|
||
# Spezielle Dateien einzeln kopieren (falls vorhanden)
|
||
for file in "package.json" "package-lock.json" "tailwind.config.js" "postcss.config.js"; do
|
||
if [ -f "$CURRENT_DIR/$file" ]; then
|
||
cp "$CURRENT_DIR/$file" "$APP_DIR/" || warning "Fehler beim Kopieren von $file"
|
||
fi
|
||
done
|
||
|
||
# Stelle sicher, dass app.py ausführbar ist
|
||
chmod +x "$APP_DIR/app.py" || error "Konnte app.py nicht ausführbar machen"
|
||
|
||
# Erstelle notwendige Verzeichnisse falls sie nicht existieren
|
||
mkdir -p "$APP_DIR/database/backups"
|
||
mkdir -p "$APP_DIR/logs/app"
|
||
mkdir -p "$APP_DIR/logs/auth"
|
||
mkdir -p "$APP_DIR/logs/errors"
|
||
mkdir -p "$APP_DIR/uploads/temp"
|
||
|
||
# Berechtigungen setzen
|
||
chown -R root:root "$APP_DIR"
|
||
chmod -R 755 "$APP_DIR"
|
||
chmod 750 "$APP_DIR/database"
|
||
chmod 750 "$APP_DIR/logs"
|
||
chmod 755 "$APP_DIR/uploads"
|
||
|
||
progress "Erstelle Systemd-Service myp-kiosk.service..."
|
||
cat > "/etc/systemd/system/${SERVICE_NAME}.service" << EOF
|
||
[Unit]
|
||
Description=MYP Druckerverwaltung Kiosk-Modus
|
||
After=network.target network-online.target
|
||
Wants=network-online.target
|
||
Requires=network.target
|
||
|
||
[Service]
|
||
Type=simple
|
||
User=root
|
||
Group=root
|
||
WorkingDirectory=$APP_DIR
|
||
ExecStart=/usr/bin/python3 $APP_DIR/app.py --debug
|
||
Restart=always
|
||
RestartSec=5
|
||
StartLimitBurst=5
|
||
StartLimitInterval=60
|
||
|
||
# Umgebungsvariablen
|
||
Environment=PYTHONUNBUFFERED=1
|
||
Environment=FLASK_ENV=production
|
||
Environment=FLASK_HOST=0.0.0.0
|
||
Environment=FLASK_PORT=5000
|
||
Environment=PYTHONPATH=$APP_DIR
|
||
Environment=LC_ALL=C.UTF-8
|
||
Environment=LANG=C.UTF-8
|
||
|
||
# Logging
|
||
StandardOutput=journal
|
||
StandardError=journal
|
||
SyslogIdentifier=myp-kiosk
|
||
|
||
# Security-Einstellungen
|
||
NoNewPrivileges=true
|
||
PrivateTmp=false
|
||
ProtectSystem=strict
|
||
ReadWritePaths=$APP_DIR
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
EOF
|
||
|
||
progress "Lade Systemd-Konfiguration neu..."
|
||
systemctl daemon-reload || error "Systemd Reload fehlgeschlagen"
|
||
|
||
progress "Aktiviere und starte $SERVICE_NAME Service..."
|
||
systemctl enable "$SERVICE_NAME.service" || error "Service Enable fehlgeschlagen"
|
||
systemctl start "$SERVICE_NAME.service" || error "Service Start fehlgeschlagen"
|
||
|
||
# Service-Status prüfen
|
||
sleep 5
|
||
if systemctl is-active --quiet "$SERVICE_NAME.service"; then
|
||
log "✅ $SERVICE_NAME Service läuft erfolgreich"
|
||
info "Service-Status: $(systemctl is-active $SERVICE_NAME.service)"
|
||
info "Port 5000: Flask-App läuft im Debug-Modus"
|
||
info "Projektverzeichnis: $APP_DIR"
|
||
|
||
# Test der Anwendung
|
||
progress "Teste Anwendungserreichbarkeit..."
|
||
sleep 3
|
||
if curl -s http://localhost:5000 > /dev/null 2>&1; then
|
||
log "✅ Anwendung ist unter http://localhost:5000 erreichbar"
|
||
else
|
||
warning "⚠️ Anwendung noch nicht erreichbar (möglicherweise noch beim Starten)"
|
||
fi
|
||
else
|
||
error "$SERVICE_NAME Service konnte nicht gestartet werden - prüfen Sie die Logs: journalctl -u $SERVICE_NAME -f"
|
||
fi
|
||
|
||
log "✅ Produktions-Kiosk-Modus erfolgreich eingerichtet"
|
||
log "🎯 Anwendung erreichbar unter: http://localhost:5000"
|
||
log "📋 Service-Befehle:"
|
||
log " • Status: sudo systemctl status $SERVICE_NAME"
|
||
log " • Stoppen: sudo systemctl stop $SERVICE_NAME"
|
||
log " • Starten: sudo systemctl start $SERVICE_NAME"
|
||
log " • Neustarten: sudo systemctl restart $SERVICE_NAME"
|
||
log " • Logs: sudo journalctl -u $SERVICE_NAME -f"
|
||
log " • Service-Info: sudo journalctl -u $SERVICE_NAME --no-pager"
|
||
}
|
||
|
||
# ========================== HAUPTMENÜ ==========================
|
||
show_menu() {
|
||
clear
|
||
echo -e "${BLUE}=================================================================${NC}"
|
||
echo -e "${GREEN} $APP_NAME - Installer für Raspbian${NC}"
|
||
echo -e "${BLUE}=================================================================${NC}"
|
||
echo ""
|
||
echo -e "${YELLOW}Aktuelles Verzeichnis:${NC} $CURRENT_DIR"
|
||
echo -e "${YELLOW}Systemzeit:${NC} $(date)"
|
||
echo -e "${YELLOW}Zielverzeichnis:${NC} $APP_DIR"
|
||
echo ""
|
||
echo -e "${PURPLE}Wählen Sie eine Option:${NC}"
|
||
echo ""
|
||
echo -e "${GREEN}1)${NC} System vorbereiten (Abhängigkeiten installieren)"
|
||
echo -e " → Installiert Python 3, pip und alle benötigten Pakete"
|
||
echo -e " → Verwendet: pip install --break-system-packages"
|
||
echo -e " → Keine virtualenv, direktes System-Python"
|
||
echo ""
|
||
echo -e "${GREEN}2)${NC} Produktions-Kiosk-Modus installieren"
|
||
echo -e " → Führt System-Vorbereitung durch"
|
||
echo -e " → Verschiebt Dateien selektiv nach /opt/myp/"
|
||
echo -e " → Erstellt systemd-Service: myp-kiosk.service"
|
||
echo -e " → Startet Flask-App mit --debug auf Port 5000"
|
||
echo -e " → Testet Anwendungserreichbarkeit"
|
||
echo ""
|
||
echo -e "${RED}0)${NC} Beenden"
|
||
echo ""
|
||
echo -e "${BLUE}=================================================================${NC}"
|
||
echo -n "Ihre Wahl [0-2]: "
|
||
}
|
||
|
||
# ========================== MAIN LOGIC ==========================
|
||
main() {
|
||
# System-Checks
|
||
check_root
|
||
check_debian_system
|
||
|
||
# Erstelle Log-Datei
|
||
mkdir -p "$(dirname "$INSTALL_LOG")"
|
||
touch "$INSTALL_LOG"
|
||
|
||
log "=== MYP INSTALLER GESTARTET ==="
|
||
log "Arbeitsverzeichnis: $CURRENT_DIR"
|
||
log "Zielverzeichnis: $APP_DIR"
|
||
log "Service-Name: $SERVICE_NAME"
|
||
log "System: $(uname -a)"
|
||
log "Debian-Version: $(cat /etc/debian_version 2>/dev/null || echo 'Unbekannt')"
|
||
|
||
while true; do
|
||
show_menu
|
||
read -r choice
|
||
|
||
case $choice in
|
||
1)
|
||
clear
|
||
log "=== OPTION 1: SYSTEM VORBEREITEN ==="
|
||
install_system_dependencies
|
||
echo ""
|
||
echo -e "${GREEN}✅ System-Vorbereitung abgeschlossen!${NC}"
|
||
echo -e "${YELLOW}Drücken Sie Enter, um fortzufahren...${NC}"
|
||
read -r
|
||
;;
|
||
2)
|
||
clear
|
||
log "=== OPTION 2: PRODUKTIONS-KIOSK-MODUS ==="
|
||
setup_production_kiosk
|
||
echo ""
|
||
echo -e "${GREEN}✅ Produktions-Kiosk-Modus erfolgreich eingerichtet!${NC}"
|
||
echo -e "${BLUE}ℹ️ Die Anwendung startet automatisch bei jedem Systemstart.${NC}"
|
||
echo -e "${YELLOW}Drücken Sie Enter, um fortzufahren...${NC}"
|
||
read -r
|
||
;;
|
||
0)
|
||
log "=== INSTALLER BEENDET ==="
|
||
echo -e "${GREEN}Auf Wiedersehen!${NC}"
|
||
echo -e "${BLUE}Log-Datei: $INSTALL_LOG${NC}"
|
||
exit 0
|
||
;;
|
||
*)
|
||
echo -e "${RED}Ungültige Eingabe. Bitte wählen Sie 0-2.${NC}"
|
||
sleep 2
|
||
;;
|
||
esac
|
||
done
|
||
}
|
||
|
||
# Script starten
|
||
main "$@" |