Files
boti/templates/reload-workflow.sh
2026-03-07 19:33:48 +01:00

380 lines
10 KiB
Bash

#!/bin/bash
#
# n8n Workflow Auto-Reload Script
# Wird beim LXC-Start ausgeführt, um den Workflow neu zu laden
#
set -euo pipefail
# Konfiguration
SCRIPT_DIR="/opt/customer-stack"
LOG_DIR="${SCRIPT_DIR}/logs"
LOG_FILE="${LOG_DIR}/workflow-reload.log"
ENV_FILE="${SCRIPT_DIR}/.env"
WORKFLOW_TEMPLATE="${SCRIPT_DIR}/workflow-template.json"
WORKFLOW_NAME="RAG KI-Bot (PGVector)"
# API-Konfiguration
API_URL="http://127.0.0.1:5678"
COOKIE_FILE="/tmp/n8n_reload_cookies.txt"
MAX_WAIT=60 # Maximale Wartezeit in Sekunden
# Erstelle Log-Verzeichnis sofort (vor den Logging-Funktionen)
mkdir -p "${LOG_DIR}"
# Logging-Funktion
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "${LOG_FILE}"
}
log_error() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: $*" | tee -a "${LOG_FILE}" >&2
}
# Funktion: Warten bis n8n bereit ist
wait_for_n8n() {
log "Warte auf n8n API..."
local count=0
while [ $count -lt $MAX_WAIT ]; do
if curl -sS -o /dev/null -w "%{http_code}" "${API_URL}/rest/settings" 2>/dev/null | grep -q "200"; then
log "n8n API ist bereit"
return 0
fi
sleep 1
count=$((count + 1))
done
log_error "n8n API nicht erreichbar nach ${MAX_WAIT} Sekunden"
return 1
}
# Funktion: .env-Datei laden
load_env() {
if [ ! -f "${ENV_FILE}" ]; then
log_error ".env-Datei nicht gefunden: ${ENV_FILE}"
return 1
fi
# Exportiere alle Variablen aus .env
set -a
source "${ENV_FILE}"
set +a
log "Konfiguration geladen aus ${ENV_FILE}"
return 0
}
# Funktion: Login bei n8n
n8n_login() {
log "Login bei n8n als ${N8N_OWNER_EMAIL}..."
# Escape special characters in password for JSON
local escaped_password
escaped_password=$(echo "${N8N_OWNER_PASS}" | sed 's/\\/\\\\/g; s/"/\\"/g')
local response
response=$(curl -sS -X POST "${API_URL}/rest/login" \
-H "Content-Type: application/json" \
-c "${COOKIE_FILE}" \
-d "{\"emailOrLdapLoginId\":\"${N8N_OWNER_EMAIL}\",\"password\":\"${escaped_password}\"}" 2>&1)
if echo "$response" | grep -q '"code":\|"status":"error"'; then
log_error "Login fehlgeschlagen: ${response}"
return 1
fi
log "Login erfolgreich"
return 0
}
# Funktion: Workflow nach Name suchen
find_workflow() {
local workflow_name="$1"
log "Suche nach Workflow '${workflow_name}'..."
local response
response=$(curl -sS -X GET "${API_URL}/rest/workflows" \
-H "Content-Type: application/json" \
-b "${COOKIE_FILE}" 2>&1)
# Extract workflow ID by name
local workflow_id
workflow_id=$(echo "$response" | grep -oP "\"name\":\s*\"${workflow_name}\".*?\"id\":\s*\"\K[^\"]+|\"id\":\s*\"\K[^\"]+(?=.*?\"name\":\s*\"${workflow_name}\")" | head -1 || echo "")
if [ -n "$workflow_id" ]; then
log "Workflow gefunden: ID=${workflow_id}"
echo "$workflow_id"
return 0
else
log "Workflow '${workflow_name}' nicht gefunden"
echo ""
return 1
fi
}
# Funktion: Workflow löschen
delete_workflow() {
local workflow_id="$1"
log "Lösche Workflow ${workflow_id}..."
local response
response=$(curl -sS -X DELETE "${API_URL}/rest/workflows/${workflow_id}" \
-H "Content-Type: application/json" \
-b "${COOKIE_FILE}" 2>&1)
log "Workflow ${workflow_id} gelöscht"
return 0
}
# Funktion: Credential nach Name und Typ suchen
find_credential() {
local cred_name="$1"
local cred_type="$2"
log "Suche nach Credential '${cred_name}' (Typ: ${cred_type})..."
local response
response=$(curl -sS -X GET "${API_URL}/rest/credentials" \
-H "Content-Type: application/json" \
-b "${COOKIE_FILE}" 2>&1)
# Extract credential ID by name and type
local cred_id
cred_id=$(echo "$response" | grep -oP "\"name\":\s*\"${cred_name}\".*?\"type\":\s*\"${cred_type}\".*?\"id\":\s*\"\K[^\"]+|\"id\":\s*\"\K[^\"]+(?=.*?\"name\":\s*\"${cred_name}\".*?\"type\":\s*\"${cred_type}\")" | head -1 || echo "")
if [ -n "$cred_id" ]; then
log "Credential gefunden: ID=${cred_id}"
echo "$cred_id"
return 0
else
log_error "Credential '${cred_name}' nicht gefunden"
echo ""
return 1
fi
}
# Funktion: Workflow-Template verarbeiten
process_workflow_template() {
local pg_cred_id="$1"
local ollama_cred_id="$2"
local output_file="/tmp/workflow_processed.json"
log "Verarbeite Workflow-Template..."
# Python-Script zum Verarbeiten des Workflows
python3 - "$pg_cred_id" "$ollama_cred_id" <<'PYTHON_SCRIPT'
import json
import sys
# Read the workflow template
with open('/opt/customer-stack/workflow-template.json', 'r') as f:
workflow = json.load(f)
# Get credential IDs from arguments
pg_cred_id = sys.argv[1]
ollama_cred_id = sys.argv[2]
# Remove fields that should not be in the import
fields_to_remove = ['id', 'versionId', 'meta', 'tags', 'active', 'pinData']
for field in fields_to_remove:
workflow.pop(field, None)
# Process all nodes and replace credential IDs
for node in workflow.get('nodes', []):
credentials = node.get('credentials', {})
# Replace PostgreSQL credential
if 'postgres' in credentials:
credentials['postgres'] = {
'id': pg_cred_id,
'name': 'PostgreSQL (local)'
}
# Replace Ollama credential
if 'ollamaApi' in credentials:
credentials['ollamaApi'] = {
'id': ollama_cred_id,
'name': 'Ollama (local)'
}
# Write the processed workflow
with open('/tmp/workflow_processed.json', 'w') as f:
json.dump(workflow, f)
print("Workflow processed successfully")
PYTHON_SCRIPT
if [ $? -eq 0 ]; then
log "Workflow-Template erfolgreich verarbeitet"
echo "$output_file"
return 0
else
log_error "Fehler beim Verarbeiten des Workflow-Templates"
return 1
fi
}
# Funktion: Workflow importieren
import_workflow() {
local workflow_file="$1"
log "Importiere Workflow aus ${workflow_file}..."
local response
response=$(curl -sS -X POST "${API_URL}/rest/workflows" \
-H "Content-Type: application/json" \
-b "${COOKIE_FILE}" \
-d @"${workflow_file}" 2>&1)
# Extract workflow ID and version ID
local workflow_id
local version_id
workflow_id=$(echo "$response" | grep -oP '"id"\s*:\s*"\K[^"]+' | head -1)
version_id=$(echo "$response" | grep -oP '"versionId"\s*:\s*"\K[^"]+' | head -1)
if [ -z "$workflow_id" ]; then
log_error "Workflow-Import fehlgeschlagen: ${response}"
return 1
fi
log "Workflow importiert: ID=${workflow_id}, Version=${version_id}"
echo "${workflow_id}:${version_id}"
return 0
}
# Funktion: Workflow aktivieren
activate_workflow() {
local workflow_id="$1"
local version_id="$2"
log "Aktiviere Workflow ${workflow_id}..."
local response
response=$(curl -sS -X POST "${API_URL}/rest/workflows/${workflow_id}/activate" \
-H "Content-Type: application/json" \
-b "${COOKIE_FILE}" \
-d "{\"versionId\":\"${version_id}\"}" 2>&1)
if echo "$response" | grep -q '"active":true\|"active": true'; then
log "Workflow ${workflow_id} erfolgreich aktiviert"
return 0
else
log_error "Workflow-Aktivierung fehlgeschlagen: ${response}"
return 1
fi
}
# Funktion: Cleanup
cleanup() {
rm -f "${COOKIE_FILE}" /tmp/workflow_processed.json 2>/dev/null || true
}
# Hauptfunktion
main() {
log "========================================="
log "n8n Workflow Auto-Reload gestartet"
log "========================================="
# Erstelle Log-Verzeichnis falls nicht vorhanden
# Lade Konfiguration
if ! load_env; then
log_error "Fehler beim Laden der Konfiguration"
exit 1
fi
# Prüfe ob Workflow-Template existiert
if [ ! -f "${WORKFLOW_TEMPLATE}" ]; then
log_error "Workflow-Template nicht gefunden: ${WORKFLOW_TEMPLATE}"
exit 1
fi
# Warte auf n8n
if ! wait_for_n8n; then
log_error "n8n nicht erreichbar"
exit 1
fi
# Login
if ! n8n_login; then
log_error "Login fehlgeschlagen"
cleanup
exit 1
fi
# Suche nach bestehendem Workflow
local existing_workflow_id
existing_workflow_id=$(find_workflow "${WORKFLOW_NAME}" || echo "")
if [ -n "$existing_workflow_id" ]; then
log "Bestehender Workflow gefunden, wird gelöscht..."
delete_workflow "$existing_workflow_id"
fi
# Suche nach Credentials
log "Suche nach bestehenden Credentials..."
local pg_cred_id
local ollama_cred_id
pg_cred_id=$(find_credential "PostgreSQL (local)" "postgres" || echo "")
ollama_cred_id=$(find_credential "Ollama (local)" "ollamaApi" || echo "")
if [ -z "$pg_cred_id" ] || [ -z "$ollama_cred_id" ]; then
log_error "Credentials nicht gefunden (PostgreSQL: ${pg_cred_id}, Ollama: ${ollama_cred_id})"
cleanup
exit 1
fi
# Verarbeite Workflow-Template
local processed_workflow
processed_workflow=$(process_workflow_template "$pg_cred_id" "$ollama_cred_id")
if [ -z "$processed_workflow" ]; then
log_error "Fehler beim Verarbeiten des Workflow-Templates"
cleanup
exit 1
fi
# Importiere Workflow
local import_result
import_result=$(import_workflow "$processed_workflow")
if [ -z "$import_result" ]; then
log_error "Workflow-Import fehlgeschlagen"
cleanup
exit 1
fi
# Extrahiere IDs
local new_workflow_id
local new_version_id
new_workflow_id=$(echo "$import_result" | cut -d: -f1)
new_version_id=$(echo "$import_result" | cut -d: -f2)
# Aktiviere Workflow
if ! activate_workflow "$new_workflow_id" "$new_version_id"; then
log_error "Workflow-Aktivierung fehlgeschlagen"
cleanup
exit 1
fi
# Cleanup
cleanup
log "========================================="
log "Workflow-Reload erfolgreich abgeschlossen"
log "Workflow-ID: ${new_workflow_id}"
log "========================================="
exit 0
}
# Trap für Cleanup bei Fehler
trap cleanup EXIT
# Hauptfunktion ausführen
main "$@"