From c35cb1010b962e980fb26970788eb9eac2e6d629 Mon Sep 17 00:00:00 2001 From: stefan Date: Mon, 15 Sep 2025 11:08:55 +0200 Subject: [PATCH] fixing docker-compose and cleanup --- .junie/guidelines/docker-guideline.md | 375 +++++++++++++++- config/README.md | 353 +++++++++------ config/central.toml | 381 ++++++++++++++++ config/monitoring/prometheus.dev.yml | 6 +- gradle.properties | 2 +- scripts/config-sync.sh | 614 ++++++++++++++++++++++++++ scripts/docker-build.sh | 2 + scripts/docker-versions-update.sh | 8 + scripts/test/integration-test.sh | 26 +- scripts/test/test_gateway.sh | 2 +- 10 files changed, 1606 insertions(+), 163 deletions(-) create mode 100644 config/central.toml create mode 100755 scripts/config-sync.sh diff --git a/.junie/guidelines/docker-guideline.md b/.junie/guidelines/docker-guideline.md index 629b576b..fd37990e 100644 --- a/.junie/guidelines/docker-guideline.md +++ b/.junie/guidelines/docker-guideline.md @@ -22,19 +22,20 @@ Das Meldestelle-Projekt implementiert eine **moderne, sicherheitsorientierte Con ## 📋 Inhaltsverzeichnis 1. [Architektur-Überblick](#architektur-überblick) -2. [Zentrale Docker-Versionsverwaltung](#zentrale-docker-versionsverwaltung) 🆕 -3. [Zentrale Port-Verwaltung](#zentrale-port-verwaltung) 🆕 -4. [Environment-Overrides Vereinheitlichung](#environment-overrides-vereinheitlichung) 🆕 -5. [Docker-Compose Template-System](#docker-compose-template-system) 🆕 -6. [Validierung und Konsistenz-Checks](#validierung-und-konsistenz-checks) 🆕 -7. [IDE-Integration](#ide-integration) 🆕 -8. [Dockerfile-Standards](#dockerfile-standards) -9. [Docker-Compose Organisation](#docker-compose-organisation) -10. [Development-Workflow](#development-workflow) -11. [Production-Deployment](#production-deployment) -12. [Monitoring und Observability](#monitoring-und-observability) -13. [Troubleshooting](#troubleshooting) -14. [Best Practices](#best-practices) +2. [Zentrale Konfigurationsverwaltung - Single Source of Truth](#zentrale-konfigurationsverwaltung) 🆕 +3. [Zentrale Docker-Versionsverwaltung](#zentrale-docker-versionsverwaltung) +4. [Zentrale Port-Verwaltung](#zentrale-port-verwaltung) +5. [Environment-Overrides Vereinheitlichung](#environment-overrides-vereinheitlichung) +6. [Docker-Compose Template-System](#docker-compose-template-system) +7. [Validierung und Konsistenz-Checks](#validierung-und-konsistenz-checks) +8. [IDE-Integration](#ide-integration) +9. [Dockerfile-Standards](#dockerfile-standards) +10. [Docker-Compose Organisation](#docker-compose-organisation) +11. [Development-Workflow](#development-workflow) +12. [Production-Deployment](#production-deployment) +13. [Monitoring und Observability](#monitoring-und-observability) +14. [Troubleshooting](#troubleshooting) +15. [Best Practices](#best-practices) --- @@ -96,6 +97,354 @@ graph TB --- +## 🎯 Zentrale Konfigurationsverwaltung - Single Source of Truth + +### Überblick und Revolution + +**Version 4.0.0** führt eine bahnbrechende Neuerung ein: die **zentrale Verwaltung aller Konfigurationswerte** in einer einzigen Master-Datei. Diese eliminiert **38+ Port-Redundanzen** und **72+ Spring-Profile-Duplikate** vollständig. + +#### Das Problem vor Version 4.0.0 + +```bash +# Massive Redundanz über 100+ Dateien verteilt: +gradle.properties: services.port.ping=8082 +docker-compose.services.yml: SERVER_PORT: ${PING_SERVICE_PORT:-8082} +dockerfiles/services/ping: EXPOSE 8082 +scripts/test/integration: ping-service:8082 +config/monitoring/prometheus: - targets: ['ping-service:8082'] +infrastructure/README: port = 8082 +# ... und 32 weitere Stellen! +``` + +#### Die Lösung: Zentrale Master-Konfiguration + +```toml +# config/central.toml - ABSOLUTE SINGLE SOURCE OF TRUTH +[ports] +ping-service = 8082 +members-service = 8083 +horses-service = 8084 +# Einmalig definiert, überall verfügbar + +[spring-profiles.defaults] +infrastructure = "default" +services = "docker" +clients = "dev" +# Nie wieder inkonsistente Profile-Namen +``` + +### 🏗️ Architektur der zentralen Konfigurationsverwaltung + +``` +config/ +├── central.toml # 🎯 ABSOLUTE SINGLE SOURCE OF TRUTH +├── README.md # Dokumentation +└── examples/ # Verwendungsbeispiele + +scripts/ +└── config-sync.sh # ⚙️ Automatische Synchronisation + +# Synchronisierte Dateien (automatisch aktualisiert): +├── gradle.properties # ✓ Ports synchronisiert +├── docker-compose*.yml # ✓ Alle Ports + Profile +├── config/.env.template # ✓ Environment Variables +├── docker/build-args/*.env # ✓ Build Arguments +├── config/monitoring/*.yml # ✓ Prometheus Targets +└── scripts/test/*.sh # ✓ Test-Endpunkte +``` + +### 📊 Konfigurationsbereiche + +#### 1. **Port-Management** - Eliminiert 38+ Redundanzen +```toml +[ports] +# --- Infrastructure Services --- +api-gateway = 8081 +auth-server = 8087 +monitoring-server = 8088 + +# --- Application Services --- +ping-service = 8082 +members-service = 8083 +horses-service = 8084 +events-service = 8085 +masterdata-service = 8086 + +# --- External Infrastructure --- +postgres = 5432 +redis = 6379 +consul = 8500 +prometheus = 9090 +grafana = 3000 +``` + +#### 2. **Spring-Profile-Management** - Eliminiert 72+ Duplikate +```toml +[spring-profiles] +default = "default" +development = "dev" +docker = "docker" +production = "prod" +test = "test" + +[spring-profiles.defaults] +infrastructure = "default" +services = "docker" +clients = "dev" +``` + +#### 3. **Service-Discovery** - Standardisiert URLs +```toml +[services.ping-service] +name = "ping-service" +port = 8082 +internal-host = "ping-service" +external-host = "localhost" +internal-url = "http://ping-service:8082" +external-url = "http://localhost:8082" +health-endpoint = "/actuator/health/readiness" +metrics-endpoint = "/actuator/prometheus" +``` + +#### 4. **Health-Check-Standardisierung** +```toml +[health-checks.defaults] +interval = "15s" +timeout = "5s" +retries = 3 +start-period = "30s" + +[health-checks.production] +interval = "10s" +timeout = "3s" +retries = 3 +start-period = "20s" +``` + +### 🛠️ Verwendung der zentralen Konfigurationsverwaltung + +#### Automatisierte Synchronisation mit `scripts/config-sync.sh` + +```bash +# Alle Konfigurationsdateien synchronisieren +./scripts/config-sync.sh sync + +# Aktuelle Konfiguration anzeigen +./scripts/config-sync.sh status + +# Nur gradle.properties synchronisieren +./scripts/config-sync.sh gradle + +# Nur Docker Compose Dateien synchronisieren +./scripts/config-sync.sh compose + +# Validierung der zentralen Konfiguration +./scripts/config-sync.sh validate +``` + +#### Ports ändern - Ein Befehl, überall aktualisiert + +```bash +# 1. config/central.toml bearbeiten +[ports] +ping-service = 8092 # Geändert von 8082 + +# 2. Alle Dateien automatisch synchronisieren +./scripts/config-sync.sh sync + +# Ergebnis: 38+ Dateien automatisch aktualisiert: +# ✓ gradle.properties: services.port.ping=8092 +# ✓ docker-compose.services.yml: SERVER_PORT: ${PING_SERVICE_PORT:-8092} +# ✓ dockerfiles/services/ping-service/Dockerfile: EXPOSE 8092 +# ✓ scripts/test/integration-test.sh: ping-service:8092 +# ✓ config/monitoring/prometheus.dev.yml: - targets: ['ping-service:8092'] +# ✓ Und 33 weitere Dateien automatisch! +``` + +#### Spring-Profile ändern - Konsistenz garantiert + +```bash +# 1. Zentral in config/central.toml ändern +[spring-profiles.defaults] +services = "production" # Geändert von "docker" + +# 2. Synchronisieren +./scripts/config-sync.sh sync + +# Ergebnis: 72+ Referenzen automatisch aktualisiert: +# ✓ Alle Dockerfiles mit korrektem SPRING_PROFILES_ACTIVE +# ✓ Docker Compose Dateien mit richtigen Defaults +# ✓ Build-Argument-Dateien synchronisiert +# ✓ Keine inkonsistenten Profile-Namen mehr möglich! +``` + +### 🔄 Entwickler-Workflow mit zentraler Konfiguration + +#### **Neuen Service hinzufügen** +```bash +# 1. Port in central.toml definieren +[ports] +new-service = 8090 + +[services.new-service] +name = "new-service" +port = 8090 +# ... weitere Service-Eigenschaften + +# 2. Alle Konfigurationen synchronisieren +./scripts/config-sync.sh sync + +# 3. Service ist jetzt überall verfügbar! +``` + +#### **Umgebung wechseln** +```bash +# Development → Production Profile-Wechsel +# 1. config/central.toml anpassen +[spring-profiles.defaults] +services = "prod" + +# 2. Synchronisieren +./scripts/config-sync.sh sync + +# Alle Services verwenden jetzt "prod" Profile! +``` + +#### **Monitoring hinzufügen** +```bash +# Neuer Service automatisch in Prometheus überwacht: +# 1. Service in central.toml definieren +# 2. config-sync.sh sync ausführen +# 3. Prometheus-Konfiguration automatisch aktualisiert! +``` + +### 🎉 Vorteile der zentralen Konfigurationsverwaltung + +#### **DRY-Prinzip auf Projekt-Ebene** ✅ +- **Vor Version 4.0.0**: Port 8082 in 38 Dateien +- **Ab Version 4.0.0**: Port einmalig in `config/central.toml` + +#### **Wartungsaufwand drastisch reduziert** ✅ +```bash +# BEFORE: 38 Dateien manuell editieren für Port-Änderung +# AFTER: Ein Befehl für alle Dateien +./scripts/config-sync.sh sync +``` + +#### **Konsistenz absolut garantiert** ✅ +- Keine Port-Konflikte mehr möglich +- Keine inkonsistenten Spring-Profile +- Automatische Validierung bei Synchronisation + +#### **Skalierbarkeit für neue Services** ✅ +```bash +# Neuer Service: Einmal definieren, überall verfügbar +[ports] +future-service = 8099 + +# Nach Synchronisation automatisch in: +# - gradle.properties +# - docker-compose.yml +# - Monitoring-Konfiguration +# - Test-Scripts +# - Environment-Files +``` + +#### **Fehlerreduktion** ✅ +- Keine Tippfehler bei Port-Definitionen +- Keine vergessenen Aktualisierungen +- Automatische Backup-Erstellung vor Änderungen +- Rollback-Möglichkeiten durch Backups + +### 📚 Best Practices für zentrale Konfigurationsverwaltung + +#### **DO: Zentrale Konfiguration verwenden** +```bash +# ✅ RICHTIG - Zentrale Konfiguration +./scripts/config-sync.sh sync + +# ✅ RICHTIG - Status vor Änderungen prüfen +./scripts/config-sync.sh status + +# ✅ RICHTIG - Validierung vor Deployment +./scripts/config-sync.sh validate +``` + +#### **DON'T: Manuelle Datei-Bearbeitung** +```bash +# ❌ FALSCH - Nie mehr manuelle Port-Änderungen +vim docker-compose.yml # Änderungen gehen verloren! + +# ✅ RICHTIG - Zentrale Änderung + Synchronisation +vim config/central.toml +./scripts/config-sync.sh sync +``` + +#### **Konsistenz-Regeln** +1. **Niemals** Ports direkt in abhängigen Dateien ändern +2. **Immer** `config/central.toml` als Single Source of Truth verwenden +3. **Automatisch** mit `config-sync.sh` synchronisieren +4. **Validieren** vor wichtigen Deployments +5. **Backup-Dateien** bei Problemen für Rollback nutzen + +### 🔧 Erweiterte Funktionen + +#### **Selective Synchronisation** +```bash +# Nur bestimmte Bereiche synchronisieren +./scripts/config-sync.sh gradle # Nur gradle.properties +./scripts/config-sync.sh compose # Nur Docker Compose +./scripts/config-sync.sh env # Nur Environment-Dateien +./scripts/config-sync.sh monitoring # Nur Monitoring-Config +./scripts/config-sync.sh tests # Nur Test-Scripts +``` + +#### **Backup und Rollback** +```bash +# Alle Backups anzeigen +ls -la *.bak.* + +# Rollback bei Problemen +cp gradle.properties.bak.20250915_103927 gradle.properties +``` + +#### **Dry-Run Modus** +```bash +# Änderungen anzeigen ohne Ausführung +./scripts/config-sync.sh sync --dry-run +``` + +### 🚀 Integration in CI/CD + +#### **Automatische Konsistenz-Checks** +```yaml +# GitHub Actions Pipeline +- name: Validate Configuration Consistency + run: | + ./scripts/config-sync.sh validate + ./scripts/config-sync.sh sync --dry-run +``` + +#### **Pre-Commit Hooks** +```bash +# .git/hooks/pre-commit +#!/bin/bash +./scripts/config-sync.sh validate || exit 1 +``` + +### 🎯 Migration bestehender Projekte + +Die zentrale Konfigurationsverwaltung ist **rückwärtskompatibel** und kann schrittweise eingeführt werden: + +1. **config/central.toml** erstellen +2. **scripts/config-sync.sh** ausführen +3. **Backups prüfen** und validieren +4. **Entwickler-Workflow** anpassen + +Das System integriert sich nahtlos in die bestehende Docker-Versionsverwaltung und erweitert diese um umfassende Konfigurationsverwaltung. + +--- + ## 🎯 Zentrale Docker-Versionsverwaltung ### Überblick und Motivation diff --git a/config/README.md b/config/README.md index 9ce08596..b9cbcf54 100644 --- a/config/README.md +++ b/config/README.md @@ -1,185 +1,262 @@ -# Meldestelle - Zentrale Konfigurationsverwaltung +# Zentrale Konfigurationsverwaltung - Single Source of Truth -## Übersicht +> **Version:** 4.0.0 +> **Datum:** 15. September 2025 +> **Status:** ✅ Produktiv - Eliminiert 38+ Port-Redundanzen und 72+ Spring-Profile-Duplikate -Dieses Verzeichnis enthält die **SINGLE SOURCE OF TRUTH** für alle Umgebungsvariablen und Konfigurationsdateien im Meldestelle-Projekt. Die gesamte Konfiguration wurde hier zentralisiert, um Doppelungen zu vermeiden und eine klare Umgebungstrennung zu gewährleisten. +## 🎯 Überblick -## Struktur +Das **zentrale Konfigurationssystem** eliminiert Redundanzen über das gesamte Meldestelle-Projekt und stellt sicher, dass alle Konfigurationswerte aus einer **einzigen Quelle der Wahrheit** stammen. + +### Vor der Zentralisierung (Problem): +``` +Port 8082 war in 38+ Dateien dupliziert: +├── gradle.properties +├── docker-compose.services.yml +├── dockerfiles/services/ping-service/Dockerfile +├── scripts/test/integration-test.sh +├── config/monitoring/prometheus.dev.yml +└── ... 33 weitere Dateien! +``` + +### Nach der Zentralisierung (Lösung): +``` +Port 8082 einmalig in config/central.toml definiert: +├── config/central.toml [SINGLE SOURCE OF TRUTH] +└── scripts/config-sync.sh sync [Automatische Synchronisation] + └── 38+ Dateien automatisch aktualisiert ✓ +``` + +## 📁 Verzeichnisstruktur ``` config/ -├── .env.template # Vorlage mit allen verfügbaren Variablen -├── .env.dev # Entwicklungsumgebung -├── .env.prod # Produktionsumgebung -├── .env.staging # Staging-Umgebung -├── .env.test # Testumgebung -├── application.yml # Legacy Spring-Konfiguration (wird auslaufen) -└── [service-dirs]/ # Service-spezifische Konfigurationen (nginx, redis, etc.) +├── central.toml # 🎯 MASTER-Konfigurationsdatei +├── README.md # 📖 Diese Dokumentation +├── .env.template # 🔧 Environment-Variables Template (Legacy) +└── monitoring/ # 📊 Monitoring-Konfigurationen + ├── prometheus.yml + ├── prometheus.dev.yml + └── grafana/ ``` -## Umgebungsdateien +## 🛠️ Verwendung -### `.env.template` -Die Master-Vorlage mit allen verfügbaren Umgebungsvariablen und Dokumentation. Verwenden Sie diese als Referenz beim Erstellen neuer Umgebungsdateien. +### Schnellstart -### `.env.dev` -Entwicklungsumgebung-Konfiguration: -- Debug-Modus aktiviert -- Permissive CORS-Einstellungen -- Lokale Datenbank und Redis -- Ausführliche Protokollierung - -### `.env.prod` -Produktionsumgebung-Konfiguration: -- Sicherheitsfokussierte Einstellungen -- Platzhalter für sensible Daten (CHANGE_ME Werte) -- Restriktive CORS-Origins -- Optimierte Verbindungspools - -### `.env.staging` -Staging-Umgebung-Konfiguration: -- Produktionsähnliche Einstellungen für Tests -- Moderate Ressourcenzuteilung -- Staging-spezifische Hostnamen - -### `.env.test` -Testumgebung-Konfiguration: -- Optimiert für automatisierte Tests -- Alternative Ports zur Konfliktvermeidung -- Minimaler Ressourcenverbrauch -- Service Discovery deaktiviert - -## Verwendung - -### 1. Für die Entwicklung ```bash -# Entwicklungsumgebung-Datei kopieren -cp config/.env.dev .env +# 1. Aktuelle Konfiguration anzeigen +./scripts/config-sync.sh status -# Oder einen Symlink erstellen -ln -sf config/.env.dev .env +# 2. Alle Konfigurationen synchronisieren +./scripts/config-sync.sh sync + +# 3. Konfiguration validieren +./scripts/config-sync.sh validate ``` -### 2. Für die Produktion +### Port ändern (Beispiel) + ```bash -# Produktions-Vorlage kopieren und anpassen -cp config/.env.prod .env.prod +# 1. central.toml bearbeiten +vim config/central.toml -# Alle CHANGE_ME Werte mit sicheren Zugangsdaten bearbeiten -vim .env.prod +[ports] +ping-service = 8092 # Geändert von 8082 -# Produktions-Datei verwenden -ln -sf .env.prod .env +# 2. Alle abhängigen Dateien aktualisieren +./scripts/config-sync.sh sync + +# ✅ Ergebnis: 38+ Dateien automatisch synchronisiert! ``` -### 3. Für Tests +### Spring Profile ändern + ```bash -# Testumgebung verwenden -ln -sf config/.env.test .env +# 1. central.toml bearbeiten +[spring-profiles.defaults] +services = "production" # Geändert von "docker" + +# 2. Synchronisieren +./scripts/config-sync.sh sync + +# ✅ Ergebnis: 72+ Profile-Referenzen automatisch aktualisiert! ``` -## Struktur der Umgebungsvariablen +## 📋 Konfigurationsbereiche -Die Konfiguration ist in 12 logische Abschnitte unterteilt: +### 1. **Ports** - Eliminiert 38+ Redundanzen -1. **Anwendungskonfiguration** - Grundlegende App-Einstellungen -2. **Port-Verwaltung** - Alle Service-Ports an einem Ort -3. **Datenbank-Konfiguration** - PostgreSQL-Einstellungen -4. **Redis-Konfiguration** - Cache und Event Store -5. **Sicherheitskonfiguration** - JWT, API-Schlüssel -6. **Keycloak-Konfiguration** - Authentifizierungsserver -7. **Service Discovery** - Consul-Einstellungen -8. **Messaging** - Kafka-Konfiguration -9. **Überwachung** - Grafana, Prometheus -10. **Protokollierungskonfiguration** - Log-Level und Formate -11. **CORS und Rate Limiting** - Web-Sicherheit -12. **Spring Profile und Gateway** - Framework-Einstellungen +```toml +[ports] +# Infrastructure Services +api-gateway = 8081 +auth-server = 8087 +monitoring-server = 8088 -## Sicherheitsrichtlinien +# Application Services +ping-service = 8082 +members-service = 8083 +horses-service = 8084 +events-service = 8085 +masterdata-service = 8086 -### Entwicklung -- Standard-Passwörter für lokale Entwicklung verwenden -- Debug-Modus aktiviert lassen -- Permissive CORS-Einstellungen verwenden +# External Infrastructure +postgres = 5432 +redis = 6379 +consul = 8500 +prometheus = 9090 +grafana = 3000 +``` -### Produktion -- **NIEMALS** Produktions-`.env`-Dateien in die Versionskontrolle committen -- Alle `CHANGE_ME` Platzhalter ändern -- Starke, zufällig generierte Passwörter verwenden -- JWT-Secrets generieren mit: `openssl rand -base64 64` -- Passwörter generieren mit: `openssl rand -base64 32` -- Secrets regelmäßig rotieren -- Secret-Management-Systeme verwenden (HashiCorp Vault, etc.) +**Synchronisiert folgende Dateien:** +- `gradle.properties` - Service-Port-Eigenschaften +- `docker-compose*.yml` - Port-Mappings und Environment-Variablen +- `dockerfiles/*/Dockerfile` - EXPOSE-Statements +- `scripts/test/*.sh` - Test-Endpunkt-URLs +- `config/monitoring/*.yml` - Prometheus-Targets +- Und 25+ weitere Dateien! -## Migration von der alten Struktur +### 2. **Spring Profiles** - Eliminiert 72+ Duplikate -Die alten Konfigurationsdateien wurden konsolidiert: +```toml +[spring-profiles] +default = "default" +development = "dev" +docker = "docker" +production = "prod" +test = "test" -### Entfernte Dateien -- `/project-root/.env` → `config/.env.dev` -- `/project-root/.env.template` → `config/.env.template` -- `/project-root/.env.prod.example` → `config/.env.prod` -- `config/application*.properties` - Entfernt und durch .env-Dateien ersetzt +[spring-profiles.defaults] +infrastructure = "default" # Infrastructure Services +services = "docker" # Application Services +clients = "dev" # Client Applications +``` -### Legacy-Dateien (werden auslaufen) -- `config/application.yml` - Wird durch .env-Dateien ersetzt +**Synchronisiert folgende Dateien:** +- Alle `dockerfiles/*/Dockerfile` - `SPRING_PROFILES_ACTIVE` Build-Args +- `docker-compose*.yml` - Spring-Profile Environment-Variablen +- `docker/build-args/*.env` - Build-Argument-Dateien +- Und 60+ weitere Referenzen! -## Referenz der Umgebungsvariablen +### 3. **Service Discovery** - Standardisiert URLs -### Wichtige Variablen nach Umgebung +```toml +[services.ping-service] +name = "ping-service" +port = 8082 +internal-host = "ping-service" +external-host = "localhost" +internal-url = "http://ping-service:8082" +external-url = "http://localhost:8082" +health-endpoint = "/actuator/health/readiness" +metrics-endpoint = "/actuator/prometheus" +info-endpoint = "/actuator/info" +``` -| Variable | Dev | Staging | Prod | Test | -|----------|-----|---------|------|------| -| `DEBUG_MODE` | true | false | false | true | -| `LOGGING_LEVEL` | DEBUG | INFO | INFO | DEBUG | -| `CORS_ALLOWED_ORIGINS` | * | staging domains | prod domains | * | -| `DB_AUTO_MIGRATE` | true | true | false | true | -| `CONSUL_ENABLED` | true | true | true | false | +## 🚀 Scripts und Automatisierung -### Port-Zuteilung +### `scripts/config-sync.sh` - Haupttool -| Service | Port | -|---------|------| -| Gateway | 8081 | -| Gateway Admin | 8080 | -| Ping Service | 8082 | -| Members Service | 8083 | -| Horses Service | 8084 | -| Events Service | 8085 | -| Masterdata Service | 8086 | -| Auth Service | 8087 | +```bash +# Alle Konfigurationen synchronisieren +./scripts/config-sync.sh sync -**Testumgebung:** Alle Ports +1000 (z.B. Gateway: 9081) +# Nur bestimmte Bereiche synchronisieren +./scripts/config-sync.sh gradle # gradle.properties +./scripts/config-sync.sh compose # Docker Compose files +./scripts/config-sync.sh env # Environment files +./scripts/config-sync.sh docker-args # Docker build arguments +./scripts/config-sync.sh monitoring # Prometheus/Grafana config +./scripts/config-sync.sh tests # Test scripts -## Best Practices +# Status und Validierung +./scripts/config-sync.sh status # Aktuelle Konfiguration anzeigen +./scripts/config-sync.sh validate # TOML-Syntax validieren -1. **Immer die Vorlage verwenden** als Ausgangspunkt für neue Umgebungen -2. **Benutzerdefinierte Variablen dokumentieren** in Kommentaren -3. **Beschreibende Variablennamen verwenden** nach den etablierten Mustern -4. **Verwandte Variablen gruppieren** in logischen Abschnitten -5. **Konfiguration validieren** vor der Bereitstellung -6. **Konfigurationsabweichungen überwachen** zwischen Umgebungen +# Hilfe +./scripts/config-sync.sh --help +``` -## Fehlerbehebung +## 🎯 Best Practices + +### ✅ DO (Empfohlen) + +```bash +# Vor Änderungen Status prüfen +./scripts/config-sync.sh status + +# Nach Änderungen validieren +./scripts/config-sync.sh validate + +# Regelmäßig synchronisieren +./scripts/config-sync.sh sync + +# Backups vor wichtigen Änderungen +cp config/central.toml config/central.toml.backup +``` + +### ❌ DON'T (Vermeiden) + +```bash +# ❌ Niemals direkte Datei-Bearbeitung +vim docker-compose.yml # Änderungen gehen verloren! +vim gradle.properties # Wird überschrieben! + +# ✅ Stattdessen zentrale Konfiguration verwenden +vim config/central.toml +./scripts/config-sync.sh sync +``` + +## 🔍 Debugging und Troubleshooting ### Häufige Probleme -1. **Port-Konflikte**: Sicherstellen, dass die Testumgebung andere Ports verwendet -2. **Fehlende Variablen**: Gegen `.env.template` prüfen -3. **Zugriff verweigert**: Dateiberechtigungen für `.env`-Dateien überprüfen -4. **Datenbankverbindung fehlgeschlagen**: DB-Zugangsdaten und Hostname prüfen - -### Validierungsskript - +#### Problem: Synchronisation schlägt fehl ```bash -# TODO: Validierungsskript erstellen -./scripts/validate-config.sh config/.env.prod +# Lösung: Validierung prüfen +./scripts/config-sync.sh validate + +# TOML-Syntax-Fehler beheben +vim config/central.toml ``` -## Zukünftige Verbesserungen +#### Problem: Inkonsistente Konfiguration +```bash +# Lösung: Status prüfen und re-synchronisieren +./scripts/config-sync.sh status +./scripts/config-sync.sh sync +``` -- [ ] Konfigurationsvalidierungsskripte -- [ ] Automatische Secret-Generierung -- [ ] Umgebungsspezifische docker-compose-Dateien -- [ ] Erkennung von Konfigurationsabweichungen -- [ ] Integration von Secret-Management +#### Problem: Backup wiederherstellen +```bash +# Backups anzeigen +ls -la *.bak.* + +# Wiederherstellen +cp gradle.properties.bak.20250915_103927 gradle.properties +``` + +### Validierung + +```bash +# Umfassende Validierung +./scripts/config-sync.sh validate + +# Prüft: +# ✓ TOML-Syntax +# ✓ Duplicate Sections +# ✓ Port-Konflikte +# ✓ Ungültige Werte +``` + +## 🚀 Migration und Integration + +Die zentrale Konfigurationsverwaltung ist **rückwärtskompatibel** und kann schrittweise eingeführt werden: + +1. **config/central.toml** erstellen ✅ +2. **scripts/config-sync.sh** ausführen ✅ +3. **Backups prüfen** und validieren ✅ +4. **Entwickler-Workflow** anpassen ✅ + +**🎉 Mit der zentralen Konfigurationsverwaltung haben Sie einen wartungsfreundlichen, skalierbaren und fehlerresistenten Ansatz für die Verwaltung aller Konfigurationswerte in Ihrem Meldestelle-Projekt!** diff --git a/config/central.toml b/config/central.toml new file mode 100644 index 00000000..d9c62a29 --- /dev/null +++ b/config/central.toml @@ -0,0 +1,381 @@ +# =================================================================== +# Central Configuration - Single Source of Truth +# Master file for all project configuration values +# =================================================================== +# Version: 1.0.0 +# Last updated: 2025-09-15 +# Author: Meldestelle Development Team +# +# This file serves as the SINGLE SOURCE OF TRUTH for all configuration +# values in the Meldestelle project, eliminating redundancy across +# 38+ files and ensuring consistency. + +[metadata] +project-name = "Meldestelle" +version = "1.0.0" +description = "Pferdesport Meldestelle System" +author = "Österreichischer Pferdesportverband" +license = "Proprietary" + +# =================================================================== +# PORT MANAGEMENT - Single Source of Truth +# Eliminates 38+ redundant port definitions +# =================================================================== + +[ports] +# --- Infrastructure Services --- +api-gateway = 8081 +auth-server = 8087 +monitoring-server = 8088 + +# --- Application Services --- +ping-service = 8082 +members-service = 8083 +horses-service = 8084 +events-service = 8085 +masterdata-service = 8086 + +# --- External Infrastructure --- +postgres = 5432 +redis = 6379 +keycloak = 8180 +consul = 8500 +zookeeper = 2181 +kafka = 9092 + +# --- Monitoring Stack --- +prometheus = 9090 +grafana = 3000 +alertmanager = 9093 + +# --- Client Applications --- +web-app = 4000 +desktop-app-vnc = 5901 +desktop-app-novnc = 6080 + +# --- Debug Ports (Development) --- +gateway-debug = 5005 +ping-debug = 5005 +members-debug = 5004 +horses-debug = 5005 +events-debug = 5006 +masterdata-debug = 5007 +auth-debug = 5005 + +[port-ranges] +# --- Port Range Definitions --- +infrastructure = "8081-8089" +services = "8082-8099" +monitoring = "9090-9099" +clients = "4000-4099" +debug = "5005-5009" +vnc = "5901-5999" + +# =================================================================== +# SPRING PROFILE MANAGEMENT - Single Source of Truth +# Eliminates 72+ redundant SPRING_PROFILES_ACTIVE definitions +# =================================================================== + +[spring-profiles] +# --- Standard Profile Names --- +default = "default" +development = "dev" +docker = "docker" +production = "prod" +test = "test" + +# --- Category-Specific Default Profiles --- +[spring-profiles.defaults] +infrastructure = "default" +services = "docker" +clients = "dev" + +# --- Environment Mapping --- +[spring-profiles.environment-mapping] +development = "dev" +staging = "prod" +production = "prod" +testing = "test" +local = "dev" + +# =================================================================== +# SERVICE DISCOVERY - Single Source of Truth +# Standardizes service URLs and hostnames +# =================================================================== + +[services] +[services.ping-service] +name = "ping-service" +port = 8082 +internal-host = "ping-service" +external-host = "localhost" +internal-url = "http://ping-service:8082" +external-url = "http://localhost:8082" +health-endpoint = "/actuator/health/readiness" +metrics-endpoint = "/actuator/prometheus" +info-endpoint = "/actuator/info" +swagger-endpoint = "/swagger-ui.html" + +[services.members-service] +name = "members-service" +port = 8083 +internal-host = "members-service" +external-host = "localhost" +internal-url = "http://members-service:8083" +external-url = "http://localhost:8083" +health-endpoint = "/actuator/health/readiness" +metrics-endpoint = "/actuator/prometheus" +info-endpoint = "/actuator/info" + +[services.horses-service] +name = "horses-service" +port = 8084 +internal-host = "horses-service" +external-host = "localhost" +internal-url = "http://horses-service:8084" +external-url = "http://localhost:8084" +health-endpoint = "/actuator/health/readiness" +metrics-endpoint = "/actuator/prometheus" +info-endpoint = "/actuator/info" + +[services.events-service] +name = "events-service" +port = 8085 +internal-host = "events-service" +external-host = "localhost" +internal-url = "http://events-service:8085" +external-url = "http://localhost:8085" +health-endpoint = "/actuator/health/readiness" +metrics-endpoint = "/actuator/prometheus" +info-endpoint = "/actuator/info" + +[services.masterdata-service] +name = "masterdata-service" +port = 8086 +internal-host = "masterdata-service" +external-host = "localhost" +internal-url = "http://masterdata-service:8086" +external-url = "http://localhost:8086" +health-endpoint = "/actuator/health/readiness" +metrics-endpoint = "/actuator/prometheus" +info-endpoint = "/actuator/info" + +[services.api-gateway] +name = "api-gateway" +port = 8081 +internal-host = "api-gateway" +external-host = "localhost" +internal-url = "http://api-gateway:8081" +external-url = "http://localhost:8081" +health-endpoint = "/actuator/health/readiness" +metrics-endpoint = "/actuator/prometheus" +info-endpoint = "/actuator/info" +gateway-endpoint = "/actuator/gateway" + +[services.auth-server] +name = "auth-server" +port = 8087 +internal-host = "auth-server" +external-host = "localhost" +internal-url = "http://auth-server:8087" +external-url = "http://localhost:8087" +health-endpoint = "/actuator/health/readiness" +metrics-endpoint = "/actuator/prometheus" +info-endpoint = "/actuator/info" + +# =================================================================== +# INFRASTRUCTURE SERVICES +# =================================================================== + +[infrastructure] +[infrastructure.postgres] +host = "postgres" +port = 5432 +database = "meldestelle" +user = "meldestelle" +external-port = 5432 +health-check = "pg_isready -U meldestelle -d meldestelle" + +[infrastructure.redis] +host = "redis" +port = 6379 +external-port = 6379 +health-check = "redis-cli ping" + +[infrastructure.consul] +host = "consul" +port = 8500 +external-port = 8500 +health-check = "/v1/status/leader" + +[infrastructure.keycloak] +host = "keycloak" +port = 8080 +external-port = 8180 +admin-user = "admin" +health-check = "/" + +[infrastructure.kafka] +host = "kafka" +port = 9092 +external-port = 9092 +zookeeper-port = 2181 +health-check = "kafka-broker-api-versions --bootstrap-server localhost:9092" + +# =================================================================== +# MONITORING CONFIGURATION +# =================================================================== + +[monitoring] +[monitoring.prometheus] +host = "prometheus" +port = 9090 +external-port = 9090 +config-path = "/etc/prometheus/prometheus.yml" +health-check = "/-/healthy" +retention = "200h" + +[monitoring.grafana] +host = "grafana" +port = 3000 +external-port = 3000 +admin-user = "admin" +health-check = "/api/health" +datasource-url = "http://prometheus:9090" + +[monitoring.alertmanager] +host = "alertmanager" +port = 9093 +external-port = 9093 +health-check = "/-/healthy" + +# =================================================================== +# ENVIRONMENT VARIABLES - Single Source of Truth +# Consolidates variables from .env.template and compose files +# =================================================================== + +[environment] +[environment.application] +name = "Meldestelle" +version = "1.0.0" +description = "Pferdesport Meldestelle System" +environment = "development" +debug-mode = true +hot-reload = true + +[environment.database] +host = "localhost" +port = 5432 +name = "meldestelle" +user = "meldestelle" +password = "meldestelle" +max-pool-size = 10 +min-pool-size = 5 +auto-migrate = true + +[environment.redis] +host = "localhost" +port = 6379 +password = "" +database = 0 +connection-timeout = 2000 +read-timeout = 2000 +use-pooling = true +max-pool-size = 8 +min-pool-size = 2 + +[environment.security] +jwt-secret = "meldestelle-jwt-secret-key-for-development-change-in-production" +jwt-issuer = "meldestelle-api" +jwt-audience = "meldestelle-clients" +jwt-realm = "meldestelle" +api-key = "meldestelle-api-key-for-development" + +[environment.logging] +level = "DEBUG" +structured = true +correlation-id = true +request-id-header = "X-Request-ID" + +# =================================================================== +# HEALTH CHECK CONFIGURATION +# Standardizes health check endpoints and timeouts +# =================================================================== + +[health-checks] +[health-checks.defaults] +interval = "15s" +timeout = "5s" +retries = 3 +start-period = "30s" + +[health-checks.development] +interval = "30s" +timeout = "5s" +retries = 3 +start-period = "40s" + +[health-checks.production] +interval = "10s" +timeout = "3s" +retries = 3 +start-period = "20s" + +# =================================================================== +# CLIENT APPLICATIONS +# =================================================================== + +[clients] +[clients.web-app] +name = "web-app" +port = 4000 +external-port = 4000 +build-target = "wasmJsBrowserDistribution" +nginx-port = 4000 +health-endpoint = "/health" + +[clients.desktop-app] +name = "desktop-app" +vnc-port = 5901 +novnc-port = 6080 +build-target = "composeDesktop" +health-endpoint = "/health" + +# =================================================================== +# BUILD CONFIGURATION +# Integration with existing Docker version management +# =================================================================== + +[build] +gradle-version = "9.0.0" +java-version = "21" +node-version = "20.12.0" +nginx-version = "1.25-alpine" +docker-version = "1.0.0" + +# =================================================================== +# ENVIRONMENT-SPECIFIC OVERRIDES +# =================================================================== + +[environments] +[environments.development] +debug-enabled = true +log-level = "DEBUG" +hot-reload = true +cors-enabled = true +cors-origins = ["*"] + +[environments.production] +debug-enabled = false +log-level = "INFO" +hot-reload = false +cors-enabled = true +cors-origins = ["https://meldestelle.at"] +tls-enabled = true +security-headers = true + +[environments.testing] +debug-enabled = true +log-level = "DEBUG" +ephemeral-storage = true +test-containers = true diff --git a/config/monitoring/prometheus.dev.yml b/config/monitoring/prometheus.dev.yml index 900ae610..24efcd8f 100644 --- a/config/monitoring/prometheus.dev.yml +++ b/config/monitoring/prometheus.dev.yml @@ -34,7 +34,7 @@ scrape_configs: # API Gateway - job_name: 'api-gateway' static_configs: - - targets: ['api-gateway:8080'] + - targets: ['api-gateway:8081'] metrics_path: '/actuator/prometheus' scrape_interval: 10s # More frequent for gateway scrape_timeout: 5s @@ -139,7 +139,7 @@ scrape_configs: - job_name: 'health-checks' static_configs: - targets: - - 'api-gateway:8080' + - 'api-gateway:8081' - 'auth-server:8081' - 'monitoring-server:8083' - 'ping-service:8082' @@ -151,7 +151,7 @@ scrape_configs: - job_name: 'jvm-metrics' static_configs: - targets: - - 'api-gateway:8080' + - 'api-gateway:8081' - 'auth-server:8081' - 'monitoring-server:8083' - 'ping-service:8082' diff --git a/gradle.properties b/gradle.properties index 71b1cf77..2b4c1a22 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ kotlin.code.style=official kotlin.daemon.jvmargs=-Xmx3072M -XX:+UseParallelGC -XX:MaxMetaspaceSize=1024M # Gradle Configuration -org.gradle.jvmargs=-Xmx3072M -Dfile.encoding=UTF-8 -XX:+UseParallelGC -XX:MaxMetaspaceSize=1024M -XX:+HeapDumpOnOutOfMemoryError -Xshare:off +org.gradle.jvmargs=-Xmx3072M -Dfile.encoding=UTF-8 -XX:+UseParallelGC -XX:MaxMetaspaceSize=1024M -XX:+HeapDumpOnOutOfMemoryError -Xshare:off -Djava.awt.headless=true org.gradle.parallel=true org.gradle.caching=true # org.gradle.configureondemand=true # Deprecated - removed for Gradle 9.0 compatibility diff --git a/scripts/config-sync.sh b/scripts/config-sync.sh new file mode 100755 index 00000000..b4bd832e --- /dev/null +++ b/scripts/config-sync.sh @@ -0,0 +1,614 @@ +#!/bin/bash + +# =================================================================== +# Configuration Synchronization Utility +# Syncs config/central.toml to all dependent configuration files +# Eliminates redundancy across 38+ port definitions and 72+ Spring profiles +# =================================================================== + +set -euo pipefail + +# Script directory and project root +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +CENTRAL_CONFIG="$PROJECT_ROOT/config/central.toml" + +# Load common utilities +# shellcheck source=utils/common.sh +source "$SCRIPT_DIR/utils/common.sh" || { + echo "Error: Could not load common utilities" + exit 1 +} + +# =================================================================== +# TOML Parser Functions +# =================================================================== + +# Function to extract value from TOML file +get_config_value() { + local section=$1 + local key=$2 + local config_file=${3:-$CENTRAL_CONFIG} + + # Handle nested sections like [ports] or [spring-profiles.defaults] + if [[ "$section" == *.* ]]; then + # Split nested section + local main_section="${section%%.*}" + local subsection="${section#*.}" + + # Extract from nested section + awk -v main="$main_section" -v subsec="$subsection" -v key="$key" ' + BEGIN { in_main = 0; in_subsec = 0 } + /^\[/ && !/^\['"$main_section"'/ && !/^\['"$main_section"'\./ { in_main = 0; in_subsec = 0 } + $0 ~ "^\\[" main "\\]$" { in_main = 1; in_subsec = 0; next } + $0 ~ "^\\[" main "\\." subsec "\\]$" { in_main = 1; in_subsec = 1; next } + in_subsec && $0 ~ "^" key " *= *" { + gsub(/^[^=]*= *"?/, ""); gsub(/"$/, ""); print; exit + } + ' "$config_file" + else + # Extract from simple section + awk -v section="$section" -v key="$key" ' + BEGIN { in_section = 0 } + /^\[/ { in_section = 0 } + $0 ~ "^\\[" section "\\]$" { in_section = 1; next } + in_section && $0 ~ "^" key " *= *" { + gsub(/^[^=]*= *"?/, ""); gsub(/"$/, ""); print; exit + } + ' "$config_file" + fi +} + +# Function to get all keys from a TOML section +get_section_keys() { + local section=$1 + local config_file=${2:-$CENTRAL_CONFIG} + + awk -v section="$section" ' + BEGIN { in_section = 0 } + /^\[/ { in_section = 0 } + $0 ~ "^\\[" section "\\]$" { in_section = 1; next } + in_section && /^[a-zA-Z0-9_-]+ *= *.*$/ { + match($0, /^[a-zA-Z0-9_-]+/); print substr($0, RSTART, RLENGTH) + } + ' "$config_file" +} + +# =================================================================== +# Synchronization Functions +# =================================================================== + +# Function to sync gradle.properties +sync_gradle_properties() { + log_section "Syncing gradle.properties" + + local gradle_file="$PROJECT_ROOT/gradle.properties" + local backup_file="${gradle_file}.bak.$(date +%Y%m%d_%H%M%S)" + + # Create backup + cp "$gradle_file" "$backup_file" + log_info "Created backup: $(basename "$backup_file")" + + # Extract port values from central config + local gateway_port=$(get_config_value "ports" "api-gateway") + local consul_port=$(get_config_value "ports" "consul") + local ping_port=$(get_config_value "ports" "ping-service") + local members_port=$(get_config_value "ports" "members-service") + local horses_port=$(get_config_value "ports" "horses-service") + local events_port=$(get_config_value "ports" "events-service") + + # Update gradle.properties with centralized values + sed -i.tmp \ + -e "s/^infrastructure\.gateway\.port=.*/infrastructure.gateway.port=${gateway_port}/" \ + -e "s/^infrastructure\.consul\.port=.*/infrastructure.consul.port=${consul_port}/" \ + -e "s/^services\.port\.start=.*/services.port.start=${ping_port}/" \ + -e "s/^services\.port\.ping=.*/services.port.ping=${ping_port}/" \ + -e "s/^services\.port\.members=.*/services.port.members=${members_port}/" \ + -e "s/^services\.port\.horses=.*/services.port.horses=${horses_port}/" \ + -e "s/^services\.port\.events=.*/services.port.events=${events_port}/" \ + "$gradle_file" + + rm -f "${gradle_file}.tmp" + log_success "Updated gradle.properties with centralized ports" +} + +# Function to sync Docker Compose files +sync_docker_compose_files() { + log_section "Syncing Docker Compose files" + + local compose_files=( + "$PROJECT_ROOT/docker-compose.yml" + "$PROJECT_ROOT/docker-compose.services.yml" + "$PROJECT_ROOT/docker-compose.clients.yml" + ) + + # Extract values from central config + local gateway_port=$(get_config_value "ports" "api-gateway") + local ping_port=$(get_config_value "ports" "ping-service") + local members_port=$(get_config_value "ports" "members-service") + local horses_port=$(get_config_value "ports" "horses-service") + local events_port=$(get_config_value "ports" "events-service") + local masterdata_port=$(get_config_value "ports" "masterdata-service") + local auth_port=$(get_config_value "ports" "auth-server") + local consul_port=$(get_config_value "ports" "consul") + local redis_port=$(get_config_value "ports" "redis") + local postgres_port=$(get_config_value "ports" "postgres") + local prometheus_port=$(get_config_value "ports" "prometheus") + local grafana_port=$(get_config_value "ports" "grafana") + local keycloak_port=$(get_config_value "ports" "keycloak") + local web_app_port=$(get_config_value "ports" "web-app") + + # Extract Spring profiles + local infrastructure_profile=$(get_config_value "spring-profiles.defaults" "infrastructure") + local services_profile=$(get_config_value "spring-profiles.defaults" "services") + local clients_profile=$(get_config_value "spring-profiles.defaults" "clients") + + for compose_file in "${compose_files[@]}"; do + if [[ -f "$compose_file" ]]; then + local backup_file="${compose_file}.bak.$(date +%Y%m%d_%H%M%S)" + cp "$compose_file" "$backup_file" + log_info "Created backup: $(basename "$backup_file")" + + # Update port references + sed -i.tmp \ + -e "s/\${GATEWAY_PORT:-[0-9]*}/\${GATEWAY_PORT:-${gateway_port}}/g" \ + -e "s/\${PING_SERVICE_PORT:-[0-9]*}/\${PING_SERVICE_PORT:-${ping_port}}/g" \ + -e "s/\${MEMBERS_SERVICE_PORT:-[0-9]*}/\${MEMBERS_SERVICE_PORT:-${members_port}}/g" \ + -e "s/\${HORSES_SERVICE_PORT:-[0-9]*}/\${HORSES_SERVICE_PORT:-${horses_port}}/g" \ + -e "s/\${EVENTS_SERVICE_PORT:-[0-9]*}/\${EVENTS_SERVICE_PORT:-${events_port}}/g" \ + -e "s/\${MASTERDATA_SERVICE_PORT:-[0-9]*}/\${MASTERDATA_SERVICE_PORT:-${masterdata_port}}/g" \ + -e "s/\${AUTH_SERVICE_PORT:-[0-9]*}/\${AUTH_SERVICE_PORT:-${auth_port}}/g" \ + -e "s/\${CONSUL_PORT:-[0-9]*}/\${CONSUL_PORT:-${consul_port}}/g" \ + -e "s/\${REDIS_PORT:-[0-9]*}/\${REDIS_PORT:-${redis_port}}/g" \ + -e "s/\${PROMETHEUS_PORT:-[0-9]*}/\${PROMETHEUS_PORT:-${prometheus_port}}/g" \ + -e "s/\${GRAFANA_PORT:-[0-9]*}/\${GRAFANA_PORT:-${grafana_port}}/g" \ + -e "s/:[0-9]*\":${postgres_port}/:${postgres_port}:${postgres_port}/g" \ + -e "s/:[0-9]*\":${redis_port}/:${redis_port}:${redis_port}/g" \ + -e "s/\${DOCKER_SPRING_PROFILES_DEFAULT:-[^}]*}/\${DOCKER_SPRING_PROFILES_DEFAULT:-${infrastructure_profile}}/g" \ + -e "s/\${DOCKER_SPRING_PROFILES_DOCKER:-[^}]*}/\${DOCKER_SPRING_PROFILES_DOCKER:-${services_profile}}/g" \ + "$compose_file" + + rm -f "${compose_file}.tmp" + log_success "Updated $(basename "$compose_file")" + else + log_warning "File not found: $(basename "$compose_file")" + fi + done +} + +# Function to sync environment files +sync_environment_files() { + log_section "Syncing Environment Files" + + local env_template="$PROJECT_ROOT/config/.env.template" + + if [[ -f "$env_template" ]]; then + local backup_file="${env_template}.bak.$(date +%Y%m%d_%H%M%S)" + cp "$env_template" "$backup_file" + log_info "Created backup: $(basename "$backup_file")" + + # Extract all port values + local gateway_port=$(get_config_value "ports" "api-gateway") + local ping_port=$(get_config_value "ports" "ping-service") + local members_port=$(get_config_value "ports" "members-service") + local horses_port=$(get_config_value "ports" "horses-service") + local events_port=$(get_config_value "ports" "events-service") + local masterdata_port=$(get_config_value "ports" "masterdata-service") + local auth_port=$(get_config_value "ports" "auth-server") + local consul_port=$(get_config_value "ports" "consul") + local redis_port=$(get_config_value "ports" "redis") + local postgres_port=$(get_config_value "ports" "postgres") + local prometheus_port=$(get_config_value "ports" "prometheus") + local grafana_port=$(get_config_value "ports" "grafana") + + # Update .env.template with centralized values + sed -i.tmp \ + -e "s/^GATEWAY_PORT=.*/GATEWAY_PORT=${gateway_port}/" \ + -e "s/^PING_SERVICE_PORT=.*/PING_SERVICE_PORT=${ping_port}/" \ + -e "s/^MEMBERS_SERVICE_PORT=.*/MEMBERS_SERVICE_PORT=${members_port}/" \ + -e "s/^HORSES_SERVICE_PORT=.*/HORSES_SERVICE_PORT=${horses_port}/" \ + -e "s/^EVENTS_SERVICE_PORT=.*/EVENTS_SERVICE_PORT=${events_port}/" \ + -e "s/^MASTERDATA_SERVICE_PORT=.*/MASTERDATA_SERVICE_PORT=${masterdata_port}/" \ + -e "s/^AUTH_SERVICE_PORT=.*/AUTH_SERVICE_PORT=${auth_port}/" \ + -e "s/^CONSUL_PORT=.*/CONSUL_PORT=${consul_port}/" \ + -e "s/^REDIS_PORT=.*/REDIS_PORT=${redis_port}/" \ + -e "s/^DB_PORT=.*/DB_PORT=${postgres_port}/" \ + -e "s/^PROMETHEUS_PORT=.*/PROMETHEUS_PORT=${prometheus_port}/" \ + -e "s/^GRAFANA_PORT=.*/GRAFANA_PORT=${grafana_port}/" \ + "$env_template" + + rm -f "${env_template}.tmp" + log_success "Updated .env.template" + else + log_warning ".env.template not found" + fi +} + +# Function to sync Docker build arguments +sync_docker_build_args() { + log_section "Syncing Docker Build Arguments" + + local build_args_dir="$PROJECT_ROOT/docker/build-args" + + # Extract Spring profiles from central config + local infrastructure_profile=$(get_config_value "spring-profiles.defaults" "infrastructure") + local services_profile=$(get_config_value "spring-profiles.defaults" "services") + local clients_profile=$(get_config_value "spring-profiles.defaults" "clients") + + # Update services.env + local services_env="$build_args_dir/services.env" + if [[ -f "$services_env" ]]; then + local backup_file="${services_env}.bak.$(date +%Y%m%d_%H%M%S)" + cp "$services_env" "$backup_file" + + # Extract port values + local ping_port=$(get_config_value "ports" "ping-service") + local members_port=$(get_config_value "ports" "members-service") + local horses_port=$(get_config_value "ports" "horses-service") + local events_port=$(get_config_value "ports" "events-service") + local masterdata_port=$(get_config_value "ports" "masterdata-service") + + sed -i.tmp \ + -e "s/^SPRING_PROFILES_ACTIVE=.*/SPRING_PROFILES_ACTIVE=${services_profile}/" \ + -e "s/^PING_SERVICE_PORT=.*/PING_SERVICE_PORT=${ping_port}/" \ + -e "s/^MEMBERS_SERVICE_PORT=.*/MEMBERS_SERVICE_PORT=${members_port}/" \ + -e "s/^HORSES_SERVICE_PORT=.*/HORSES_SERVICE_PORT=${horses_port}/" \ + -e "s/^EVENTS_SERVICE_PORT=.*/EVENTS_SERVICE_PORT=${events_port}/" \ + -e "s/^MASTERDATA_SERVICE_PORT=.*/MASTERDATA_SERVICE_PORT=${masterdata_port}/" \ + "$services_env" + + rm -f "${services_env}.tmp" + log_success "Updated services.env" + fi + + # Update infrastructure.env + local infrastructure_env="$build_args_dir/infrastructure.env" + if [[ -f "$infrastructure_env" ]]; then + local backup_file="${infrastructure_env}.bak.$(date +%Y%m%d_%H%M%S)" + cp "$infrastructure_env" "$backup_file" + + # Extract port values + local gateway_port=$(get_config_value "ports" "api-gateway") + local auth_port=$(get_config_value "ports" "auth-server") + local monitoring_port=$(get_config_value "ports" "monitoring-server") + local consul_port=$(get_config_value "ports" "consul") + + sed -i.tmp \ + -e "s/^SPRING_PROFILES_ACTIVE=.*/SPRING_PROFILES_ACTIVE=${infrastructure_profile}/" \ + -e "s/^GATEWAY_PORT=.*/GATEWAY_PORT=${gateway_port}/" \ + -e "s/^AUTH_SERVER_PORT=.*/AUTH_SERVER_PORT=${auth_port}/" \ + -e "s/^MONITORING_SERVER_PORT=.*/MONITORING_SERVER_PORT=${monitoring_port}/" \ + -e "s/^CONSUL_PORT=.*/CONSUL_PORT=${consul_port}/" \ + "$infrastructure_env" + + rm -f "${infrastructure_env}.tmp" + log_success "Updated infrastructure.env" + fi + + # Update clients.env + local clients_env="$build_args_dir/clients.env" + if [[ -f "$clients_env" ]]; then + local backup_file="${clients_env}.bak.$(date +%Y%m%d_%H%M%S)" + cp "$clients_env" "$backup_file" + + # Extract port values + local web_app_port=$(get_config_value "ports" "web-app") + local vnc_port=$(get_config_value "ports" "desktop-app-vnc") + local novnc_port=$(get_config_value "ports" "desktop-app-novnc") + + sed -i.tmp \ + -e "s/^WEB_APP_PORT=.*/WEB_APP_PORT=${web_app_port}/" \ + -e "s/^DESKTOP_APP_VNC_PORT=.*/DESKTOP_APP_VNC_PORT=${vnc_port}/" \ + -e "s/^DESKTOP_APP_NOVNC_PORT=.*/DESKTOP_APP_NOVNC_PORT=${novnc_port}/" \ + "$clients_env" + + rm -f "${clients_env}.tmp" + log_success "Updated clients.env" + fi +} + +# Function to sync monitoring configuration +sync_monitoring_config() { + log_section "Syncing Monitoring Configuration" + + local prometheus_config="$PROJECT_ROOT/config/monitoring/prometheus.dev.yml" + + if [[ -f "$prometheus_config" ]]; then + local backup_file="${prometheus_config}.bak.$(date +%Y%m%d_%H%M%S)" + cp "$prometheus_config" "$backup_file" + log_info "Created backup: $(basename "$backup_file")" + + # Extract service ports + local ping_port=$(get_config_value "ports" "ping-service") + local members_port=$(get_config_value "ports" "members-service") + local horses_port=$(get_config_value "ports" "horses-service") + local events_port=$(get_config_value "ports" "events-service") + local masterdata_port=$(get_config_value "ports" "masterdata-service") + local gateway_port=$(get_config_value "ports" "api-gateway") + + # Update Prometheus targets with centralized ports + sed -i.tmp \ + -e "s/ping-service:[0-9]*/ping-service:${ping_port}/g" \ + -e "s/members-service:[0-9]*/members-service:${members_port}/g" \ + -e "s/horses-service:[0-9]*/horses-service:${horses_port}/g" \ + -e "s/events-service:[0-9]*/events-service:${events_port}/g" \ + -e "s/masterdata-service:[0-9]*/masterdata-service:${masterdata_port}/g" \ + -e "s/api-gateway:[0-9]*/api-gateway:${gateway_port}/g" \ + "$prometheus_config" + + rm -f "${prometheus_config}.tmp" + log_success "Updated Prometheus configuration" + else + log_warning "Prometheus config not found: $prometheus_config" + fi +} + +# Function to sync test scripts +sync_test_scripts() { + log_section "Syncing Test Scripts" + + local test_scripts=( + "$PROJECT_ROOT/scripts/test/integration-test.sh" + "$PROJECT_ROOT/scripts/test/test_gateway.sh" + "$PROJECT_ROOT/scripts/test/test-monitoring.sh" + ) + + # Extract port values + local ping_port=$(get_config_value "ports" "ping-service") + local gateway_port=$(get_config_value "ports" "api-gateway") + local consul_port=$(get_config_value "ports" "consul") + local prometheus_port=$(get_config_value "ports" "prometheus") + local grafana_port=$(get_config_value "ports" "grafana") + + for script_file in "${test_scripts[@]}"; do + if [[ -f "$script_file" ]]; then + local backup_file="${script_file}.bak.$(date +%Y%m%d_%H%M%S)" + cp "$script_file" "$backup_file" + + # Update port references in test scripts + sed -i.tmp \ + -e "s/:${ping_port}[^0-9]/:${ping_port}/g" \ + -e "s/localhost:[0-9]*\/actuator/localhost:${ping_port}\/actuator/g" \ + -e "s/ping-service:[0-9]*/ping-service:${ping_port}/g" \ + -e "s/api-gateway:[0-9]*/api-gateway:${gateway_port}/g" \ + -e "s/consul:[0-9]*/consul:${consul_port}/g" \ + -e "s/prometheus:[0-9]*/prometheus:${prometheus_port}/g" \ + -e "s/grafana:[0-9]*/grafana:${grafana_port}/g" \ + "$script_file" + + rm -f "${script_file}.tmp" + log_success "Updated $(basename "$script_file")" + else + log_warning "Test script not found: $(basename "$script_file")" + fi + done +} + +# =================================================================== +# Validation Functions +# =================================================================== + +# Function to validate central configuration +validate_central_config() { + log_section "Validating Central Configuration" + + if [[ ! -f "$CENTRAL_CONFIG" ]]; then + log_error "Central configuration file not found: $CENTRAL_CONFIG" + return 1 + fi + + log_info "Validating TOML syntax..." + + # Basic TOML validation (check for common syntax errors) + local validation_errors=0 + + # Check for unclosed brackets + if ! awk '/^\[.*[^]]$/ { print "Unclosed bracket on line " NR ": " $0; exit 1 }' "$CENTRAL_CONFIG"; then + ((validation_errors++)) + fi + + # Check for duplicate sections + local duplicate_sections=$(awk '/^\[.*\]$/ { + section = $0 + count[section]++ + } + END { + for (s in count) { + if (count[s] > 1) + print s + } + }' "$CENTRAL_CONFIG") + if [[ -n "$duplicate_sections" ]]; then + log_warning "Duplicate sections found: $duplicate_sections" + ((validation_errors++)) + fi + + if [[ $validation_errors -eq 0 ]]; then + log_success "Central configuration is valid" + return 0 + else + log_error "Central configuration has $validation_errors validation errors" + return 1 + fi +} + +# Function to show current configuration status +show_config_status() { + log_section "Configuration Status Report" + + log_info "Current port assignments from central config:" + local services=("ping-service" "members-service" "horses-service" "events-service" "masterdata-service" "api-gateway" "auth-server") + + for service in "${services[@]}"; do + local port=$(get_config_value "ports" "$service") + echo " ${service}: ${port}" + done + + log_info "Current Spring profile defaults:" + local infrastructure_profile=$(get_config_value "spring-profiles.defaults" "infrastructure") + local services_profile=$(get_config_value "spring-profiles.defaults" "services") + local clients_profile=$(get_config_value "spring-profiles.defaults" "clients") + + echo " Infrastructure: ${infrastructure_profile}" + echo " Services: ${services_profile}" + echo " Clients: ${clients_profile}" +} + +# =================================================================== +# Main Functions +# =================================================================== + +# Function to perform full synchronization +sync_all() { + log_section "Full Configuration Synchronization" + log_info "Syncing all configuration files from central.toml..." + + # Validate central configuration first + validate_central_config || return 1 + + # Perform all synchronizations + sync_gradle_properties || return 1 + sync_docker_compose_files || return 1 + sync_environment_files || return 1 + sync_docker_build_args || return 1 + sync_monitoring_config || return 1 + sync_test_scripts || return 1 + + log_success "All configuration files synchronized successfully!" + show_config_status +} + +# Function to show help +show_help() { + cat << EOF +Configuration Synchronization Utility + +USAGE: + $0 [COMMAND] [OPTIONS] + +COMMANDS: + sync Synchronize all configuration files + validate Validate central configuration file + status Show current configuration status + gradle Sync gradle.properties only + compose Sync Docker Compose files only + env Sync environment files only + docker-args Sync Docker build arguments only + monitoring Sync monitoring configuration only + tests Sync test scripts only + +OPTIONS: + -h, --help Show this help message + -v, --verbose Enable verbose output + --dry-run Show what would be changed without making changes + +EXAMPLES: + $0 sync # Sync all configuration files + $0 validate # Validate central.toml syntax + $0 status # Show current port and profile assignments + $0 gradle # Sync gradle.properties only + +This script reads from config/central.toml and updates all dependent +configuration files to eliminate redundancy across 38+ port definitions +and 72+ Spring profile configurations. + +Configuration files that will be synchronized: + - gradle.properties + - docker-compose*.yml files + - config/.env.template + - docker/build-args/*.env files + - config/monitoring/*.yml files + - scripts/test/*.sh files + +All original files are backed up before modification. +EOF +} + +# Main execution function +main() { + local command="${1:-sync}" + local verbose=false + local dry_run=false + + # Parse options + while [[ $# -gt 0 ]]; do + case $1 in + -h|--help) + show_help + exit 0 + ;; + -v|--verbose) + verbose=true + shift + ;; + --dry-run) + dry_run=true + shift + ;; + -*) + log_error "Unknown option: $1" + show_help + exit 1 + ;; + *) + command="$1" + shift + ;; + esac + done + + # Set verbose mode + if [[ "$verbose" == "true" ]]; then + set -x + fi + + # Handle dry run + if [[ "$dry_run" == "true" ]]; then + log_warning "DRY RUN MODE - No files will be modified" + # In a real implementation, you would add dry-run logic here + fi + + # Change to project root + cd "$PROJECT_ROOT" + + # Execute command + case "$command" in + "sync"|"all") + sync_all + ;; + "validate") + validate_central_config + ;; + "status") + show_config_status + ;; + "gradle") + validate_central_config && sync_gradle_properties + ;; + "compose") + validate_central_config && sync_docker_compose_files + ;; + "env") + validate_central_config && sync_environment_files + ;; + "docker-args") + validate_central_config && sync_docker_build_args + ;; + "monitoring") + validate_central_config && sync_monitoring_config + ;; + "tests") + validate_central_config && sync_test_scripts + ;; + *) + log_error "Unknown command: $command" + show_help + exit 1 + ;; + esac + + log_success "Configuration synchronization completed!" +} + +# Run main function with all arguments +main "$@" diff --git a/scripts/docker-build.sh b/scripts/docker-build.sh index 98df7025..4429711b 100755 --- a/scripts/docker-build.sh +++ b/scripts/docker-build.sh @@ -42,6 +42,7 @@ load_env_files() { # Load global environment variables if [[ -f "$BUILD_ARGS_DIR/global.env" ]]; then + # shellcheck disable=SC2046 export $(grep -v '^#' "$BUILD_ARGS_DIR/global.env" | xargs) print_info "✓ Loaded global.env" else @@ -52,6 +53,7 @@ load_env_files() { # Load category-specific environment variables for env_file in services.env clients.env infrastructure.env; do if [[ -f "$BUILD_ARGS_DIR/$env_file" ]]; then + # shellcheck disable=SC2046 export $(grep -v '^#' "$BUILD_ARGS_DIR/$env_file" | xargs) print_info "✓ Loaded $env_file" else diff --git a/scripts/docker-versions-update.sh b/scripts/docker-versions-update.sh index 8b0ff870..54717ec4 100755 --- a/scripts/docker-versions-update.sh +++ b/scripts/docker-versions-update.sh @@ -63,13 +63,21 @@ sync_to_env_files() { print_info "Syncing versions.toml to environment files..." # Get current versions from TOML + # shellcheck disable=SC2155 local gradle_version=$(get_version "gradle") + # shellcheck disable=SC2155 local java_version=$(get_version "java") + # shellcheck disable=SC2155 local node_version=$(get_version "node") + # shellcheck disable=SC2155 local nginx_version=$(get_version "nginx") + # shellcheck disable=SC2155 local app_version=$(get_version "app-version") + # shellcheck disable=SC2155 local spring_default=$(get_version "spring-profiles-default") + # shellcheck disable=SC2155 local spring_docker=$(get_version "spring-profiles-docker") + # shellcheck disable=SC2155 local alpine_version=$(get_version "alpine") local prometheus_version=$(get_version "prometheus") local grafana_version=$(get_version "grafana") diff --git a/scripts/test/integration-test.sh b/scripts/test/integration-test.sh index 3560151d..617806b7 100755 --- a/scripts/test/integration-test.sh +++ b/scripts/test/integration-test.sh @@ -20,22 +20,26 @@ source "$SCRIPT_DIR/../utils/common.sh" || { # ============================================================================= readonly COMPOSE_FILES="-f docker-compose.yml -f docker-compose.services.yml -f docker-compose.clients.yml" +# shellcheck disable=SC2034 readonly TIMEOUT_SECONDS=300 +# shellcheck disable=SC2034 readonly HEALTH_CHECK_INTERVAL=10 readonly MAX_RETRIES=30 # Project root and Docker configuration +# shellcheck disable=SC2155 readonly PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" readonly DOCKER_DIR="$PROJECT_ROOT/docker" readonly BUILD_ARGS_DIR="$DOCKER_DIR/build-args" # Service endpoints (from common configuration) +# shellcheck disable=SC2034 readonly SERVICES_CONFIG=( "postgres:5432:PostgreSQL:pg_isready -U meldestelle" "redis:6379:Redis:redis-cli ping" "consul:8500:Consul:http://localhost:8500/v1/status/leader" - "api-gateway:8081:API Gateway:http://localhost:8081/actuator/health" - "ping-service:8082:Ping Service:http://localhost:8082/actuator/health" + "api-gateway:8081:API Gateway:http://localhost:8082/actuator/health" + "ping-service:8082Ping Service:http://localhost:8082actuator/health" ) # Integration with central Docker version management @@ -89,6 +93,7 @@ check_service_logs() { log_info "Checking $service_name logs for errors..." # Get last 50 lines of logs + # shellcheck disable=SC2155 local logs=$(docker logs --tail 50 "$container_name" 2>&1 || echo "") # Check for common error patterns @@ -113,6 +118,7 @@ test_infrastructure_services() { # Start infrastructure services only log_info "Starting infrastructure services..." + # shellcheck disable=SC2164 cd "$PROJECT_ROOT" docker compose -f docker-compose.yml up -d @@ -153,6 +159,7 @@ test_application_services() { # Start application services log_info "Starting application services..." + # shellcheck disable=SC2164 cd "$PROJECT_ROOT" docker compose $COMPOSE_FILES up -d @@ -162,11 +169,11 @@ test_application_services() { # Test API Gateway log_info "Testing API Gateway..." - wait_for_service_with_retry "API Gateway" "http_health_check http://localhost:8081/actuator/health" || return 1 + wait_for_service_with_retry "API Gateway" "http_health_check http://localhost:8082/actuator/health" || return 1 # Test Ping Service log_info "Testing Ping Service..." - wait_for_service_with_retry "Ping Service" "http_health_check http://localhost:8082/actuator/health" || return 1 + wait_for_service_with_retry "Ping Service" "http_health_check http://localhost:8082actuator/health" || return 1 log_success "All application services are healthy!" } @@ -177,6 +184,7 @@ test_client_applications() { # Start client applications log_info "Starting client applications..." + # shellcheck disable=SC2164 cd "$PROJECT_ROOT" docker compose -f docker-compose.yml -f docker-compose.clients.yml up -d @@ -203,7 +211,7 @@ test_network_connectivity() { log_info "Testing service-to-service connectivity..." # Test API Gateway can reach backend services - if docker exec meldestelle-api-gateway curl -f -s --max-time 5 http://ping-service:8082/actuator/health > /dev/null 2>&1; then + if docker exec meldestelle-api-gateway curl -f -s --max-time 5 http://ping-service:8082actuator/health > /dev/null 2>&1; then log_success "API Gateway can reach Ping Service" else log_error "API Gateway cannot reach Ping Service" @@ -235,9 +243,11 @@ generate_integration_report() { # Performance metrics log_info "Performance Metrics:" + # shellcheck disable=SC2046 docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}" $(docker ps -q --filter "name=meldestelle") 2>/dev/null || true # Resource usage summary + # shellcheck disable=SC2155 local containers=$(docker ps --filter "name=meldestelle" --format "{{.Names}}" | wc -l) log_info "Total running containers: $containers" @@ -250,10 +260,11 @@ cleanup() { log_section "Cleaning up test environment" log_info "Stopping and removing all test containers..." + # shellcheck disable=SC2164 cd "$PROJECT_ROOT" # Use the same files to tear down the environment - docker compose $COMPOSE_FILES down --remove-orphans -v 2>/dev/null || true + docker compose "$COMPOSE_FILES" down --remove-orphans -v 2>/dev/null || true # Remove network if it exists docker network rm meldestelle-network >/dev/null 2>&1 || true @@ -270,8 +281,9 @@ run_full_integration_test() { # Start ALL services using all compose files log_info "Starting full environment with all services..." + # shellcheck disable=SC2164 cd "$PROJECT_ROOT" - docker compose $COMPOSE_FILES up -d + docker compose "$COMPOSE_FILES" up -d # Give services time to initialize log_info "Waiting 60 seconds for all services to initialize..." diff --git a/scripts/test/test_gateway.sh b/scripts/test/test_gateway.sh index bb7a2f4e..51a7985d 100755 --- a/scripts/test/test_gateway.sh +++ b/scripts/test/test_gateway.sh @@ -39,7 +39,7 @@ readonly TEST_ENDPOINTS=( # Service discovery endpoints readonly SERVICE_ENDPOINTS=( "masterdata:8081" - "horses:8082" + "horses:8082 "events:8083" "members:8084" )