diff --git a/docker-compose.yml b/docker-compose.yml index 37cab818..5ab98e49 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -245,7 +245,9 @@ services: - reverse_proxy sdk_storage: - build: ./sdk_storage + build: + context: ../sdk_storage + dockerfile: Dockerfile container_name: sdk-storage restart: unless-stopped entrypoint: > @@ -258,35 +260,35 @@ services: - sdk_storage_data:/app/storage # Service interne: aucun port exposé - sdk_signer: - build: - context: ./sdk_signer - dockerfile: ../dockerfiles/sdk_signer.Dockerfile - container_name: sdk-signer - restart: unless-stopped - user: "0:0" - environment: - - PORT=9090 - - API_KEY=dev-change-me - - RELAY_URLS=ws://sdk_relay_1:8090 - - LOG_LEVEL=info - - DATABASE_PATH=/app/data/server.db - entrypoint: > - /bin/sh -lc "mkdir -p /app/data && chown -R nodejs:nodejs /app/data || true; \ - apk add --no-cache busybox-extras >/dev/null 2>&1 || true; \ - mkdir -p /tmp/health && printf 'ok' > /tmp/health/health; \ - ( /usr/sbin/httpd -f -h /tmp/health -p 9092 ) & \ - exec node -r ts-node/register/transpile-only src/index.ts" - networks: - btcnet: - aliases: - - sdk_signer - depends_on: - sdk_relay_1: - condition: service_started - volumes: - - sdk_signer_data:/app/data - # Service interne: aucun port exposé + # sdk_signer: + # build: + # context: ../sdk_signer + # dockerfile: Dockerfile + # container_name: sdk-signer + # restart: unless-stopped + # user: "0:0" + # environment: + # - PORT=9090 + # - API_KEY=dev-change-me + # - RELAY_URLS=ws://sdk_relay_1:8090 + # - LOG_LEVEL=info + # - DATABASE_PATH=/app/data/server.db + # entrypoint: > + # /bin/sh -lc "mkdir -p /app/data && chown -R nodejs:nodejs /app/data || true; \ + # apk add --no-cache busybox-extras >/dev/null 2>&1 || true; \ + # mkdir -p /tmp/health && printf 'ok' > /tmp/health/health; \ + # ( /usr/sbin/httpd -f -h /tmp/health -p 9092 ) & \ + # exec node -r ts-node/register/transpile-only src/index.ts" + # networks: + # btcnet: + # aliases: + # - sdk_signer + # depends_on: + # sdk_relay_1: + # condition: service_started + # volumes: + # - sdk_signer_data:/app/data + # # Service interne: aucun port exposé volumes: bitcoin_data: diff --git a/docs/scripts/manage_services.md b/docs/scripts/manage_services.md new file mode 100644 index 00000000..fd306d56 --- /dev/null +++ b/docs/scripts/manage_services.md @@ -0,0 +1,179 @@ +# Script de Gestion des Services 4NK Node + +## Description + +Le script `manage_services.sh` est un outil de gestion complet pour arrêter, nettoyer et relancer tous les services de l'infrastructure 4NK Node. Il utilise Docker Compose pour orchestrer les services et fournit des fonctionnalités de nettoyage et de surveillance. + +## Emplacement + +``` +4NK_dev/4NK_node/scripts/manage_services.sh +``` + +## Fonctionnalités + +### Commandes Disponibles + +| Commande | Description | +|----------|-------------| +| `stop` | Arrêter tous les services | +| `clean` | Arrêter et nettoyer les conteneurs | +| `clean-all` | Arrêter, nettoyer conteneurs et volumes | +| `start` | Démarrer tous les services | +| `restart` | Arrêter, nettoyer et redémarrer (défaut) | +| `status` | Afficher le statut des services | +| `logs` | Afficher les logs en temps réel | +| `help` | Afficher l'aide | + +### Services Gérés + +Le script gère les services suivants définis dans `docker-compose.yml` : + +- **tor-proxy** : Proxy Tor pour l'anonymat +- **bitcoin-signet** : Nœud Bitcoin Core (signet) +- **blindbit-oracle** : Oracle BlindBit +- **sdk_relay_1/2/3** : Trois instances de relais SDK +- **sdk-storage** : Service de stockage +- **4nk-ihm-client** : Interface utilisateur +- **4nk-reverse-proxy** : Proxy inverse Nginx + +## Utilisation + +### Redémarrage Complet (Recommandé) + +```bash +./scripts/manage_services.sh +# ou +./scripts/manage_services.sh restart +``` + +### Arrêt des Services + +```bash +./scripts/manage_services.sh stop +``` + +### Nettoyage Complet + +```bash +./scripts/manage_services.sh clean-all +``` + +**⚠️ Attention** : Cette commande supprime TOUTES les données persistantes ! + +### Vérification du Statut + +```bash +./scripts/manage_services.sh status +``` + +### Surveillance des Logs + +```bash +./scripts/manage_services.sh logs +``` + +## Fonctionnalités Avancées + +### Nettoyage Intelligent + +Le script effectue un nettoyage intelligent en supprimant : +- Conteneurs arrêtés +- Images non utilisées +- Volumes non utilisés +- Réseaux non utilisés + +### Attente des Services Critiques + +Le script attend automatiquement que les services critiques soient prêts : +- Tor Proxy +- Bitcoin Core +- BlindBit Oracle + +### Gestion des Erreurs + +- Vérification de la présence de Docker +- Vérification du daemon Docker +- Vérification de Docker Compose +- Arrêt en cas d'erreur (`set -e`) + +## Configuration + +### Variables d'Environnement + +Le script utilise les variables suivantes : + +```bash +PROJECT_NAME="4NK Node" +PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +COMPOSE_FILE="$PROJECT_DIR/docker-compose.yml" +``` + +### Couleurs d'Affichage + +Le script utilise des couleurs pour améliorer la lisibilité : +- 🔵 Bleu : En-têtes +- 🟢 Vert : Succès +- 🟡 Jaune : Avertissements +- 🔴 Rouge : Erreurs +- 🟣 Violet : Informations +- 🔵 Cyan : Étapes en cours + +## Dépannage + +### Problèmes Courants + +1. **Docker non installé** + ``` + ❌ Docker n'est pas installé ou n'est pas dans le PATH + ``` + +2. **Daemon Docker non démarré** + ``` + ❌ Docker daemon n'est pas en cours d'exécution + ``` + +3. **Docker Compose non disponible** + ``` + ❌ Docker Compose n'est pas installé ou n'est pas dans le PATH + ``` + +### Logs de Construction + +En cas de problème lors de la construction des images, utilisez : + +```bash +docker compose -f docker-compose.yml build --no-cache --progress=plain +``` + +## Notes Techniques + +### Services Temporairement Désactivés + +Le service `sdk_signer` est temporairement désactivé en raison de dépendances manquantes (module `../pkg/sdk_client`). + +### Volumes Persistants + +Les volumes suivants sont préservés lors du redémarrage : +- `4nk_node_bitcoin_data` +- `4nk_node_blindbit_data` +- `4nk_node_sdk_relay_1_data` +- `4nk_node_sdk_relay_2_data` +- `4nk_node_sdk_relay_3_data` +- `4nk_node_sdk_storage_data` +- `4nk_node_sdk_signer_data` + +### Réseau Docker + +Le script utilise le réseau `4nk_node_btcnet` pour la communication inter-services. + +## Historique des Modifications + +- **2025-08-29** : Création du script avec support Docker Compose v2 +- Correction des chemins de build pour sdk_storage et sdk_signer +- Désactivation temporaire du service sdk_signer +- Ajout de la documentation complète + +## Auteur + +Script créé pour l'infrastructure 4NK Node. diff --git a/scripts/manage_services.sh b/scripts/manage_services.sh new file mode 100755 index 00000000..482cf459 --- /dev/null +++ b/scripts/manage_services.sh @@ -0,0 +1,294 @@ +#!/bin/bash + +# ============================================================================= +# Script de Gestion des Services 4NK Node +# ============================================================================= +# Date: $(date) +# Description: Arrêter, nettoyer et relancer tous les services +# ============================================================================= + +set -e # Arrêter en cas d'erreur + +# ============================================================================= +# CONFIGURATION +# ============================================================================= + +# Couleurs pour l'affichage +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +PURPLE='\033[0;35m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + +# Configuration du projet +PROJECT_NAME="4NK Node" +PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +COMPOSE_FILE="$PROJECT_DIR/docker-compose.yml" + +# ============================================================================= +# FONCTIONS UTILITAIRES +# ============================================================================= + +print_header() { + echo -e "${BLUE}=============================================================================${NC}" + echo -e "${BLUE}$1${NC}" + echo -e "${BLUE}=============================================================================${NC}" +} + +print_step() { + echo -e "${CYAN}🔄 $1${NC}" +} + +print_success() { + echo -e "${GREEN}✅ $1${NC}" +} + +print_warning() { + echo -e "${YELLOW}⚠️ $1${NC}" +} + +print_error() { + echo -e "${RED}❌ $1${NC}" +} + +print_info() { + echo -e "${PURPLE}ℹ️ $1${NC}" +} + +wait_for_service() { + local service_name=$1 + local max_attempts=30 + local attempt=1 + + print_step "Attente du service $service_name..." + + while [ $attempt -le $max_attempts ]; do + if docker compose -f "$COMPOSE_FILE" ps "$service_name" | grep -q "Up"; then + print_success "Service $service_name est prêt" + return 0 + fi + + echo -n "." + sleep 2 + attempt=$((attempt + 1)) + done + + print_warning "Service $service_name n'est pas prêt après $max_attempts tentatives" + return 1 +} + +# ============================================================================= +# FONCTIONS PRINCIPALES +# ============================================================================= + +stop_all_services() { + print_header "ARRÊT DE TOUS LES SERVICES" + + if [ -f "$COMPOSE_FILE" ]; then + print_step "Arrêt des services Docker Compose..." + docker compose -f "$COMPOSE_FILE" down --timeout 30 + print_success "Services Docker Compose arrêtés" + else + print_warning "Fichier docker-compose.yml non trouvé" + fi + + # Arrêt des conteneurs individuels au cas où + print_step "Arrêt des conteneurs individuels..." + docker stop $(docker ps -q --filter "name=4nk" --filter "name=tor" --filter "name=bitcoin" --filter "name=blindbit" --filter "name=sdk" --filter "name=proxy") 2>/dev/null || true + print_success "Conteneurs individuels arrêtés" +} + +cleanup_containers() { + print_header "NETTOYAGE DES CONTENEURS" + + print_step "Suppression des conteneurs arrêtés..." + docker container prune -f + print_success "Conteneurs arrêtés supprimés" + + print_step "Suppression des images non utilisées..." + docker image prune -f + print_success "Images non utilisées supprimées" + + print_step "Nettoyage des volumes non utilisés..." + docker volume prune -f + print_success "Volumes non utilisés supprimés" + + print_step "Nettoyage des réseaux non utilisés..." + docker network prune -f + print_success "Réseaux non utilisés supprimés" +} + +cleanup_volumes() { + print_header "NETTOYAGE COMPLET DES VOLUMES" + + print_warning "Cette opération supprimera TOUTES les données persistantes !" + read -p "Êtes-vous sûr de vouloir continuer ? (y/N): " -n 1 -r + echo + + if [[ $REPLY =~ ^[Yy]$ ]]; then + print_step "Suppression des volumes 4NK..." + docker volume rm $(docker volume ls -q --filter "name=4nk_node") 2>/dev/null || true + print_success "Volumes 4NK supprimés" + else + print_info "Nettoyage des volumes annulé" + fi +} + +start_all_services() { + print_header "DÉMARRAGE DE TOUS LES SERVICES" + + if [ ! -f "$COMPOSE_FILE" ]; then + print_error "Fichier docker-compose.yml non trouvé dans $PROJECT_DIR" + exit 1 + fi + + print_step "Construction des images Docker..." + docker compose -f "$COMPOSE_FILE" build --no-cache + print_success "Images construites" + + print_step "Démarrage de tous les services..." + docker compose -f "$COMPOSE_FILE" up -d + print_success "Services démarrés" + + # Attente des services critiques + print_step "Attente des services critiques..." + wait_for_service "tor" + wait_for_service "bitcoin" + wait_for_service "blindbit" + + print_success "Services critiques prêts" +} + +show_status() { + print_header "STATUT DES SERVICES" + + echo "" + print_info "Conteneurs en cours d'exécution:" + docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep -E "(4nk|tor|bitcoin|blindbit|sdk|proxy)" || echo "Aucun conteneur 4NK en cours d'exécution" + + echo "" + print_info "Services Docker Compose:" + if [ -f "$COMPOSE_FILE" ]; then + docker compose -f "$COMPOSE_FILE" ps + else + print_warning "Fichier docker-compose.yml non trouvé" + fi + + echo "" + print_info "Volumes 4NK:" + docker volume ls --filter "name=4nk_node" + + echo "" + print_info "Réseaux 4NK:" + docker network ls --filter "name=4nk_node" +} + +show_logs() { + print_header "LOGS DES SERVICES" + + if [ -f "$COMPOSE_FILE" ]; then + docker compose -f "$COMPOSE_FILE" logs --tail=50 -f + else + print_error "Fichier docker-compose.yml non trouvé" + fi +} + +# ============================================================================= +# FONCTION PRINCIPALE +# ============================================================================= + +main() { + print_header "SCRIPT DE GESTION DES SERVICES $PROJECT_NAME" + print_info "Répertoire de travail: $PROJECT_DIR" + print_info "Fichier compose: $COMPOSE_FILE" + print_info "Date: $(date)" + + # Traitement des arguments + case "${1:-restart}" in + "stop") + stop_all_services + ;; + "clean") + stop_all_services + cleanup_containers + ;; + "clean-all") + stop_all_services + cleanup_containers + cleanup_volumes + ;; + "start") + start_all_services + ;; + "restart") + stop_all_services + cleanup_containers + start_all_services + ;; + "status") + show_status + ;; + "logs") + show_logs + ;; + "help"|"-h"|"--help") + echo "" + echo -e "${CYAN}Usage: $0 [COMMANDE]${NC}" + echo "" + echo -e "${GREEN}Commandes disponibles:${NC}" + echo -e " ${GREEN}stop${NC} Arrêter tous les services" + echo -e " ${GREEN}clean${NC} Arrêter et nettoyer les conteneurs" + echo -e " ${GREEN}clean-all${NC} Arrêter, nettoyer conteneurs et volumes" + echo -e " ${GREEN}start${NC} Démarrer tous les services" + echo -e " ${GREEN}restart${NC} Arrêter, nettoyer et redémarrer (défaut)" + echo -e " ${GREEN}status${NC} Afficher le statut des services" + echo -e " ${GREEN}logs${NC} Afficher les logs en temps réel" + echo -e " ${GREEN}help${NC} Afficher cette aide" + echo "" + echo -e "${CYAN}Exemples:${NC}" + echo -e " ${GREEN}$0${NC} Redémarrage complet" + echo -e " ${GREEN}$0 stop${NC} Arrêter tous les services" + echo -e " ${GREEN}$0 status${NC} Vérifier le statut" + echo "" + exit 0 + ;; + *) + print_error "Commande inconnue: $1" + print_info "Utilisez '$0 help' pour voir les commandes disponibles" + exit 1 + ;; + esac + + print_header "OPÉRATION TERMINÉE" + print_success "Gestion des services $PROJECT_NAME terminée !" +} + +# ============================================================================= +# VÉRIFICATIONS PRÉALABLES +# ============================================================================= + +# Vérification de Docker +if ! command -v docker &> /dev/null; then + print_error "Docker n'est pas installé ou n'est pas dans le PATH" + exit 1 +fi + +# Vérification que Docker daemon est en cours d'exécution +if ! docker info &> /dev/null; then + print_error "Docker daemon n'est pas en cours d'exécution" + exit 1 +fi + +# Vérification de Docker Compose +if ! docker compose version &> /dev/null; then + print_error "Docker Compose n'est pas installé ou n'est pas dans le PATH" + exit 1 +fi + +# ============================================================================= +# EXÉCUTION +# ============================================================================= + +main "$@" diff --git a/tests/scripts/test_manage_services.sh b/tests/scripts/test_manage_services.sh new file mode 100755 index 00000000..91f04e70 --- /dev/null +++ b/tests/scripts/test_manage_services.sh @@ -0,0 +1,328 @@ +#!/bin/bash + +# ============================================================================= +# Tests pour le Script de Gestion des Services 4NK Node +# ============================================================================= + +set -e + +# ============================================================================= +# CONFIGURATION +# ============================================================================= + +# Couleurs pour l'affichage +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Configuration des tests +SCRIPT_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../scripts" && pwd)/manage_services.sh" +TEST_DIR="/tmp/.4nk/test_manage_services_$(date +%s)" +PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" + +# ============================================================================= +# FONCTIONS UTILITAIRES +# ============================================================================= + +print_header() { + echo -e "${BLUE}=============================================================================${NC}" + echo -e "${BLUE}$1${NC}" + echo -e "${BLUE}=============================================================================${NC}" +} + +print_test() { + echo -e "${YELLOW}🧪 Test: $1${NC}" +} + +print_success() { + echo -e "${GREEN}✅ $1${NC}" +} + +print_error() { + echo -e "${RED}❌ $1${NC}" +} + +print_info() { + echo -e "${BLUE}ℹ️ $1${NC}" +} + +# ============================================================================= +# FONCTIONS DE TEST +# ============================================================================= + +test_script_exists() { + print_test "Vérification de l'existence du script" + + if [ -f "$SCRIPT_PATH" ]; then + print_success "Le script existe" + return 0 + else + print_error "Le script n'existe pas: $SCRIPT_PATH" + return 1 + fi +} + +test_script_executable() { + print_test "Vérification des permissions d'exécution" + + if [ -x "$SCRIPT_PATH" ]; then + print_success "Le script est exécutable" + return 0 + else + print_error "Le script n'est pas exécutable" + return 1 + fi +} + +test_help_command() { + print_test "Test de la commande help" + + if output=$(bash "$SCRIPT_PATH" help 2>&1); then + if echo "$output" | grep -q "Usage:"; then + print_success "Commande help fonctionne" + return 0 + else + print_error "Commande help ne retourne pas l'usage attendu" + return 1 + fi + else + print_error "Commande help échoue" + return 1 + fi +} + +test_invalid_command() { + print_test "Test d'une commande invalide" + + if output=$(bash "$SCRIPT_PATH" invalid_command 2>&1); then + print_error "Commande invalide devrait échouer" + return 1 + else + if echo "$output" | grep -q "Commande inconnue"; then + print_success "Commande invalide correctement rejetée" + return 0 + else + print_error "Message d'erreur inattendu pour commande invalide" + return 1 + fi + fi +} + +test_docker_requirements() { + print_test "Vérification des prérequis Docker" + + # Test Docker + if ! command -v docker &> /dev/null; then + print_error "Docker n'est pas installé" + return 1 + fi + + # Test Docker daemon + if ! docker info &> /dev/null; then + print_error "Docker daemon n'est pas en cours d'exécution" + return 1 + fi + + # Test Docker Compose + if ! docker compose version &> /dev/null; then + print_error "Docker Compose n'est pas disponible" + return 1 + fi + + print_success "Tous les prérequis Docker sont satisfaits" + return 0 +} + +test_compose_file_exists() { + print_test "Vérification de l'existence du fichier docker-compose.yml" + + local compose_file="$PROJECT_DIR/docker-compose.yml" + + if [ -f "$compose_file" ]; then + print_success "Fichier docker-compose.yml trouvé" + return 0 + else + print_error "Fichier docker-compose.yml manquant: $compose_file" + return 1 + fi +} + +test_status_command() { + print_test "Test de la commande status" + + if output=$(bash "$SCRIPT_PATH" status 2>&1); then + if echo "$output" | grep -q "STATUT DES SERVICES"; then + print_success "Commande status fonctionne" + return 0 + else + print_error "Commande status ne retourne pas le format attendu" + return 1 + fi + else + print_error "Commande status échoue" + return 1 + fi +} + +test_stop_command() { + print_test "Test de la commande stop" + + # Vérifier d'abord s'il y a des services en cours + if ! docker compose -f "$PROJECT_DIR/docker-compose.yml" ps | grep -q "Up"; then + print_info "Aucun service en cours, test de stop ignoré" + return 0 + fi + + if output=$(bash "$SCRIPT_PATH" stop 2>&1); then + if echo "$output" | grep -q "Services Docker Compose arrêtés"; then + print_success "Commande stop fonctionne" + return 0 + else + print_error "Commande stop ne retourne pas le message attendu" + return 1 + fi + else + print_error "Commande stop échoue" + return 1 + fi +} + +test_clean_command() { + print_test "Test de la commande clean" + + if output=$(bash "$SCRIPT_PATH" clean 2>&1); then + if echo "$output" | grep -q "Nettoyage des conteneurs"; then + print_success "Commande clean fonctionne" + return 0 + else + print_error "Commande clean ne retourne pas le message attendu" + return 1 + fi + else + print_error "Commande clean échoue" + return 1 + fi +} + +# ============================================================================= +# FONCTION PRINCIPALE +# ============================================================================= + +run_tests() { + print_header "TESTS DU SCRIPT DE GESTION DES SERVICES 4NK NODE" + print_info "Script: $SCRIPT_PATH" + print_info "Projet: $PROJECT_DIR" + print_info "Date: $(date)" + + local total_tests=0 + local passed_tests=0 + local failed_tests=0 + + # Créer le répertoire de test + mkdir -p "$TEST_DIR" + + # Tests de base + ((total_tests++)) + if test_script_exists; then + ((passed_tests++)) + else + ((failed_tests++)) + fi + + ((total_tests++)) + if test_script_executable; then + ((passed_tests++)) + else + ((failed_tests++)) + fi + + ((total_tests++)) + if test_help_command; then + ((passed_tests++)) + else + ((failed_tests++)) + fi + + ((total_tests++)) + if test_invalid_command; then + ((passed_tests++)) + else + ((failed_tests++)) + fi + + # Tests des prérequis + ((total_tests++)) + if test_docker_requirements; then + ((passed_tests++)) + else + ((failed_tests++)) + fi + + ((total_tests++)) + if test_compose_file_exists; then + ((passed_tests++)) + else + ((failed_tests++)) + fi + + # Tests des commandes (si Docker est disponible) + if command -v docker &> /dev/null && docker info &> /dev/null; then + ((total_tests++)) + if test_status_command; then + ((passed_tests++)) + else + ((failed_tests++)) + fi + + ((total_tests++)) + if test_stop_command; then + ((passed_tests++)) + else + ((failed_tests++)) + fi + + ((total_tests++)) + if test_clean_command; then + ((passed_tests++)) + else + ((failed_tests++)) + fi + else + print_info "Tests des commandes Docker ignorés (Docker non disponible)" + fi + + # Résumé + print_header "RÉSUMÉ DES TESTS" + echo -e "${GREEN}Tests réussis: $passed_tests${NC}" + echo -e "${RED}Tests échoués: $failed_tests${NC}" + echo -e "${BLUE}Total: $total_tests${NC}" + + # Nettoyage + rm -rf "$TEST_DIR" + + if [ $failed_tests -eq 0 ]; then + print_success "Tous les tests sont passés !" + exit 0 + else + print_error "$failed_tests test(s) ont échoué" + exit 1 + fi +} + +# ============================================================================= +# EXÉCUTION +# ============================================================================= + +if [ "${1:-}" = "help" ] || [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ]; then + echo "Usage: $0 [help]" + echo "" + echo "Tests pour le script de gestion des services 4NK Node" + echo "" + echo "Options:" + echo " help, -h, --help Afficher cette aide" + exit 0 +fi + +run_tests