# [COURS] GUIDE MONGODB REPLICA SET - ULTRA DÉTAILLÉ POUR DÉBUTANTS

## [DOCS] PARTIE 1 : INTRODUCTION ET CONCEPTS FONDAMENTAUX

### * BIENVENUE DANS LE MONDE DE MONGODB REPLICA SET !

Ce guide est conçu pour un **étudiant en génie logiciel débutant** qui veut comprendre **TOUT** sur les Replica Sets MongoDB, de A à Z.

**Promesse de ce guide :**
[OK] Tu n'auras PLUS BESOIN de chercher ailleurs
[OK] Chaque concept est expliqué avec le POURQUOI et le COMMENT
[OK] Des exemples concrets à chaque étape
[OK] Des exercices pratiques pour consolider
[OK] Des scripts d'automatisation prêts à l'emploi

---

## [REFLEXION] QU'EST-CE QUE MONGODB ?

### Définition simple

**MongoDB** = Base de données NoSQL orientée documents

**Traduction en langage simple :**
Au lieu de stocker tes données dans des tableaux (comme MySQL), MongoDB les stocke dans des **documents JSON**.

**Analogie :**
```
Base de données SQL (MySQL)     vs     MongoDB (NoSQL)
═════════════════════════════          ═══════════════════════════

┌─────────────────────────┐            ┌──────────────────────────┐
│  Table: users           │            │  Collection: users       │
├─────────────────────────┤            ├──────────────────────────┤
│ id │ name    │ email    │            │  Document 1:             │
├────┼─────────┼──────────┤            │  {                       │
│ 1  │ Pierre  │ p@e.com  │            │    "_id": 1,             │
│ 2  │ Marie   │ m@e.com  │            │    "name": "Pierre",     │
└────┴─────────┴──────────┘            │    "email": "p@e.com",   │
                                       │    "age": 25,            │
  Structure RIGIDE                     │    "hobbies": ["code"]   │
  Colonnes fixes                       │  }                       │
  Relations complexes                  │                          │
                                       │  Document 2:             │
                                       │  {                       │
                                       │    "_id": 2,             │
                                       │    "name": "Marie",      │
                                       │    "email": "m@e.com"    │
                                       │  }                       │
                                       └──────────────────────────┘

                                         Structure FLEXIBLE
                                         Documents différents OK
                                         Pas de schéma strict
```

**Pourquoi MongoDB est populaire ?**

| Avantage | Explication |
|----------|-------------|
| **Flexible** | Pas besoin de définir un schéma strict à l'avance |
| **Scalable** | Facile d'ajouter des serveurs pour plus de puissance |
| **Rapide** | Excellentes performances en lecture/écriture |
| **JSON natif** | Format naturel pour les applis web modernes |
| **Géospatial** | Support natif des coordonnées GPS |
| **Agrégation** | Pipeline puissant pour analyser les données |

---

## [SYNC] QU'EST-CE QU'UN REPLICA SET ?

### Définition simple

**Replica Set** = Groupe de serveurs MongoDB qui contiennent **les mêmes données**

**Analogie du livre :**

```
Imagine que tu écris un livre important...

┌─────────────────────────────────────────────────────────────┐
│  SANS Replica Set (DANGEREUX [ATTENTION])                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  [GUIDE] Un seul exemplaire du livre                             │
│     v                                                       │
│  [HOT] Si tu perds ce livre -> TOUT EST PERDU                   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│  AVEC Replica Set (SÉCURISÉ [OK])                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  [GUIDE] Exemplaire Original (Primary)                           │
│  [LIVRE] Copie 1 (Secondary)                                     │
│  [LIVRE] Copie 2 (Secondary)                                     │
│     v                                                       │
│  [HOT] Si tu perds l'original -> Les copies existent encore     │
│  [OK] Une copie devient automatiquement le nouveau original   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

### Architecture d'un Replica Set

```
                    APPLICATION
                         │
                         │ Lecture/Écriture
                         v
        ┌────────────────────────────────────┐
        │       REPLICA SET MONGODB          │
        │                                    │
        │  ┌──────────────────────────────┐  │
        │  │      PRIMARY (Principal)     │  │
        │  │  ┌──────────────────────┐    │  │
        │  │  │  Base de données     │    │  │
        │  │  │  [EDIT]  Écritures       │    │  │
        │  │  │  [EYE]  Lectures        │    │  │
        │  │  └──────────────────────┘    │  │
        │  └──────────────────────────────┘  │
        │              │                     │
        │              │ Réplication         │
        │              │ (copie auto)        │
        │              v                     │
        │  ┌──────────────┬─────────────┐   │
        │  │              │             │   │
        │  │  SECONDARY   │  SECONDARY  │   │
        │  │  (Copie 1)   │  (Copie 2)  │   │
        │  │  ┌────────┐  │  ┌────────┐ │   │
        │  │  │  Copie │  │  │  Copie │ │   │
        │  │  │  exacte│  │  │  exacte│ │   │
        │  │  │  [EYE]     │  │  │  [EYE]     │ │   │
        │  │  └────────┘  │  └────────┘ │   │
        │  └──────────────┴─────────────┘   │
        └────────────────────────────────────┘
```

**Explication des rôles :**

### PRIMARY (Principal)
- **Rôle :** Reçoit TOUTES les écritures
- **Analogie :** Le directeur qui prend les décisions
- **Actions :**
  - [EDIT] Traite toutes les insertions, modifications, suppressions
  - [RESEAU] Envoie les changements aux SECONDARY
  - [EYE] Peut aussi gérer les lectures

### SECONDARY (Secondaire)
- **Rôle :** Maintient une copie exacte du PRIMARY
- **Analogie :** Les assistants qui notent tout ce que fait le directeur
- **Actions :**
  - [ENTREE] Reçoit les changements du PRIMARY
  - [SYNC] Applique les changements localement
  - [EYE] Peut gérer les lectures (si configuré)
  - [OBJECTIF] Peut devenir PRIMARY si le PRIMARY tombe

---

## [OBJECTIF] POURQUOI UTILISER UN REPLICA SET ?

### 1⃣ HAUTE DISPONIBILITÉ (High Availability)

**Problème sans Replica Set :**
```
Serveur MongoDB unique
      v
[IMPACT] Panne (électricité, crash, maintenance)
      v
[X] Application COMPLÈTEMENT en panne
[X] Clients ne peuvent plus rien faire
[X] Perte de revenus, mauvaise expérience
```

**Solution avec Replica Set :**
```
PRIMARY tombe en panne
      v
[BOT] Élection automatique (10-12 secondes)
      v
[OK] Un SECONDARY devient PRIMARY
[OK] Application continue de fonctionner
[OK] Interruption minimale (quelques secondes)
```

**Temps d'arrêt typique :**
- Sans Replica Set : **Minutes à heures** (intervention manuelle)
- Avec Replica Set : **10-30 secondes** (automatique)

**Exemple concret :**
```
E-commerce avec 1000 commandes/heure
Sans Replica Set : Panne 2h = 2000 commandes perdues
Avec Replica Set : Panne 15s = ~4 commandes affectées

Impact financier :
Sans RS : 2000 × 50€ = 100 000€ de pertes
Avec RS : 4 × 50€ = 200€ de pertes

ROI évident ! [ARGENT]
```

---

### 2⃣ REDONDANCE DES DONNÉES (Data Redundancy)

**Problème sans Replica Set :**
```
Disque dur corrompu
      v
[SAUVEGARDE] Données perdues
      v
[X] Perte définitive des données clients
[X] Catastrophe pour l'entreprise
```

**Solution avec Replica Set :**
```
Disque dur PRIMARY corrompu
      v
[LISTE] Données existent sur SECONDARY 1
[LISTE] Données existent sur SECONDARY 2
      v
[OK] Aucune perte de données
[OK] Restauration immédiate
```

**Niveau de protection :**
```
Avec 3 membres (1 PRIMARY + 2 SECONDARY) :

Probabilité de panne d'un disque : 1%/an
Probabilité de panne de 3 disques EN MÊME TEMPS : 0.0001%/an

Protection : 99.9999% (Six 9s) *
```

---

### 3⃣ SCALABILITÉ EN LECTURE (Read Scalability)

**Problème sans Replica Set :**
```
Application avec 10 000 utilisateurs
Tous lisent depuis le MÊME serveur
      v
[LENT] Serveur surchargé
[LENT] Requêtes lentes (500ms -> 5000ms)
[X] Mauvaise expérience utilisateur
```

**Solution avec Replica Set :**
```
Répartition des lectures :
- 33% vers PRIMARY
- 33% vers SECONDARY 1
- 33% vers SECONDARY 2
      v
[RAPIDE] Charge divisée par 3
[RAPIDE] Requêtes rapides (500ms constant)
[OK] Excellente expérience utilisateur
```

**Exemple concret :**
```
Site d'actualités : 95% lectures, 5% écritures

Sans RS :
- 1 serveur traite 100% du trafic
- Limite : 1000 requêtes/seconde

Avec RS (3 membres) :
- PRIMARY : 5% écritures + 33% lectures
- SECONDARY 1 : 33% lectures
- SECONDARY 2 : 33% lectures
- Limite : 3000 requêtes/seconde

Capacité × 3 ! [RAPIDE]
```

---

### 4⃣ RÉCUPÉRATION APRÈS SINISTRE (Disaster Recovery)

**Scénarios catastrophes :**

**Scénario 1 : Incendie dans le datacenter**
```
Sans Replica Set :
[X] Serveur détruit
[X] Données perdues
[X] Entreprise en faillite

Avec Replica Set (membres géographiquement distribués) :
[OK] PRIMARY détruit à Paris
[OK] SECONDARY 1 à Lyon prend le relais
[OK] SECONDARY 2 à Marseille reste en backup
[OK] Zéro perte de données
```

**Scénario 2 : Attaque ransomware**
```
Sans Replica Set :
[SKULL] Base chiffrée par ransomware
[ARGENT] Demande de rançon
[X] Choix : payer ou perdre tout

Avec Replica Set + snapshots :
[OK] PRIMARY compromis -> isolé
[OK] Restauration depuis SECONDARY sain
[OK] Retour à l'état d'avant l'attaque
[OK] Zéro rançon payée
```

---

### 5⃣ MAINTENANCE SANS INTERRUPTION (Zero Downtime Maintenance)

**Problème sans Replica Set :**
```
Mise à jour MongoDB 5.0 -> 6.0
      v
[DOUBLE_VERTICAL_BAR] Arrêt du serveur (30 minutes)
[X] Site inaccessible pendant 30 minutes
[X] Clients mécontents
```

**Solution avec Replica Set :**
```
Stratégie Rolling Update :

1. Mettre à jour SECONDARY 1
   v (PRIMARY et SECONDARY 2 restent actifs)
   [OK] Site fonctionne

2. Mettre à jour SECONDARY 2
   v (PRIMARY et SECONDARY 1 restent actifs)
   [OK] Site fonctionne

3. Faire basculer PRIMARY -> SECONDARY 1
   v (Interruption : 10 secondes)
   [OK] Site fonctionne

4. Mettre à jour l'ancien PRIMARY
   v (Nouveaux PRIMARY et SECONDARY 2 actifs)
   [OK] Site fonctionne

Interruption totale : 10 secondes au lieu de 30 minutes !
```

---

## [GRAPHIQUE] COMPARAISON : MONGODB STANDALONE vs REPLICA SET

| Critère | MongoDB Standalone | MongoDB Replica Set |
|---------|-------------------|---------------------|
| **Configuration** | * Simple (1 serveur) | *** Complexe (3+ serveurs) |
| **Coût matériel** | [ARGENT] Bas (1 machine) | [ARGENT][ARGENT][ARGENT] Élevé (3+ machines) |
| **Haute disponibilité** | [X] Non (SPOF) | [OK] Oui (failover auto) |
| **Redondance** | [X] Aucune | [OK] Oui (N copies) |
| **Scalabilité lecture** | [X] Limitée | [OK] Excellente |
| **Temps de récupération** | [ALARM_CLOCK] Heures (manuel) | [ALARM_CLOCK] Secondes (auto) |
| **Perte de données** | [ATTENTION] Risque élevé | [OK] Quasi impossible |
| **Maintenance** | [X] Interruption requise | [OK] Zero downtime possible |
| **Production** | [X] DÉCONSEILLÉ | [OK] RECOMMANDÉ |
| **Développement** | [OK] OK | [ATTENTION] Overkill |
| **Complexité admin** | * Facile | *** Moyenne |

**SPOF** = Single Point Of Failure (Point de défaillance unique)

---

## [COURS] QUAND UTILISER UN REPLICA SET ?

### [OK] UTILISE UN REPLICA SET SI :

**1. Application en production :**
```
[OK] Site web accessible 24/7
[OK] Application mobile avec utilisateurs
[OK] API utilisée par des clients
[OK] Service critique pour l'entreprise
```

**2. Données importantes :**
```
[OK] Données clients sensibles
[OK] Transactions financières
[OK] Contenu irremplaçable
[OK] Logs d'audit obligatoires
```

**3. Haute disponibilité requise :**
```
[OK] SLA (Service Level Agreement) > 99%
[OK] Pénalités en cas de panne
[OK] Réputation en jeu
[OK] Revenus dépendant de la disponibilité
```

**4. Charge importante :**
```
[OK] Plus de 1000 requêtes/seconde
[OK] Pics de trafic imprévisibles
[OK] Croissance rapide attendue
[OK] Besoin de scalabilité
```

---

### [X] N'UTILISE PAS DE REPLICA SET SI :

**1. Environnement de développement local :**
```
[X] Tests sur ton laptop
[X] Prototype rapide
[X] Apprentissage de MongoDB
[X] POC (Proof of Concept)
```

**2. Application triviale :**
```
[X] Script one-shot
[X] Petit projet personnel
[X] Données non critiques
[X] Usage ponctuel
```

**3. Ressources limitées :**
```
[X] Un seul serveur disponible
[X] Budget très serré
[X] Pas de compétences en ops
[X] Pas de monitoring prévu
```

**Règle d'or :**
```
Développement local : Standalone
Staging/Test : Replica Set (3 membres)
Production : Replica Set (3-7 membres) + Monitoring
```

---

## [CONSTRUCTION] ARCHITECTURE MINIMALE D'UN REPLICA SET

### Configuration à 3 membres (RECOMMANDÉ MINIMUM)

**Pourquoi 3 membres ? Nombre impair obligatoire !**

```
┌────────────────────────────────────────────────────────────────┐
│  QUORUM ET ÉLECTION - CONCEPT FONDAMENTAL                       │
├────────────────────────────────────────────────────────────────┤
│                                                                │
│  Quorum = Majorité absolue nécessaire pour prendre décision   │
│                                                                │
│  Avec 2 membres :                                              │
│  ┌─────────┐  ┌─────────┐                                     │
│  │ PRIMARY │  │SECONDARY│                                     │
│  └─────────┘  └─────────┘                                     │
│       │            │                                           │
│       │            [X] Panne                                    │
│       │                                                       │
│       ? Qui décide ? Impossible d'avoir majorité (1/2)        │
│       [X] Pas d'élection possible                              │
│       [X] Système bloqué                                       │
│                                                                │
│  Avec 3 membres :                                              │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐                       │
│  │ PRIMARY │  │SECONDARY│  │SECONDARY│                       │
│  └─────────┘  └─────────┘  └─────────┘                       │
│       │            │            │                             │
│       [X] Panne      │            │                             │
│                    │            │                             │
│       Majorité : 2/3 -> Élection possible ! [OK]                 │
│       Un SECONDARY devient PRIMARY                             │
│                                                                │
└────────────────────────────────────────────────────────────────┘
```

**Tableau des quorums :**

| Nombre de membres | Majorité requise | Pannes tolérées | Recommandation |
|-------------------|------------------|-----------------|----------------|
| **1** | 1 | 0 | [X] Développement uniquement |
| **2** | 2 | 0 | [X] INUTILE (aucune tolérance) |
| **3** | 2 | 1 | [OK] MINIMUM recommandé |
| **4** | 3 | 1 | [ATTENTION] Même tolérance que 3 (gaspillage) |
| **5** | 3 | 2 | [OK] Haute disponibilité |
| **6** | 4 | 2 | [ATTENTION] Même tolérance que 5 |
| **7** | 4 | 3 | [OK] Maximum recommandé |

**Règle d'or : TOUJOURS un nombre IMPAIR de membres !**

---

### Topologie pour ce guide (2 machines + 1 arbiter)

**Configuration que nous allons mettre en place :**

```
┌─────────────────────────────────────────────────────────────┐
│                     RÉSEAU LOCAL                            │
│                   192.168.1.0/24                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌───────────────────────────────────────────┐              │
│  │  MACHINE 1 (Ton PC principal)             │              │
│  │  IP: 192.168.1.10                         │              │
│  ├───────────────────────────────────────────┤              │
│  │  ┌─────────────────────────────────────┐  │              │
│  │  │  MongoDB PRIMARY                    │  │              │
│  │  │  Port: 27017                        │  │              │
│  │  │  Rôle: Lectures + Écritures         │  │              │
│  │  │  Priorité: 2 (préféré comme PRIMARY)│  │              │
│  │  └─────────────────────────────────────┘  │              │
│  │  ┌─────────────────────────────────────┐  │              │
│  │  │  MongoDB ARBITER                    │  │              │
│  │  │  Port: 27018                        │  │              │
│  │  │  Rôle: Vote uniquement (pas de données)│             │
│  │  │  Consommation: ~50 MB RAM           │  │              │
│  │  └─────────────────────────────────────┘  │              │
│  └───────────────────────────────────────────┘              │
│                          │                                  │
│                          │ Réplication                      │
│                          v                                  │
│  ┌───────────────────────────────────────────┐              │
│  │  MACHINE 2 (Ancien laptop / VM)          │              │
│  │  IP: 192.168.1.20                         │              │
│  ├───────────────────────────────────────────┤              │
│  │  ┌─────────────────────────────────────┐  │              │
│  │  │  MongoDB SECONDARY                  │  │              │
│  │  │  Port: 27017                        │  │              │
│  │  │  Rôle: Lectures + Backup            │  │              │
│  │  │  Priorité: 1                        │  │              │
│  │  └─────────────────────────────────────┘  │              │
│  └───────────────────────────────────────────┘              │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

**Qu'est-ce qu'un ARBITER ?**

**Définition :**
```
ARBITER = Membre du Replica Set qui VOTE mais ne stocke PAS de données

Analogie : Un juge qui vote aux élections mais ne garde pas de dossiers
```

**Avantages d'utiliser un ARBITER :**

| Avantage | Explication |
|----------|-------------|
| **Économie de ressources** | Consomme ~50 MB RAM vs 1+ GB pour un membre complet |
| **Permet le quorum** | Fournit le 3ème vote nécessaire (nombre impair) |
| **Pas de stockage** | Pas besoin d'espace disque pour les données |
| **Léger** | Peut tourner sur la même machine que PRIMARY |

**Quand utiliser un ARBITER ?**

[OK] **OUI si :**
- Tu as seulement 2 machines physiques
- Budget limité (pas de 3ème serveur)
- Environnement de développement/test
- Données pas ultra-critiques

[X] **NON si :**
- Production critique (préfère 3 vrais membres)
- Besoin de haute performance en lecture (arbiter ne peut pas lire)
- Données très importantes (préfère plus de redondance)

---

## [WEB] METTRE 2 MACHINES SUR LE MÊME RÉSEAU

### Option 1 : Réseau local existant (LA PLUS SIMPLE [OK])

**Scénario : Tu as déjà une Box Internet / Routeur**

```
┌────────────────────────────────────────────────────────────┐
│                    Ta Box Internet                          │
│                   (192.168.1.1)                            │
│                 Réseau: 192.168.1.0/24                     │
└───────────┬────────────────────────────┬───────────────────┘
            │                            │
            │ WiFi/Ethernet              │ WiFi/Ethernet
            v                            v
    ┌───────────────┐            ┌───────────────┐
    │   Machine 1   │            │   Machine 2   │
    │ 192.168.1.10  │            │ 192.168.1.20  │
    │   (PRIMARY)   │            │  (SECONDARY)  │
    └───────────────┘            └───────────────┘
```

**Étapes :**

**1. Connecter les deux machines à ta Box**
- Machine 1 : WiFi ou Ethernet
- Machine 2 : WiFi ou Ethernet

**2. Vérifier qu'elles sont sur le même réseau**

**Sur Machine 1 (Linux/Mac) :**
```bash
ip addr show
# ou
ifconfig
```

**Sur Machine 1 (Windows) :**
```cmd
ipconfig
```

**Résultat attendu :**
```
Machine 1 : 192.168.1.10 (ou 192.168.1.X)
Machine 2 : 192.168.1.20 (ou 192.168.1.Y)

Les 3 premiers octets DOIVENT être identiques !
192.168.1.X <- Même réseau [OK]
```

**3. Tester la connexion**

**Depuis Machine 1 :**
```bash
ping 192.168.1.20
```

**Résultat attendu :**
```
PING 192.168.1.20 (192.168.1.20) 56(84) bytes of data.
64 bytes from 192.168.1.20: icmp_seq=1 ttl=64 time=2.34 ms
64 bytes from 192.168.1.20: icmp_seq=2 ttl=64 time=1.89 ms
64 bytes from 192.168.1.20: icmp_seq=3 ttl=64 time=2.01 ms

[OK] Si tu vois ça, les machines communiquent !
```

**Si ça ne fonctionne pas :**

```bash
# Vérifier le pare-feu (Linux)
sudo ufw status
sudo ufw allow from 192.168.1.0/24

# Vérifier le pare-feu (Windows)
# Panneau de configuration -> Pare-feu Windows Defender
# -> Autoriser une application -> Autoriser MongoDB
```

---

### Option 2 : Câble Ethernet direct (SANS routeur)

**Scénario : Pas de Box, juste 2 PC avec ports Ethernet**

```
┌───────────────┐    Câble Ethernet    ┌───────────────┐
│   Machine 1   │[BLACK_LEFT-POINTING_POINTER]────────────────────[BLACK_RIGHT-POINTING_POINTER]│   Machine 2   │
│ 192.168.0.10  │   (croisé ou droit)  │ 192.168.0.20  │
└───────────────┘                      └───────────────┘
```

**[ATTENTION] Attention : Câble croisé vs droit**

**Câble Ethernet DROIT :**
- Connecte PC -> Switch -> PC
- Broches : 1-1, 2-2, 3-3, etc.
- [OK] Fonctionne avec cartes modernes (Auto-MDIX)

**Câble Ethernet CROISÉ :**
- Connecte PC -> PC directement
- Broches croisées : 1-3, 2-6, etc.
- Nécessaire sur vieux matériel

**Bonne nouvelle :** Les cartes réseau modernes (post-2010) détectent automatiquement et adaptent -> Câble droit suffit généralement ! [OK]

**Configuration manuelle des IPs :**

**Machine 1 (Linux) :**
```bash
sudo ip addr add 192.168.0.10/24 dev eth0
sudo ip link set eth0 up
```

**Machine 1 (Windows) :**
```
1. Panneau de configuration
2. Réseau et Internet
3. Centre Réseau et partage
4. Modifier les paramètres de la carte
5. Clic droit sur "Ethernet" -> Propriétés
6. IPv4 -> Propriétés
7. Utiliser l'adresse IP suivante :
   IP : 192.168.0.10
   Masque : 255.255.255.0
   Passerelle : (vide)
```

**Machine 2 : Même chose avec IP 192.168.0.20**

**Tester :**
```bash
ping 192.168.0.20  # Depuis Machine 1
ping 192.168.0.10  # Depuis Machine 2
```

---

### Option 3 : Réseau virtuel (VirtualBox / VMware)

**Scénario : 2 VMs sur le même ordinateur**

**VirtualBox - Configuration "Réseau interne" :**

```
┌──────────────────────────────────────────────────────────┐
│                  Ordinateur Hôte                          │
│                                                          │
│  ┌────────────────────┐    ┌────────────────────┐       │
│  │   VM 1 (Machine 1) │    │   VM 2 (Machine 2) │       │
│  │                    │    │                    │       │
│  │  192.168.56.10     │    │  192.168.56.20     │       │
│  └─────────┬──────────┘    └─────────┬──────────┘       │
│            │                          │                 │
│            └──────────┬───────────────┘                 │
│                       │                                 │
│            ┌──────────[BLACK_DOWN-POINTING_TRIANGLE]──────────┐                      │
│            │  Réseau interne     │                      │
│            │  "mongodb-network"  │                      │
│            └─────────────────────┘                      │
└──────────────────────────────────────────────────────────┘
```

**Configuration dans VirtualBox :**

**1. VM 1 :**
```
Machine -> Paramètres -> Réseau
Adaptateur 1 :
  - Activer
  - Mode : Réseau interne
  - Nom : mongodb-network
```

**2. VM 2 :**
```
Machine -> Paramètres -> Réseau
Adaptateur 1 :
  - Activer
  - Mode : Réseau interne
  - Nom : mongodb-network (MÊME NOM !)
```

**3. Configuration IP manuelle (sur chaque VM) :**

```bash
# VM 1
sudo nano /etc/netplan/01-netcfg.yaml
```

**Contenu :**
```yaml
network:
  version: 2
  ethernets:
    enp0s3:
      addresses:
        - 192.168.56.10/24
```

```bash
# Appliquer
sudo netplan apply
```

**VM 2 : Même chose avec 192.168.56.20**

---

## [OBJECTIF] RÉSUMÉ DE LA PARTIE 1

**Ce que tu as appris :**

[OK] **MongoDB** = Base NoSQL orientée documents (JSON)
[OK] **Replica Set** = Groupe de serveurs MongoDB synchronisés
[OK] **PRIMARY** = Reçoit les écritures, envoie aux SECONDARY
[OK] **SECONDARY** = Copie le PRIMARY, peut gérer les lectures
[OK] **ARBITER** = Vote aux élections, ne stocke pas de données

[OK] **Pourquoi Replica Set ?**
   - Haute disponibilité (failover automatique)
   - Redondance des données (pas de perte)
   - Scalabilité en lecture (charge répartie)
   - Maintenance sans interruption

[OK] **Configuration minimale** = 3 membres (nombre impair obligatoire)

[OK] **Comment connecter 2 machines :**
   - Option 1 : Via Box/Routeur (le plus simple)
   - Option 2 : Câble Ethernet direct
   - Option 3 : Réseau virtuel (VMs)

---

## [DOCS] PROCHAINES PARTIES

**PARTIE 2 : Installation de MongoDB sur les deux machines**
- Installation sur Ubuntu/Debian
- Installation sur Windows
- Installation sur macOS
- Vérification de l'installation

**PARTIE 3 : Configuration du Replica Set**
- Configuration du PRIMARY
- Configuration du SECONDARY
- Configuration de l'ARBITER
- Initialisation du Replica Set

**PARTIE 4 : Test et validation**
- Connexion au Replica Set
- Test de réplication
- Test de failover
- Test de lecture/écriture

**PARTIE 5 : Opérations avancées**
- Ajout/Suppression de membres
- Reconfiguration
- Maintenance
- Backup et restauration

**PARTIE 6 : Monitoring et dépannage**
- Surveillance du Replica Set
- Logs et diagnostic
- Problèmes courants
- Scripts d'automatisation

**PARTIE 7 : Sécurité**
- Authentification
- Autorisation (RBAC)
- Chiffrement
- Bonnes pratiques

**PARTIE 8 : Performance et optimisation**
- Tuning du Replica Set
- Indexation
- Read Preferences
- Write Concerns

---

## [COURS] QUIZ DE VALIDATION

**Réponds à ces questions pour vérifier ta compréhension :**

**1. Qu'est-ce qu'un Replica Set ?**
- A) Une sauvegarde de MongoDB
- B) Un groupe de serveurs MongoDB synchronisés
- C) Un type de base de données
- D) Un outil de monitoring

<details>
<summary>Voir la réponse</summary>
[OK] **B) Un groupe de serveurs MongoDB synchronisés**

Un Replica Set est un ensemble de serveurs (nœuds) MongoDB qui maintiennent les mêmes données, avec un PRIMARY pour les écritures et des SECONDARY pour la redondance et les lectures.
</details>

---

**2. Pourquoi TOUJOURS avoir un nombre IMPAIR de membres ?**
- A) C'est une convention
- B) Pour pouvoir élire un PRIMARY en cas de panne
- C) Pour économiser des ressources
- D) MongoDB ne fonctionne qu'avec des nombres impairs

<details>
<summary>Voir la réponse</summary>
[OK] **B) Pour pouvoir élire un PRIMARY en cas de panne**

Avec un nombre impair, il est toujours possible d'obtenir une majorité absolue (quorum) nécessaire pour élire un nouveau PRIMARY. Avec un nombre pair, en cas de split réseau, aucune majorité ne peut être atteinte.
</details>

---

**3. Qu'est-ce qu'un ARBITER ?**
- A) Un serveur de backup
- B) Un membre qui vote mais ne stocke pas de données
- C) Un serveur de monitoring
- D) Un type de PRIMARY

<details>
<summary>Voir la réponse</summary>
[OK] **B) Un membre qui vote mais ne stocke pas de données**

Un ARBITER participe aux élections en votant, mais ne maintient pas de copie des données. Cela permet d'avoir un nombre impair de votants avec moins de ressources.
</details>

---

**4. Combien de temps dure typiquement un failover automatique ?**
- A) 1-2 secondes
- B) 10-30 secondes
- C) 5-10 minutes
- D) 30-60 minutes

<details>
<summary>Voir la réponse</summary>
[OK] **B) 10-30 secondes**

Un failover automatique prend généralement 10 à 30 secondes, incluant la détection de la panne du PRIMARY et l'élection d'un nouveau PRIMARY par les SECONDARY.
</details>

---

**5. Quelle est la configuration minimale recommandée pour la production ?**
- A) 1 membre (standalone)
- B) 2 membres
- C) 3 membres
- D) 5 membres

<details>
<summary>Voir la réponse</summary>
[OK] **C) 3 membres**

3 membres est le minimum recommandé pour la production : 1 PRIMARY + 2 SECONDARY (ou 1 PRIMARY + 1 SECONDARY + 1 ARBITER). Cela permet de tolérer la panne d'un membre tout en maintenant un quorum.
</details>

---

## [OK] AUTO-ÉVALUATION

**Avant de passer à la Partie 2, assure-toi de pouvoir répondre OUI à :**

- [ ] Je comprends la différence entre MongoDB et une base SQL
- [ ] Je peux expliquer ce qu'est un Replica Set à quelqu'un
- [ ] Je comprends les rôles PRIMARY, SECONDARY et ARBITER
- [ ] Je sais pourquoi on a besoin d'un nombre impair de membres
- [ ] Je peux citer 3 avantages d'utiliser un Replica Set
- [ ] J'ai compris comment mettre 2 machines sur le même réseau
- [ ] Je sais tester si 2 machines communiquent (ping)
- [ ] Je sais quelle configuration je vais mettre en place (2 machines + arbiter)

**Si tu as coché toutes les cases, tu es prêt pour la PARTIE 2 ! [BRAVO]**

---

**[IMPORTANT] NOTE IMPORTANTE :**

Ce guide est conçu pour être **progressif**. Ne saute pas les parties ! Chaque partie s'appuie sur les connaissances acquises précédemment.

**Si quelque chose n'est pas clair, RELIS cette partie avant de continuer.**

La compréhension des concepts de base est ESSENTIELLE pour réussir la configuration pratique.

---

**[RAPIDE] Prêt ? Passons à la PARTIE 2 : Installation de MongoDB ! ->**
# [COURS] GUIDE MONGODB REPLICA SET - PARTIE 2

## [PACKAGE] INSTALLATION DE MONGODB SUR LES DEUX MACHINES

### [OBJECTIF] OBJECTIF DE CETTE PARTIE

À la fin de cette partie, tu auras :
[OK] MongoDB installé sur la Machine 1 (PRIMARY)
[OK] MongoDB installé sur la Machine 2 (SECONDARY)
[OK] Les deux instances configurées mais PAS ENCORE en Replica Set
[OK] Vérifié que tout fonctionne individuellement

**[ATTENTION] IMPORTANT : On installe d'abord, on configure le Replica Set APRÈS !**

---

## [ECRAN] PRÉREQUIS

**Avant de commencer :**

[OK] **2 machines connectées sur le même réseau**
   - Machine 1 : 192.168.1.10 (ou ton IP)
   - Machine 2 : 192.168.1.20 (ou ton IP)
   - Test ping fonctionnel entre les deux

[OK] **Systèmes d'exploitation supportés :**
   - Linux (Ubuntu 20.04/22.04, Debian 11/12, CentOS 8+)
   - Windows 10/11, Server 2019/2022
   - macOS 11+ (Big Sur ou plus récent)

[OK] **Ressources minimales par machine :**
   - CPU : 2 cœurs
   - RAM : 2 GB (4 GB recommandé)
   - Disque : 10 GB libres (SSD recommandé)

[OK] **Accès administrateur :**
   - Linux : compte avec `sudo`
   - Windows : compte Administrateur
   - macOS : compte admin

---

## [LINUX] INSTALLATION SUR UBUNTU/DEBIAN (Machine 1 et 2)

### [LISTE] Vue d'ensemble

**Étapes d'installation :**
1. Importer la clé GPG de MongoDB
2. Ajouter le dépôt MongoDB
3. Mettre à jour les paquets
4. Installer MongoDB
5. Vérifier l'installation

**Durée estimée :** 5-10 minutes par machine

---

### [SECURISE] Étape 1 : Importer la clé GPG

**Pourquoi cette étape ?**
```
La clé GPG = Signature numérique qui garantit que les paquets
proviennent bien de MongoDB Inc. et n'ont pas été modifiés.

Analogie : Comme un sceau officiel sur un document administratif.

Sans cette clé : apt refuse d'installer (sécurité)
```

**Commande (sur CHAQUE machine) :**

```bash
curl -fsSL https://pgp.mongodb.com/server-7.0.asc | \
   sudo gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg \
   --dearmor
```

**Explication ligne par ligne :**

```bash
curl -fsSL https://pgp.mongodb.com/server-7.0.asc
# curl = Outil pour télécharger depuis Internet
# -f = Fail (échouer en cas d'erreur HTTP)
# -s = Silent (mode silencieux, pas de barre de progression)
# -S = Show errors (montrer les erreurs malgré -s)
# -L = Follow redirects (suivre les redirections)
# https://pgp.mongodb.com/server-7.0.asc = URL de la clé

| \
# Le pipe (|) envoie la sortie de curl vers la commande suivante

sudo gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg --dearmor
# gpg = Outil de chiffrement/signature
# -o = Output file (fichier de sortie)
# /usr/share/keyrings/mongodb-server-7.0.gpg = Où stocker la clé
# --dearmor = Convertir du format ASCII vers binaire
```

**Résultat attendu :**
```
(Aucun message = succès silencieux [OK])
```

**Vérification :**
```bash
ls -lh /usr/share/keyrings/mongodb-server-7.0.gpg
```

**Sortie attendue :**
```
-rw-r--r-- 1 root root 2.7K Dec 16 10:00 /usr/share/keyrings/mongodb-server-7.0.gpg
                        ^
                  Fichier existe ! [OK]
```

---

### [PACKAGE] Étape 2 : Ajouter le dépôt MongoDB

**Pourquoi cette étape ?**
```
Par défaut, apt ne sait pas où trouver MongoDB.
On lui dit : "Cherche dans les dépôts officiels de MongoDB"

Analogie : Ajouter une nouvelle librairie à ta liste de librairies
          où tu peux acheter des livres.
```

**Commande :**

**Pour Ubuntu 22.04 (Jammy) :**
```bash
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
```

**Pour Ubuntu 20.04 (Focal) :**
```bash
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
```

**Pour Debian 12 (Bookworm) :**
```bash
echo "deb [ signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/debian bookworm/mongodb-org/7.0 main" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
```

**Pour Debian 11 (Bullseye) :**
```bash
echo "deb [ signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/debian bullseye/mongodb-org/7.0 main" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
```

**[REFLEXION] Comment savoir quelle version d'Ubuntu/Debian ?**

```bash
lsb_release -a
```

**Sortie exemple :**
```
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.3 LTS
Release:        22.04
Codename:       jammy
             ^^^^^^^
      Utilise la commande pour "jammy"
```

**Explication de la commande echo :**

```bash
echo "deb [...] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse"
# echo = Affiche du texte
# "deb" = Type de dépôt (Debian package)
# "[ arch=amd64,arm64 ]" = Architectures supportées
# "signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg" = Clé de signature
# "https://repo.mongodb.org/apt/ubuntu" = URL du dépôt
# "jammy/mongodb-org/7.0" = Version Ubuntu + version MongoDB
# "multiverse" = Composant Ubuntu

| sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
# | = Pipe (envoie la sortie)
# sudo = Avec privilèges root
# tee = Écrit dans un fichier ET affiche à l'écran
# /etc/apt/sources.list.d/mongodb-org-7.0.list = Fichier de config apt
```

**Vérification :**
```bash
cat /etc/apt/sources.list.d/mongodb-org-7.0.list
```

**Sortie attendue :**
```
deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse
```

---

### [SYNC] Étape 3 : Mettre à jour la liste des paquets

**Pourquoi cette étape ?**
```
On vient d'ajouter un nouveau dépôt.
apt doit "rafraîchir" sa liste pour connaître les paquets disponibles.

Analogie : Recharger la page web pour voir les nouvelles offres.
```

**Commande :**
```bash
sudo apt update
```

**Explication :**
```bash
sudo apt update
# sudo = Avec privilèges administrateur
# apt = Gestionnaire de paquets Debian/Ubuntu
# update = Met à jour la LISTE des paquets (pas les paquets eux-mêmes)
```

**Sortie attendue :**
```
Hit:1 http://archive.ubuntu.com/ubuntu jammy InRelease
Get:2 http://security.ubuntu.com/ubuntu jammy-security InRelease [110 kB]
Get:3 https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 InRelease [4,783 B]
                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                  Le dépôt MongoDB est détecté ! [OK]
Get:4 https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0/multiverse amd64 Packages [23.4 kB]
Fetched 138 kB in 2s (69.0 kB/s)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
All packages are up to date.
```

**[OK] Si tu vois "mongodb.org" dans la sortie, c'est bon !**

---

### [ENTREE] Étape 4 : Installer MongoDB

**Commande :**
```bash
sudo apt install -y mongodb-org
```

**Explication :**
```bash
sudo apt install -y mongodb-org
# sudo = Avec privilèges root
# apt install = Installer un paquet
# -y = Yes (accepter automatiquement toutes les questions)
# mongodb-org = Le meta-paquet qui installe tout MongoDB
```

**Qu'est-ce qui est installé ?**

```
mongodb-org (meta-paquet)
    │
    ├─ mongodb-org-server     -> Le serveur MongoDB (mongod)
    ├─ mongodb-org-mongos     -> Le routeur pour sharding
    ├─ mongodb-org-shell      -> Le shell interactif (mongosh)
    ├─ mongodb-org-tools      -> Outils (import/export, dump/restore)
    └─ mongodb-org-database-tools-extra -> Outils supplémentaires
```

**Durée :** 1-3 minutes selon ta connexion Internet

**Sortie attendue :**
```
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following NEW packages will be installed:
  mongodb-mongosh mongodb-org mongodb-org-database
  mongodb-org-database-tools-extra mongodb-org-mongos
  mongodb-org-server mongodb-org-shell mongodb-org-tools
0 upgraded, 8 newly installed, 0 to remove and 0 not upgraded.
Need to get 165 MB of archives.
After this operation, 549 MB of additional disk space will be used.
Get:1 https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0/multiverse amd64 mongodb-database-tools amd64 100.9.4 [50.9 MB]
[...]
Downloading mongodb-org-server_7.0.5_amd64.deb
[...]
Setting up mongodb-org-server (7.0.5) ...
Created symlink /etc/systemd/system/multi-user.target.wants/mongod.service
[...]
Setting up mongodb-org (7.0.5) ...
```

**[OK] Si tu vois "Setting up mongodb-org", l'installation est réussie !**

---

### [OK] Étape 5 : Vérifier l'installation

**1. Vérifier que le binaire est installé :**

```bash
mongod --version
```

**Sortie attendue :**
```
db version v7.0.5
Build Info: {
    "version": "7.0.5",
    "gitVersion": "7809d71e84e314b497f282f9d1c0a15cf5e4b83e",
    "openSSLVersion": "OpenSSL 3.0.2 15 Mar 2022",
    "modules": [],
    "allocator": "tcmalloc",
    "environment": {
        "distmod": "ubuntu2204",
        "distarch": "x86_64",
        "target_arch": "x86_64"
    }
}
```

**[OK] Si tu vois le numéro de version, MongoDB est installé !**

---

**2. Vérifier le shell MongoDB :**

```bash
mongosh --version
```

**Sortie attendue :**
```
1.10.6
```

---

**3. Vérifier le statut du service :**

```bash
sudo systemctl status mongod
```

**Sortie attendue :**
```
[BLACK_CIRCLE] mongod.service - MongoDB Database Server
     Loaded: loaded (/lib/systemd/system/mongod.service; enabled; vendor preset: enabled)
     Active: inactive (dead)
             ^^^^^^^^^^^^^^
        Pas encore démarré - NORMAL [OK]
       On le démarrera après configuration
     
       Docs: https://docs.mongodb.org/manual
```

**[ATTENTION] Note : "inactive" est NORMAL à ce stade !**

Pourquoi ?
```
MongoDB est installé mais pas encore configuré pour le Replica Set.
On le démarrera manuellement après la configuration dans la Partie 3.
```

---

**4. Vérifier les fichiers de configuration :**

```bash
ls -lh /etc/mongod.conf
```

**Sortie attendue :**
```
-rw-r--r-- 1 root root 1.0K Dec 16 10:15 /etc/mongod.conf
```

**Contenu par défaut :**
```bash
cat /etc/mongod.conf
```

**Tu devrais voir :**
```yaml
# mongod.conf

# for documentation of all options, see:
#   http://docs.mongodb.org/manual/reference/configuration-options/

# Where and how to store data.
storage:
  dbPath: /var/lib/mongodb
  journal:
    enabled: true

# where to write logging data.
systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log

# network interfaces
net:
  port: 27017
  bindIp: 127.0.0.1

# how the process runs
processManagement:
  timeZoneInfo: /usr/share/zoneinfo

#replication:

#sharding:
```

**[NOTE] Note : On modifiera ce fichier dans la Partie 3 !**

---

### [SYNC] Répéter sur la Machine 2

**Maintenant, RÉPÈTE EXACTEMENT les mêmes étapes sur la Machine 2 !**

```
Machine 2 (192.168.1.20) :
1. Importer la clé GPG     <- Étape 1
2. Ajouter le dépôt        <- Étape 2
3. apt update              <- Étape 3
4. apt install mongodb-org <- Étape 4
5. Vérifier                <- Étape 5
```

**[TEMPS] Durée totale pour les 2 machines : 15-20 minutes**

---

## [WINDOW] INSTALLATION SUR WINDOWS (Machine 1 et 2)

### [LISTE] Vue d'ensemble

**Méthode recommandée : Installateur MSI officiel**

**Étapes :**
1. Télécharger MongoDB Community Server
2. Exécuter l'installateur
3. Choisir le type d'installation
4. Configurer MongoDB comme service
5. Installer MongoDB Compass (optionnel)
6. Vérifier l'installation

**Durée estimée :** 10-15 minutes par machine

---

### [ENTREE] Étape 1 : Télécharger MongoDB

**1. Aller sur le site officiel :**
```
https://www.mongodb.com/try/download/community
```

**2. Sélectionner :**
```
Version: 7.0.5 (Current)
Platform: Windows
Package: MSI
```

**3. Cliquer sur "Download"**

**Taille du fichier :** ~330 MB

**[DOSSIER] Fichier téléchargé :**
```
mongodb-windows-x86_64-7.0.5-signed.msi
```

---

### [OUTIL] Étape 2 : Lancer l'installateur

**1. Double-cliquer sur le fichier .msi**

**2. Contrôle de compte utilisateur (UAC) :**
```
"Do you want to allow this app to make changes to your device?"
-> Cliquer sur "Yes"
```

**3. Écran de bienvenue :**
```
"Welcome to the MongoDB 7.0.5 Community Edition Setup Wizard"
-> Cliquer sur "Next"
```

---

### [DOC] Étape 3 : Accepter la licence

**Écran "End-User License Agreement" :**

```
[ ] I accept the terms in the License Agreement
-> [x] Cocher la case
-> Cliquer sur "Next"
```

---

### [CONFIG] Étape 4 : Choisir le type d'installation

**Écran "Choose Setup Type" :**

**2 options :**

**Option 1 : Complete (RECOMMANDÉ [OK])**
```
Installe tout :
- MongoDB Server
- MongoDB Shell (mongosh)
- MongoDB Tools
- MongoDB Compass (GUI)

Dossier d'installation :
C:\Program Files\MongoDB\Server\7.0\
```

**Option 2 : Custom**
```
Permet de choisir quoi installer et où.
Utile si espace disque limité.
```

**Choix recommandé : Complete**

**-> Cliquer sur "Next"**

---

### [SYNC] Étape 5 : Configurer le service

**Écran "Service Configuration" :**

**TRÈS IMPORTANT [ATTENTION] : On va configurer mais PAS démarrer le service !**

**Options :**

```
[x] Install MongoDB as a Service
   -> Laisser COCHÉ

Service Name: MongoDB
   -> Laisser par défaut

Data Directory: C:\Program Files\MongoDB\Server\7.0\data\
   -> Laisser par défaut

Log Directory: C:\Program Files\MongoDB\Server\7.0\log\
   -> Laisser par défaut

[ ] Run service as Network Service user
   -> NE PAS cocher (on utilise Local System Account)
```

**[ATTENTION] ATTENTION : Après installation, on ARRÊTERA le service !**

Pourquoi ?
```
Par défaut, MongoDB démarre en mode standalone.
On doit le reconfigurer pour le Replica Set avant de le démarrer.
```

**-> Cliquer sur "Next"**

---

### [COMPASS] Étape 6 : MongoDB Compass (optionnel)

**Écran "Install MongoDB Compass" :**

**MongoDB Compass = Interface graphique (GUI) pour MongoDB**

```
[x] Install MongoDB Compass
   -> COCHER si tu veux une interface graphique
   -> DÉCOCHER si tu préfères la ligne de commande uniquement
```

**Recommandation pour débutants :** [x] COCHER (très utile pour visualiser les données)

**Taille supplémentaire :** ~200 MB

**-> Cliquer sur "Next"**

---

### [OK] Étape 7 : Installation

**Écran "Ready to install" :**

```
-> Cliquer sur "Install"
```

**[TEMPS] Durée : 5-10 minutes**

**Progression :**
```
Installing MongoDB Server...
Installing MongoDB Shell...
Installing MongoDB Tools...
Installing MongoDB Compass... (si coché)
```

**Écran final :**
```
"Completed the MongoDB 7.0.5 Community Edition Setup Wizard"
-> Cliquer sur "Finish"
```

---

### [STOP] Étape 8 : ARRÊTER le service

**[ATTENTION] IMPORTANT : MongoDB est maintenant installé et DÉMARRÉ en standalone**

**On doit l'arrêter IMMÉDIATEMENT avant de le configurer en Replica Set !**

**Méthode 1 : Via les Services Windows**

```
1. Appuyer sur Windows + R
2. Taper : services.msc
3. Entrée
4. Chercher "MongoDB Server (MongoDB)"
5. Clic droit -> Arrêter
6. Clic droit -> Propriétés
7. Type de démarrage : Manuel
8. OK
```

**Méthode 2 : Via PowerShell (Administrateur)**

```powershell
# Ouvrir PowerShell en tant qu'Administrateur
Stop-Service -Name MongoDB
Set-Service -Name MongoDB -StartupType Manual
```

**Vérification :**
```powershell
Get-Service -Name MongoDB
```

**Sortie attendue :**
```
Status   Name               DisplayName
------   ----               -----------
Stopped  MongoDB            MongoDB Server (MongoDB)
```

**[OK] "Stopped" = Service arrêté, parfait !**

---

### [OK] Étape 9 : Vérifier l'installation

**1. Ouvrir PowerShell (pas besoin d'être admin) :**

```powershell
mongod --version
```

**Sortie attendue :**
```
db version v7.0.5
Build Info: {
    "version": "7.0.5",
    "gitVersion": "7809d71e84e314b497f282f9d1c0a15cf5e4b83e",
    "openSSLVersion": "Windows SChannel",
    "modules": [],
    "allocator": "tcmalloc",
    "environment": {
        "distarch": "x86_64",
        "target_arch": "x86_64"
    }
}
```

---

**2. Vérifier le shell :**

```powershell
mongosh --version
```

**Sortie attendue :**
```
1.10.6
```

---

**3. Vérifier les chemins d'installation :**

```powershell
# Dossier d'installation
dir "C:\Program Files\MongoDB\Server\7.0\bin"
```

**Tu devrais voir :**
```
mongod.exe          <- Le serveur MongoDB
mongos.exe          <- Le routeur pour sharding
mongosh.exe         <- Le shell MongoDB
mongoexport.exe     <- Outil d'export
mongoimport.exe     <- Outil d'import
mongodump.exe       <- Outil de sauvegarde
mongorestore.exe    <- Outil de restauration
[...]
```

---

**4. Vérifier le fichier de configuration :**

```powershell
notepad "C:\Program Files\MongoDB\Server\7.0\bin\mongod.cfg"
```

**Contenu par défaut :**
```yaml
# mongod.conf

# for documentation of all options, see:
#   http://docs.mongodb.org/manual/reference/configuration-options/

# Where and how to store data.
storage:
  dbPath: C:\Program Files\MongoDB\Server\7.0\data
  journal:
    enabled: true

# where to write logging data.
systemLog:
  destination: file
  logAppend: true
  path:  C:\Program Files\MongoDB\Server\7.0\log\mongod.log

# network interfaces
net:
  port: 27017
  bindIp: 127.0.0.1

#replication:

#sharding:
```

**[NOTE] On modifiera ce fichier dans la Partie 3 !**

---

### [HOT] Configurer le pare-feu Windows

**[ATTENTION] IMPORTANT pour que les 2 machines communiquent !**

**Méthode 1 : Via l'interface graphique**

```
1. Panneau de configuration
2. Système et sécurité
3. Pare-feu Windows Defender
4. Paramètres avancés
5. Règles de trafic entrant
6. Nouvelle règle...
7. Type : Port
8. TCP
9. Ports spécifiques : 27017
10. Autoriser la connexion
11. Domaine, Privé, Public : Cocher les 3
12. Nom : MongoDB Replica Set
13. Terminer
```

**Méthode 2 : Via PowerShell (Administrateur)**

```powershell
New-NetFirewallRule -DisplayName "MongoDB Replica Set" `
                    -Direction Inbound `
                    -Protocol TCP `
                    -LocalPort 27017 `
                    -Action Allow
```

**Vérification :**
```powershell
Get-NetFirewallRule -DisplayName "MongoDB Replica Set"
```

**Sortie attendue :**
```
Name                  : {GUID}
DisplayName           : MongoDB Replica Set
Description           :
DisplayGroup          :
Group                 :
Enabled               : True
Profile               : Any
Platform              : {}
Direction             : Inbound
Action                : Allow
EdgeTraversalPolicy   : Block
```

---

### [SYNC] Répéter sur la Machine 2 (Windows)

**Répète TOUTES les étapes sur la Machine 2 :**

```
Machine 2 (192.168.1.20) :
1. Télécharger le MSI        <- Étape 1
2. Installer MongoDB          <- Étapes 2-7
3. ARRÊTER le service        <- Étape 8
4. Vérifier                  <- Étape 9
5. Configurer pare-feu       <- Pare-feu
```

---

## [ITEM] INSTALLATION SUR macOS (Machine 1 et 2)

### [LISTE] Vue d'ensemble

**Méthode recommandée : Homebrew**

**Étapes :**
1. Installer Homebrew (si pas déjà installé)
2. Installer MongoDB via Homebrew
3. Vérifier l'installation

**Durée estimée :** 10-15 minutes par machine

---

### [BEER_MUG] Étape 1 : Installer Homebrew (si nécessaire)

**Vérifier si Homebrew est installé :**

```bash
brew --version
```

**Si tu vois :**
```
Homebrew 4.x.x
-> Homebrew est installé, passer à l'Étape 2 [OK]
```

**Si tu vois :**
```
command not found: brew
-> Installer Homebrew v
```

**Installer Homebrew :**

```bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

**[TEMPS] Durée : 5-10 minutes**

**Suivre les instructions à l'écran.**

**Après installation, vérifier :**
```bash
brew --version
```

---

### [ENTREE] Étape 2 : Installer MongoDB

**1. Ajouter le tap MongoDB :**

```bash
brew tap mongodb/brew
```

**Explication :**
```bash
brew tap mongodb/brew
# brew tap = Ajouter un dépôt tiers à Homebrew
# mongodb/brew = Dépôt officiel de MongoDB sur Homebrew
```

**Sortie attendue :**
```
==> Tapping mongodb/brew
Cloning into '/usr/local/Homebrew/Library/Taps/mongodb/homebrew-brew'...
Tapped 17 formulae (21 files, 345.2KB).
```

---

**2. Installer MongoDB Community Edition :**

```bash
brew install mongodb-community@7.0
```

**Explication :**
```bash
brew install mongodb-community@7.0
# brew install = Installer un paquet
# mongodb-community@7.0 = MongoDB Community version 7.0
```

**[TEMPS] Durée : 3-5 minutes**

**Sortie attendue :**
```
==> Downloading https://fastdl.mongodb.org/tools/db/mongodb-database-tools-macos-x86_64-100.9.4.zip
[...]
==> Installing mongodb-community from mongodb/brew
[...]
==> Caveats
To start mongodb/brew/mongodb-community now and restart at login:
  brew services start mongodb/brew/mongodb-community

Or, if you don't want/need a background service you can just run:
  mongod --config /usr/local/etc/mongod.conf
[...]
==> Summary
[BEER_MUG]  /usr/local/Cellar/mongodb-community/7.0.5: 12 files, 213MB
```

---

### [OK] Étape 3 : Vérifier l'installation

**1. Vérifier le binaire :**

```bash
mongod --version
```

**Sortie attendue :**
```
db version v7.0.5
Build Info: {
    "version": "7.0.5",
    "gitVersion": "7809d71e84e314b497f282f9d1c0a15cf5e4b83e",
    "modules": [],
    "allocator": "system",
    "environment": {
        "distarch": "x86_64",
        "target_arch": "x86_64"
    }
}
```

---

**2. Vérifier le shell :**

```bash
mongosh --version
```

**Sortie attendue :**
```
1.10.6
```

---

**3. Vérifier le fichier de configuration :**

```bash
cat /usr/local/etc/mongod.conf
```

**Sortie attendue :**
```yaml
systemLog:
  destination: file
  path: /usr/local/var/log/mongodb/mongo.log
  logAppend: true
storage:
  dbPath: /usr/local/var/mongodb
net:
  bindIp: 127.0.0.1
  port: 27017
```

**[NOTE] On modifiera ce fichier dans la Partie 3 !**

---

### [STOP] Étape 4 : NE PAS démarrer le service

**[ATTENTION] IMPORTANT : Ne pas démarrer MongoDB maintenant !**

**Si tu as déjà démarré le service par erreur :**

```bash
# Arrêter le service
brew services stop mongodb-community@7.0

# Vérifier qu'il est arrêté
brew services list
```

**Sortie attendue :**
```
Name                  Status  User File
mongodb-community@7.0 stopped
                      ^^^^^^^^
                   Arrêté [OK]
```

---

### [SYNC] Répéter sur la Machine 2 (macOS)

**Répète TOUTES les étapes sur la Machine 2.**

---

## [TEST] TEST DE CONNECTIVITÉ ENTRE LES 2 MACHINES

**Avant de passer à la configuration du Replica Set, on vérifie que les machines peuvent communiquer sur le port MongoDB (27017).**

### Test avec netcat (nc)

**Sur Machine 1 (Ouvrir un port temporaire) :**

```bash
# Linux/Mac
nc -l 27017

# Windows (installer netcat d'abord ou utiliser telnet)
# Ou simplement démarrer MongoDB temporairement
```

**Sur Machine 2 (Tester la connexion) :**

```bash
# Linux/Mac
nc -zv 192.168.1.10 27017

# Windows
Test-NetConnection -ComputerName 192.168.1.10 -Port 27017
```

**Si ça fonctionne :**
```
Connection to 192.168.1.10 27017 port [tcp/*] succeeded!
[OK] Les machines peuvent communiquer !
```

**Si ça échoue :**
```
[X] Vérifier :
1. Pare-feu sur les 2 machines
2. Les IPs sont correctes
3. Les machines sont sur le même réseau
```

---

## [LISTE] RÉCAPITULATIF DE LA PARTIE 2

**Ce que tu as fait :**

[OK] **Sur Machine 1 :**
   - MongoDB 7.0.5 installé
   - Service arrêté (pas en standalone)
   - Pare-feu configuré (port 27017)

[OK] **Sur Machine 2 :**
   - MongoDB 7.0.5 installé
   - Service arrêté
   - Pare-feu configuré

[OK] **Test de connectivité :**
   - Les 2 machines communiquent [OK]

**État actuel :**
```
Machine 1 (192.168.1.10)         Machine 2 (192.168.1.20)
┌─────────────────┐              ┌─────────────────┐
│ MongoDB installé│[BLACK_LEFT-POINTING_POINTER]────ping────[BLACK_RIGHT-POINTING_POINTER]│ MongoDB installé│
│ Service ARRÊTÉ  │              │ Service ARRÊTÉ  │
│ Port 27017 ouvert              │ Port 27017 ouvert
└─────────────────┘              └─────────────────┘

       Prêt pour configuration Replica Set ! [OK]
```

---

## [OBJECTIF] PROCHAINE ÉTAPE

**PARTIE 3 : Configuration du Replica Set**

Tu vas maintenant :
1. Modifier les fichiers de configuration
2. Configurer le PRIMARY sur Machine 1
3. Configurer le SECONDARY sur Machine 2
4. Configurer l'ARBITER sur Machine 1 (port 27018)
5. Initialiser le Replica Set
6. Vérifier que tout fonctionne

**[RAPIDE] Prêt ? Passons à la PARTIE 3 ! ->**

# [COURS] GUIDE MONGODB REPLICA SET - PARTIE 3

## [CONFIG] CONFIGURATION DU REPLICA SET

### [OBJECTIF] OBJECTIF DE CETTE PARTIE

À la fin de cette partie, tu auras :
[OK] Configuré le PRIMARY sur Machine 1 (port 27017)
[OK] Configuré l'ARBITER sur Machine 1 (port 27018)
[OK] Configuré le SECONDARY sur Machine 2 (port 27017)
[OK] Initialisé le Replica Set
[OK] Vérifié que la réplication fonctionne

**[TEMPS] Durée estimée : 30-45 minutes**

---

## [MESURE] ARCHITECTURE FINALE

```
┌─────────────────────────────────────────────────────────────┐
│                REPLICA SET: "rs0"                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  MACHINE 1 (192.168.1.10)                                   │
│  ┌────────────────────────────────────────────────────┐     │
│  │  PRIMARY                                           │     │
│  │  mongodb://192.168.1.10:27017                      │     │
│  │  Priorité: 2 (préféré comme PRIMARY)              │     │
│  │  Vote: Oui                                         │     │
│  │  Données: Oui                                      │     │
│  └────────────────────────────────────────────────────┘     │
│  ┌────────────────────────────────────────────────────┐     │
│  │  ARBITER                                           │     │
│  │  mongodb://192.168.1.10:27018                      │     │
│  │  Priorité: 0 (ne peut pas devenir PRIMARY)        │     │
│  │  Vote: Oui                                         │     │
│  │  Données: Non                                      │     │
│  └────────────────────────────────────────────────────┘     │
│                                                             │
│  MACHINE 2 (192.168.1.20)                                   │
│  ┌────────────────────────────────────────────────────┐     │
│  │  SECONDARY                                         │     │
│  │  mongodb://192.168.1.20:27017                      │     │
│  │  Priorité: 1                                       │     │
│  │  Vote: Oui                                         │     │
│  │  Données: Oui                                      │     │
│  └────────────────────────────────────────────────────┘     │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Quorum: 2/3 membres -> Tolérance: 1 membre en panne
```

---

## [OUTIL] CONFIGURATION MACHINE 1 : PRIMARY (Port 27017)

### [NOTE] Étape 1 : Modifier le fichier de configuration

**Linux (Ubuntu/Debian) :**
```bash
sudo nano /etc/mongod.conf
```

**macOS :**
```bash
sudo nano /usr/local/etc/mongod.conf
```

**Windows :**
```powershell
notepad "C:\Program Files\MongoDB\Server\7.0\bin\mongod.cfg"
# Exécuter notepad en tant qu'Administrateur !
```

---

### [FICHIER] Configuration complète du PRIMARY

**Remplace TOUT le contenu par ceci :**

```yaml
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION MONGODB - PRIMARY
# ═══════════════════════════════════════════════════════════════
# Machine: Machine 1
# IP: 192.168.1.10
# Port: 27017
# Rôle: PRIMARY
# Replica Set: rs0
# ═══════════════════════════════════════════════════════════════

# ───────────────────────────────────────────────────────────────
# STOCKAGE DES DONNÉES
# ───────────────────────────────────────────────────────────────
storage:
  # Chemin où MongoDB stocke les données
  dbPath: /var/lib/mongodb              # Linux
  # dbPath: /usr/local/var/mongodb      # macOS
  # dbPath: C:\Program Files\MongoDB\Server\7.0\data  # Windows
  
  # Journal = Log des opérations d'écriture pour garantir la durabilité
  journal:
    enabled: true
  
  # Moteur de stockage (WiredTiger = défaut, performant)
  engine: wiredTiger
  
  # Configuration WiredTiger
  wiredTiger:
    engineConfig:
      # Taille du cache (50% de la RAM - 1GB par défaut)
      # cacheSizeGB: 1
      
    collectionConfig:
      # Compression des données (économise l'espace disque)
      blockCompressor: snappy
    
    indexConfig:
      # Compression des index
      prefixCompression: true

# ───────────────────────────────────────────────────────────────
# LOGS SYSTÈME
# ───────────────────────────────────────────────────────────────
systemLog:
  # Où écrire les logs
  destination: file
  
  # Chemin du fichier de log
  path: /var/log/mongodb/mongod.log    # Linux
  # path: /usr/local/var/log/mongodb/mongo.log  # macOS
  # path: C:\Program Files\MongoDB\Server\7.0\log\mongod.log  # Windows
  
  # Ne pas écraser le fichier de log à chaque démarrage
  logAppend: true
  
  # Niveau de verbosité (0 = info, 1-5 = debug)
  verbosity: 0
  
  # Composants spécifiques (optionnel)
  component:
    replication:
      verbosity: 1  # Plus de détails sur la réplication

# ───────────────────────────────────────────────────────────────
# RÉSEAU
# ───────────────────────────────────────────────────────────────
net:
  # Port d'écoute
  port: 27017
  
  # IMPORTANT : Écouter sur TOUTES les interfaces pour le Replica Set
  bindIp: 0.0.0.0
  # bindIp: 127.0.0.1 <- Avant (standalone, localhost uniquement)
  # bindIp: 0.0.0.0   <- Maintenant (Replica Set, accessible depuis réseau)
  
  # Nombre max de connexions simultanées
  maxIncomingConnections: 1000
  
  # Compression réseau (réduit la bande passante)
  compression:
    compressors: snappy,zstd
  
  # IPv6 (optionnel)
  ipv6: false

# ───────────────────────────────────────────────────────────────
# RÉPLICATION (REPLICA SET)
# ───────────────────────────────────────────────────────────────
replication:
  # Nom du Replica Set (DOIT être identique sur tous les membres)
  replSetName: rs0
  
  # Chemin du fichier oplog (log des opérations)
  # oplogSizeMB: 1024  # 1 GB (optionnel, auto-calculé par défaut)

# ───────────────────────────────────────────────────────────────
# GESTION DES PROCESSUS
# ───────────────────────────────────────────────────────────────
processManagement:
  # Fork (démon en arrière-plan) - Linux/macOS uniquement
  fork: false  # false = rester en premier plan pour systemd
  
  # Fichier PID
  pidFilePath: /var/run/mongodb/mongod.pid  # Linux
  # pidFilePath: /usr/local/var/mongodb/mongod.pid  # macOS
  
  # Fuseau horaire
  timeZoneInfo: /usr/share/zoneinfo  # Linux
  # timeZoneInfo: /usr/share/zoneinfo  # macOS

# ───────────────────────────────────────────────────────────────
# SÉCURITÉ (À activer APRÈS initialisation du Replica Set)
# ───────────────────────────────────────────────────────────────
#security:
#  authorization: enabled
#  keyFile: /etc/mongodb/keyfile

# ───────────────────────────────────────────────────────────────
# OPÉRATIONS
# ───────────────────────────────────────────────────────────────
operationProfiling:
  # Profiler de requêtes (désactivé par défaut)
  mode: off  # off | slowOp | all
  
  # Seuil pour "requête lente" (en ms)
  slowOpThresholdMs: 100

# ───────────────────────────────────────────────────────────────
# SHARDING (Non utilisé dans un Replica Set simple)
# ───────────────────────────────────────────────────────────────
#sharding:
#  clusterRole: shardsvr

# ═══════════════════════════════════════════════════════════════
# FIN DE LA CONFIGURATION PRIMARY
# ═══════════════════════════════════════════════════════════════
```

**[ATTENTION] ATTENTION : Adaptations selon ton système :**

**Linux :**
- `dbPath: /var/lib/mongodb`
- `path: /var/log/mongodb/mongod.log`
- `pidFilePath: /var/run/mongodb/mongod.pid`
- `fork: false` (pour systemd)

**macOS :**
- `dbPath: /usr/local/var/mongodb`
- `path: /usr/local/var/log/mongodb/mongo.log`
- `pidFilePath: /usr/local/var/mongodb/mongod.pid`
- `fork: true` (macOS n'utilise pas systemd)

**Windows :**
- `dbPath: C:\Program Files\MongoDB\Server\7.0\data`
- `path: C:\Program Files\MongoDB\Server\7.0\log\mongod.log`
- Retirer sections `processManagement` (pas utilisé sur Windows)

---

### [SAUVEGARDE] Sauvegarder le fichier

**Linux/macOS :**
```
Ctrl + O (save)
Entrée (confirmer)
Ctrl + X (exit)
```

**Windows :**
```
Fichier -> Enregistrer
```

---

### [OK] Vérifier la syntaxe du fichier

**Linux/macOS :**
```bash
# Vérifier que le YAML est valide
mongod --config /etc/mongod.conf --configExpand rest --outputConfig

# Sur macOS :
mongod --config /usr/local/etc/mongod.conf --configExpand rest --outputConfig
```

**Windows :**
```powershell
mongod --config "C:\Program Files\MongoDB\Server\7.0\bin\mongod.cfg" --configExpand rest --outputConfig
```

**Si tout est OK, tu verras la configuration parsée.**

**Si erreur YAML :**
```
Error parsing YAML config file: yaml-cpp: error at line X, column Y
-> Vérifier l'indentation (espaces, PAS de tabs)
-> Vérifier les deux-points (:) suivis d'un espace
```

---

### [RAPIDE] Démarrer le PRIMARY

**Linux (systemd) :**
```bash
sudo systemctl start mongod
sudo systemctl status mongod
```

**Linux (si pas systemd) :**
```bash
sudo mongod --config /etc/mongod.conf
```

**macOS (Homebrew services) :**
```bash
brew services start mongodb-community@7.0
brew services list
```

**macOS (manuel) :**
```bash
mongod --config /usr/local/etc/mongod.conf
```

**Windows (Service) :**
```powershell
# Démarrer en tant qu'Administrateur
Start-Service -Name MongoDB

# Vérifier
Get-Service -Name MongoDB
```

**Windows (manuel) :**
```powershell
# Ouvrir PowerShell en Administrateur
cd "C:\Program Files\MongoDB\Server\7.0\bin"
.\mongod.exe --config mongod.cfg
```

---

### [RECHERCHE] Vérifier que le PRIMARY est démarré

**Connexion au shell MongoDB :**

```bash
mongosh --host 192.168.1.10 --port 27017
```

**Tu devrais voir :**
```
Current Mongosh Log ID: 64f3e7a8b5c2d4e8f1a2b3c4
Connecting to:    mongodb://192.168.1.10:27017/
Using MongoDB:    7.0.5
Using Mongosh:    1.10.6

For mongosh info see: https://docs.mongodb.com/mongodb-shell/

rs0 [direct: primary] test>
    ^^^             ^^^^^^^^^
Replica Set      PRIMARY (après init)
```

**[ATTENTION] Au premier démarrage, tu verras juste `test>` (pas encore "rs0")**

**C'est normal ! On initialisera le Replica Set plus tard.**

**Quitter le shell :**
```javascript
exit
```

---

## [OUTIL] CONFIGURATION MACHINE 1 : ARBITER (Port 27018)

### [DOSSIER] Créer les répertoires pour l'ARBITER

**Linux :**
```bash
sudo mkdir -p /var/lib/mongodb-arbiter
sudo mkdir -p /var/log/mongodb
sudo chown -R mongodb:mongodb /var/lib/mongodb-arbiter
sudo chown -R mongodb:mongodb /var/log/mongodb
```

**macOS :**
```bash
sudo mkdir -p /usr/local/var/mongodb-arbiter
sudo mkdir -p /usr/local/var/log/mongodb
sudo chown -R $(whoami) /usr/local/var/mongodb-arbiter
sudo chown -R $(whoami) /usr/local/var/log/mongodb
```

**Windows :**
```powershell
# Ouvrir PowerShell en Administrateur
New-Item -ItemType Directory -Path "C:\Program Files\MongoDB\Server\7.0\data-arbiter"
New-Item -ItemType Directory -Path "C:\Program Files\MongoDB\Server\7.0\log"
```

---

### [NOTE] Créer le fichier de configuration de l'ARBITER

**Linux :**
```bash
sudo nano /etc/mongod-arbiter.conf
```

**macOS :**
```bash
sudo nano /usr/local/etc/mongod-arbiter.conf
```

**Windows :**
```powershell
notepad "C:\Program Files\MongoDB\Server\7.0\bin\mongod-arbiter.cfg"
# En tant qu'Administrateur !
```

---

### [FICHIER] Configuration de l'ARBITER

**Contenu du fichier :**

```yaml
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION MONGODB - ARBITER
# ═══════════════════════════════════════════════════════════════
# Machine: Machine 1
# IP: 192.168.1.10
# Port: 27018 (différent du PRIMARY !)
# Rôle: ARBITER (vote seulement, pas de données)
# Replica Set: rs0
# ═══════════════════════════════════════════════════════════════

storage:
  # ARBITER stocke TRÈS PEU de données (juste metadata)
  dbPath: /var/lib/mongodb-arbiter       # Linux
  # dbPath: /usr/local/var/mongodb-arbiter  # macOS
  # dbPath: C:\Program Files\MongoDB\Server\7.0\data-arbiter  # Windows
  
  journal:
    enabled: true

systemLog:
  destination: file
  path: /var/log/mongodb/mongod-arbiter.log  # Linux
  # path: /usr/local/var/log/mongodb/mongo-arbiter.log  # macOS
  # path: C:\Program Files\MongoDB\Server\7.0\log\mongod-arbiter.log  # Windows
  logAppend: true

net:
  # Port DIFFÉRENT du PRIMARY (27018 au lieu de 27017)
  port: 27018
  
  # Écouter sur toutes les interfaces
  bindIp: 0.0.0.0

replication:
  # MÊME nom de Replica Set que le PRIMARY
  replSetName: rs0

processManagement:
  fork: false  # Linux : false pour systemd
  # fork: true  # macOS
  pidFilePath: /var/run/mongodb/mongod-arbiter.pid  # Linux
  # pidFilePath: /usr/local/var/mongodb/mongod-arbiter.pid  # macOS

# ═══════════════════════════════════════════════════════════════
# FIN DE LA CONFIGURATION ARBITER
# ═══════════════════════════════════════════════════════════════
```

---

### [RAPIDE] Démarrer l'ARBITER

**Linux (manuel - recommandé pour l'arbiter) :**
```bash
sudo mongod --config /etc/mongod-arbiter.conf &
```

**macOS :**
```bash
mongod --config /usr/local/etc/mongod-arbiter.conf &
```

**Windows :**
```powershell
# Ouvrir PowerShell en Administrateur
cd "C:\Program Files\MongoDB\Server\7.0\bin"
Start-Process mongod.exe -ArgumentList "--config mongod-arbiter.cfg" -WindowStyle Hidden
```

---

### [RECHERCHE] Vérifier que l'ARBITER tourne

```bash
# Vérifier que le port 27018 est ouvert
# Linux/macOS
netstat -tulpn | grep 27018

# Windows
netstat -ano | findstr 27018
```

**Tu devrais voir :**
```
tcp        0      0 0.0.0.0:27018           0.0.0.0:*               LISTEN      12345/mongod
```

**[OK] Port 27018 en écoute = ARBITER tourne !**

---

## [OUTIL] CONFIGURATION MACHINE 2 : SECONDARY (Port 27017)

**Sur Machine 2, répète les MÊMES étapes que pour le PRIMARY, MAIS :**

**Modifications à faire :**

```yaml
# Dans /etc/mongod.conf (ou équivalent)

# [ATTENTION] Les chemins restent les MÊMES (pas "secondary" dans le nom)
storage:
  dbPath: /var/lib/mongodb  # <- Identique au PRIMARY

systemLog:
  path: /var/log/mongodb/mongod.log  # <- Identique

net:
  port: 27017  # <- MÊME PORT que le PRIMARY
  bindIp: 0.0.0.0  # <- IMPORTANT

replication:
  replSetName: rs0  # <- MÊME NOM de Replica Set
```

**La configuration est IDENTIQUE au PRIMARY !**

**Pourquoi ?**
```
À ce stade, on ne distingue pas PRIMARY et SECONDARY dans la config.
C'est lors de l'INITIALISATION du Replica Set qu'on définit les rôles.
```

---

### [RAPIDE] Démarrer le SECONDARY

**Linux :**
```bash
sudo systemctl start mongod
sudo systemctl status mongod
```

**macOS :**
```bash
brew services start mongodb-community@7.0
```

**Windows :**
```powershell
Start-Service -Name MongoDB
```

---

### [RECHERCHE] Vérifier que le SECONDARY tourne

```bash
mongosh --host 192.168.1.20 --port 27017
```

**Tu devrais te connecter avec succès.**

---

## [OBJECTIF] INITIALISATION DU REPLICA SET

**Maintenant, on a :**
```
[OK] PRIMARY démarré (192.168.1.10:27017)
[OK] ARBITER démarré (192.168.1.10:27018)
[OK] SECONDARY démarré (192.168.1.20:27017)

Mais ils ne se connaissent PAS encore !
Il faut les LIER en un Replica Set.
```

---

### [LIEN] Étape 1 : Se connecter au PRIMARY

**Sur Machine 1 :**

```bash
mongosh --host 192.168.1.10 --port 27017
```

---

### [RAPIDE] Étape 2 : Initialiser le Replica Set

**Dans le shell MongoDB, tape :**

```javascript
rs.initiate({
  _id: "rs0",
  members: [
    { _id: 0, host: "192.168.1.10:27017", priority: 2 },
    { _id: 1, host: "192.168.1.20:27017", priority: 1 },
    { _id: 2, host: "192.168.1.10:27018", arbiterOnly: true }
  ]
})
```

**Explication ligne par ligne :**

```javascript
rs.initiate({
  // rs = replica set
  // initiate = initialiser
  
  _id: "rs0",
  // _id = Nom du Replica Set
  // DOIT correspondre à "replSetName" dans mongod.conf
  
  members: [
    // Liste des membres du Replica Set
    
    { 
      _id: 0,                        // ID unique du membre (0, 1, 2...)
      host: "192.168.1.10:27017",    // IP:Port
      priority: 2                    // Priorité (0-1000)
                                     // Plus haut = plus de chances d'être PRIMARY
    },
    
    { 
      _id: 1,
      host: "192.168.1.20:27017",
      priority: 1                    // Priorité plus basse
    },
    
    { 
      _id: 2,
      host: "192.168.1.10:27018",
      arbiterOnly: true              // C'est un ARBITER
                                     // Ne stocke PAS de données
                                     // Vote uniquement
    }
  ]
})
```

**Résultat attendu :**

```javascript
{
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1702730000, i: 1 }),
    signature: { ... }
  },
  operationTime: Timestamp({ t: 1702730000, i: 1 })
}
```

**[OK] "ok: 1" = Initialisation réussie ! [BRAVO]**

---

### [RECHERCHE] Étape 3 : Vérifier le statut du Replica Set

**Dans le shell MongoDB, tape :**

```javascript
rs.status()
```

**Tu devrais voir :**

```javascript
{
  set: 'rs0',
  members: [
    {
      _id: 0,
      name: '192.168.1.10:27017',
      health: 1,
      state: 1,
      stateStr: 'PRIMARY',
      uptime: 123,
      ...
    },
    {
      _id: 1,
      name: '192.168.1.20:27017',
      health: 1,
      state: 2,
      stateStr: 'SECONDARY',
      uptime: 118,
      syncSourceHost: '192.168.1.10:27017',
      ...
    },
    {
      _id: 2,
      name: '192.168.1.10:27018',
      health: 1,
      state: 7,
      stateStr: 'ARBITER',
      uptime: 120,
      ...
    }
  ],
  ok: 1
}
```

**Points importants :**

```javascript
stateStr: 'PRIMARY'    // <- Ce membre est le PRIMARY
stateStr: 'SECONDARY'  // <- Ce membre est le SECONDARY
stateStr: 'ARBITER'    // <- Ce membre est l'ARBITER

health: 1              // <- 1 = En bonne santé
health: 0              // <- 0 = Problème !

syncSourceHost         // <- SECONDARY se synchronise depuis qui
```

---

### [DESIGN] Commande simplifiée

**Pour un affichage plus simple :**

```javascript
rs.status().members.forEach(m => {
  print(`${m.name.padEnd(25)} | ${m.stateStr.padEnd(10)} | Health: ${m.health}`)
})
```

**Résultat :**

```
192.168.1.10:27017        | PRIMARY    | Health: 1
192.168.1.20:27017        | SECONDARY  | Health: 1
192.168.1.10:27018        | ARBITER    | Health: 1
```

**[OK] Tous "Health: 1" = Tout va bien ! [BRAVO]**

---

## [TEST] TESTS DE VALIDATION

### Test 1 : Insertion de données sur le PRIMARY

**Se connecter au PRIMARY :**

```bash
mongosh --host 192.168.1.10 --port 27017
```

**Créer une base de données de test :**

```javascript
use testdb

db.users.insertOne({
  name: "Alice",
  email: "alice@example.com",
  age: 25,
  created: new Date()
})
```

**Résultat attendu :**

```javascript
{
  acknowledged: true,
  insertedId: ObjectId("64f3e7a8b5c2d4e8f1a2b3c4")
}
```

---

### Test 2 : Vérifier la réplication sur le SECONDARY

**Se connecter au SECONDARY (Machine 2) :**

```bash
mongosh --host 192.168.1.20 --port 27017
```

**[ATTENTION] Par défaut, on NE PEUT PAS lire depuis un SECONDARY !**

**Tu verras :**

```javascript
use testdb
db.users.find()

// Erreur :
MongoServerError: not primary and secondaryOk=false
```

**C'est une protection par défaut. Pour lire depuis un SECONDARY :**

```javascript
// Autoriser les lectures sur SECONDARY
rs.secondaryOk()
// Ou la nouvelle syntaxe :
db.getMongo().setReadPref('secondaryPreferred')

// Maintenant, lire :
db.users.find()
```

**Résultat attendu :**

```javascript
[
  {
    _id: ObjectId("64f3e7a8b5c2d4e8f1a2b3c4"),
    name: 'Alice',
    email: 'alice@example.com',
    age: 25,
    created: ISODate('2024-12-16T10:30:00.000Z')
  }
]
```

**[OK] Les données sont répliquées ! [BRAVO]**

---

### Test 3 : Tester le failover automatique

**[OBJECTIF] Objectif : Simuler la panne du PRIMARY et voir le SECONDARY prendre le relais**

**1. Noter quel membre est PRIMARY :**

```javascript
rs.status().members.filter(m => m.stateStr === 'PRIMARY')[0].name
```

**Résultat :**
```
192.168.1.10:27017  <- PRIMARY actuel
```

---

**2. Arrêter le PRIMARY (sur Machine 1) :**

**Linux :**
```bash
sudo systemctl stop mongod
```

**macOS :**
```bash
brew services stop mongodb-community@7.0
```

**Windows :**
```powershell
Stop-Service -Name MongoDB
```

---

**3. Sur Machine 2, observer l'élection (attendre 10-30 secondes) :**

```bash
mongosh --host 192.168.1.20 --port 27017
```

**Dans le shell :**

```javascript
// Vérifier le statut
rs.status()

// Ou plus simple :
rs.isMaster().ismaster
```

**Après quelques secondes, tu devrais voir :**

```javascript
true  <- Le SECONDARY est devenu PRIMARY !
```

**Vérifier le statut complet :**

```javascript
rs.status().members.forEach(m => {
  print(`${m.name.padEnd(25)} | ${m.stateStr}`)
})
```

**Résultat :**

```
192.168.1.10:27017        | (not reachable/healthy)  <- Ancien PRIMARY (arrêté)
192.168.1.20:27017        | PRIMARY                  <- Nouveau PRIMARY ! [OK]
192.168.1.10:27018        | ARBITER                  <- Toujours ARBITER
```

**[OK] Le failover a fonctionné ! [BRAVO]**

---

**4. Redémarrer l'ancien PRIMARY (Machine 1) :**

**Linux :**
```bash
sudo systemctl start mongod
```

**macOS :**
```bash
brew services start mongodb-community@7.0
```

**Windows :**
```powershell
Start-Service -Name MongoDB
```

---

**5. Observer le résultat (attendre 10-20 secondes) :**

**Connecte-toi à n'importe quel membre et vérifie :**

```javascript
rs.status().members.forEach(m => {
  print(`${m.name.padEnd(25)} | ${m.stateStr}`)
})
```

**Résultat (2 possibilités) :**

**Possibilité 1 : L'ancien PRIMARY redevient PRIMARY**
```
192.168.1.10:27017        | PRIMARY    <- Repris son rôle (priorité 2)
192.168.1.20:27017        | SECONDARY  <- Redevenu SECONDARY
192.168.1.10:27018        | ARBITER
```

**Pourquoi ?** Priorité 2 > Priorité 1 -> Préférence pour Machine 1

---

**Possibilité 2 : Le nouveau PRIMARY reste PRIMARY**
```
192.168.1.10:27017        | SECONDARY  <- Rejoint comme SECONDARY
192.168.1.20:27017        | PRIMARY    <- Reste PRIMARY
192.168.1.10:27018        | ARBITER
```

**Pourquoi ?** Le Replica Set évite les basculements inutiles si le PRIMARY actuel fonctionne bien.

**Les deux sont corrects ! [OK]**

---

## [GRAPHIQUE] COMMANDES UTILES DU REPLICA SET

### Informations générales

```javascript
// Statut complet
rs.status()

// Statut simplifié
rs.isMaster()

// Configuration du Replica Set
rs.conf()

// Afficher le PRIMARY actuel
db.hello().primary

// Afficher TOUS les membres
rs.status().members.map(m => ({ name: m.name, state: m.stateStr }))
```

---

### Gestion des membres

```javascript
// Ajouter un membre
rs.add("192.168.1.30:27017")

// Ajouter un arbiter
rs.addArb("192.168.1.30:27018")

// Retirer un membre
rs.remove("192.168.1.30:27017")

// Changer la priorité d'un membre
cfg = rs.conf()
cfg.members[1].priority = 5
rs.reconfig(cfg)
```

---

### Opérations de maintenance

```javascript
// Forcer une élection (faire du SECONDARY actuel le PRIMARY)
rs.stepDown()

// Geler un membre (l'empêcher de devenir PRIMARY)
rs.freeze(120)  // 120 secondes

// Forcer une synchronisation
rs.syncFrom("192.168.1.10:27017")
```

---

## [LISTE] RÉCAPITULATIF DE LA PARTIE 3

**Ce que tu as fait :**

[OK] Configuré 3 membres d'un Replica Set :
   - PRIMARY (Machine 1, port 27017)
   - ARBITER (Machine 1, port 27018)
   - SECONDARY (Machine 2, port 27017)

[OK] Initialisé le Replica Set avec `rs.initiate()`

[OK] Vérifié la réplication des données

[OK] Testé le failover automatique

[OK] Observé l'élection d'un nouveau PRIMARY

**État actuel :**

```
┌─────────────────────────────────────────────────────────────┐
│          REPLICA SET "rs0" OPÉRATIONNEL [OK]                   │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  PRIMARY: 192.168.1.10:27017 (ou 192.168.1.20:27017)        │
│  SECONDARY: 192.168.1.20:27017 (ou 192.168.1.10:27017)      │
│  ARBITER: 192.168.1.10:27018                                │
│                                                             │
│  - Réplication : [OK] Fonctionne                              │
│  - Failover : [OK] Testé avec succès                          │
│  - Haute disponibilité : [OK] Garantie                        │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

---

## [OBJECTIF] PROCHAINES ÉTAPES

**PARTIE 4 : Opérations avancées**
- Read Preference (où lire les données)
- Write Concern (garanties d'écriture)
- Read Concern (garanties de lecture)
- Gestion des priorités
- Ajout/Suppression de membres

**PARTIE 5 : Sécurité**
- Authentification
- Autorisation (RBAC)
- Chiffrement des communications (TLS/SSL)
- KeyFile pour Replica Set

**PARTIE 6 : Monitoring et maintenance**
- Surveillance du Replica Set
- Métriques importantes
- Backup et restauration
- Logs et diagnostic

**PARTIE 7 : Performance et optimisation**
- Indexation
- Tuning du Replica Set
- Gestion de l'oplog
- Compression

**PARTIE 8 : Cas pratiques et exercices**
- Scénarios réels
- Dépannage de problèmes courants
- Scripts d'automatisation
- Best practices

**[RAPIDE] Ton Replica Set est maintenant opérationnel ! Continue vers la PARTIE 4 pour maîtriser les opérations avancées ! ->**


# [COURS] GUIDE MONGODB REPLICA SET - PARTIE 4

## [OBJECTIF] OPÉRATIONS AVANCÉES DU REPLICA SET

### READ PREFERENCE - Où lire les données ?

**Concept :**
```
Read Preference = Préférence de lecture
Définit depuis QUEL membre du Replica Set lire les données
```

**5 modes disponibles :**

| Mode | Lecture depuis | Cas d'usage |
|------|----------------|-------------|
| **primary** | PRIMARY uniquement | Données toujours à jour (défaut) |
| **primaryPreferred** | PRIMARY en priorité, SECONDARY si PRIMARY down | Haute disponibilité |
| **secondary** | SECONDARY uniquement | Décharger le PRIMARY |
| **secondaryPreferred** | SECONDARY en priorité, PRIMARY en dernier recours | Lectures à fort volume |
| **nearest** | Membre le plus proche (latence réseau) | Applications géo-distribuées |

---

#### Mode PRIMARY (défaut)

```javascript
// Lire depuis le PRIMARY
db.getMongo().setReadPref('primary')

db.users.find()
// [OK] Données TOUJOURS à jour
// [X] Charge le PRIMARY
```

**Quand l'utiliser ?**
- Données critiques nécessitant la plus grande cohérence
- Lectures après écritures immédiates
- Par défaut si pas de préférence spécifiée

---

#### Mode SECONDARY

```javascript
// Lire depuis un SECONDARY
db.getMongo().setReadPref('secondary')

db.users.find()
// [OK] Décharge le PRIMARY
// [ATTENTION] Données peuvent être légèrement obsolètes (lag de réplication)
```

**Quand l'utiliser ?**
- Analytics et rapports
- Recherches complexes
- Données où un léger retard est acceptable

---

#### Mode NEAREST

```javascript
// Lire depuis le membre le plus proche
db.getMongo().setReadPref('nearest')

db.users.find()
// [OK] Latence minimale
// [ATTENTION] Peut lire depuis n'importe quel membre
```

**Quand l'utiliser ?**
- Applications multi-régions
- Optimisation de la latence
- Lecture de données non critiques

---

### WRITE CONCERN - Garanties d'écriture

**Concept :**
```
Write Concern = Niveau de garantie d'écriture
Combien de membres doivent confirmer avant que l'écriture soit considérée réussie ?
```

**Syntaxe :**
```javascript
db.collection.insertOne(
  { data: "..." },
  { writeConcern: { w: X, j: true, wtimeout: 5000 } }
)
```

**Paramètres :**

| Paramètre | Valeurs | Signification |
|-----------|---------|---------------|
| **w** | 1 | PRIMARY uniquement (rapide, risque de perte) |
|  | 2 | PRIMARY + 1 SECONDARY |
|  | 3 | PRIMARY + 2 SECONDARY |
|  | "majority" | Majorité des membres (RECOMMANDÉ) |
| **j** | true | Attendre écriture sur disque (journal) |
|  | false | Écriture en mémoire suffit |
| **wtimeout** | millisecondes | Timeout si les membres ne répondent pas |

---

#### Exemples de Write Concern

**1. w: 1 (par défaut, rapide mais risqué)**

```javascript
db.orders.insertOne(
  { product: "Laptop", price: 999 },
  { writeConcern: { w: 1 } }
)

// [OK] Rapide (PRIMARY uniquement)
// [X] Si PRIMARY crash avant réplication -> PERTE DE DONNÉES
```

**Utilisation :** Logs, données non critiques

---

**2. w: "majority" (recommandé en production)**

```javascript
db.orders.insertOne(
  { product: "Laptop", price: 999 },
  { writeConcern: { w: "majority", j: true, wtimeout: 5000 } }
)

// [OK] Garantie de durabilité (majorité + journal)
// [ATTENTION] Plus lent (attente de réplication)
```

**Utilisation :** Transactions financières, données critiques

---

**3. w: 3 (tous les membres)**

```javascript
db.orders.insertOne(
  { product: "Laptop", price: 999 },
  { writeConcern: { w: 3, j: true } }
)

// [OK] Garantie maximale (PRIMARY + 2 SECONDARY + journal)
// [X] Très lent
// [X] Échoue si un membre est down
```

**Utilisation :** Données ultra-critiques (rare)

---

### READ CONCERN - Garanties de lecture

**Concept :**
```
Read Concern = Niveau de garantie de lecture
Quelle "fraîcheur" des données veux-tu ?
```

**Niveaux disponibles :**

| Niveau | Garantie | Performance |
|--------|----------|-------------|
| **local** | Aucune (lit la dernière version locale) | [RAPIDE] Très rapide |
| **available** | Comme local, mais pour sharded clusters | [RAPIDE] Très rapide |
| **majority** | Lit seulement données confirmées par majorité | [LENT] Plus lent |
| **linearizable** | Garantie de linéarisabilité (une seule lecture) | [TURTLE] Très lent |

---

#### Exemple de Read Concern

```javascript
// Lecture avec garantie "majority"
db.orders.find().readConcern("majority")

// [OK] Données confirmées par majorité
// [OK] Pas de rollback possible
// [ATTENTION] Plus lent
```

**Quand l'utiliser ?**
- Lectures critiques après écritures importantes
- Transactions nécessitant forte cohérence
- Garantie contre les rollbacks

---

### GESTION DES PRIORITÉS

**Concept :**
```
Priorité = Probabilité qu'un membre devienne PRIMARY lors d'une élection
Valeur : 0 à 1000 (défaut : 1)
Priorité 0 = Ne peut JAMAIS devenir PRIMARY
```

---

#### Modifier les priorités

**1. Voir la configuration actuelle :**

```javascript
rs.conf().members.forEach(m => {
  print(`${m.host.padEnd(25)} | Priority: ${m.priority}`)
})
```

**Résultat :**
```
192.168.1.10:27017        | Priority: 2
192.168.1.20:27017        | Priority: 1
192.168.1.10:27018        | Priority: 0  <- ARBITER
```

---

**2. Changer la priorité d'un membre :**

```javascript
// Récupérer la config
cfg = rs.conf()

// Machine 1 : Priorité maximale (toujours PRIMARY si disponible)
cfg.members[0].priority = 10

// Machine 2 : Priorité minimale (PRIMARY uniquement si Machine 1 down)
cfg.members[1].priority = 1

// Appliquer la nouvelle config
rs.reconfig(cfg)
```

**Résultat :**
```
{
  ok: 1,
  '$clusterTime': { ... },
  operationTime: Timestamp({ ... })
}
```

---

**3. Forcer une élection :**

```javascript
// Sur le PRIMARY actuel, forcer à redevenir SECONDARY
rs.stepDown()

// Après 10-30 secondes, vérifier le nouveau PRIMARY
rs.isMaster().primary
```

---

### AJOUT DE MEMBRES

#### Ajouter un nouveau SECONDARY

**Prérequis :**
- Machine 3 avec MongoDB installé
- Fichier mongod.conf configuré avec `replSetName: rs0`
- MongoDB démarré

**Commande :**

```javascript
// Se connecter au PRIMARY
mongosh --host 192.168.1.10 --port 27017

// Ajouter le membre
rs.add({
  host: "192.168.1.30:27017",
  priority: 1,
  votes: 1
})
```

**Vérifier :**

```javascript
rs.status().members.forEach(m => {
  print(`${m.name.padEnd(25)} | ${m.stateStr}`)
})
```

**Résultat :**
```
192.168.1.10:27017        | PRIMARY
192.168.1.20:27017        | SECONDARY
192.168.1.10:27018        | ARBITER
192.168.1.30:27017        | SECONDARY  <- Nouveau membre ! [OK]
```

---

#### Ajouter un ARBITER supplémentaire

```javascript
// Ajouter un arbiter
rs.addArb("192.168.1.30:27018")
```

**[ATTENTION] Attention :** Maximum recommandé = 1 ARBITER par Replica Set

---

### SUPPRESSION DE MEMBRES

```javascript
// Retirer un membre
rs.remove("192.168.1.30:27017")

// Vérifier
rs.status().members.length  // Devrait afficher 3 (au lieu de 4)
```

---

### HIDDEN MEMBERS - Membres cachés

**Concept :**
```
Hidden Member = Membre SECONDARY caché
- Invisible pour l'application
- Ne reçoit JAMAIS de lectures
- Utilisé pour backup, analytics, reporting
```

**Configuration :**

```javascript
cfg = rs.conf()

// Trouver l'index du membre à cacher (ex: Machine 2)
// cfg.members[1] = 192.168.1.20:27017

cfg.members[1].hidden = true
cfg.members[1].priority = 0  // Ne peut pas devenir PRIMARY

rs.reconfig(cfg)
```

**Vérifier :**

```javascript
rs.isMaster().hosts
// Ne montre PAS le membre hidden ! [OK]
```

**Cas d'usage :**
- Serveur de backup dédié
- Serveur d'analytics (rapports lourds)
- Serveur de développement synchronisé avec prod

---

### DELAYED MEMBERS - Membres retardés

**Concept :**
```
Delayed Member = Membre SECONDARY avec décalage temporel
Exemple : Toujours 1 heure en retard par rapport au PRIMARY

Utilité : Protection contre erreurs humaines
Si quelqu'un supprime une base par erreur, on a 1h pour restaurer
depuis le membre retardé (avant qu'il ne réplique la suppression)
```

**Configuration :**

```javascript
cfg = rs.conf()

cfg.members[1].slaveDelay = 3600  // 3600 secondes = 1 heure
cfg.members[1].priority = 0       // Ne peut pas devenir PRIMARY
cfg.members[1].hidden = true      // Invisible pour l'application

rs.reconfig(cfg)
```

**Vérifier :**

```javascript
rs.conf().members[1]

// Résultat :
{
  _id: 1,
  host: '192.168.1.20:27017',
  priority: 0,
  hidden: true,
  slaveDelay: 3600  <- Décalage de 1h [OK]
}
```

---

## [LISTE] RÉCAPITULATIF PARTIE 4

**Compétences acquises :**

[OK] Read Preference (primary, secondary, nearest)
[OK] Write Concern (w, j, wtimeout)
[OK] Read Concern (local, majority, linearizable)
[OK] Gestion des priorités
[OK] Ajout/Suppression de membres
[OK] Hidden Members (backup, analytics)
[OK] Delayed Members (protection erreurs)

---

# [COURS] GUIDE MONGODB REPLICA SET - PARTIE 5

## [SECURISE] SÉCURITÉ DU REPLICA SET

### [ALERTE] POURQUOI LA SÉCURITÉ EST CRITIQUE ?

**Sans sécurité :**
```
[X] N'importe qui sur le réseau peut se connecter
[X] Lecture de toutes les données
[X] Suppression de bases entières
[X] Modification de la configuration
[X] Vol de données sensibles
```

**Avec sécurité :**
```
[OK] Authentification obligatoire
[OK] Accès contrôlé par utilisateur
[OK] Communications chiffrées
[OK] Audit des actions
[OK] Conformité (RGPD, SOC2, etc.)
```

---

### [CLE] AUTHENTIFICATION - Qui es-tu ?

#### Étape 1 : Créer un utilisateur admin (AVANT d'activer l'auth)

**Se connecter au PRIMARY :**

```bash
mongosh --host 192.168.1.10 --port 27017
```

**Créer l'utilisateur admin :**

```javascript
use admin

db.createUser({
  user: "admin",
  pwd: "VotreMo tDePasseTrèsSécurisé123!",  // [ATTENTION] Change ça !
  roles: [
    { role: "root", db: "admin" }
  ]
})
```

**Résultat :**
```javascript
{ ok: 1 }  <- Utilisateur créé ! [OK]
```

**Explication des rôles :**

| Rôle | Permissions |
|------|-------------|
| **root** | Tous les droits (super admin) |
| **userAdminAnyDatabase** | Gérer les utilisateurs |
| **dbAdminAnyDatabase** | Administrer toutes les bases |
| **readWriteAnyDatabase** | Lire/écrire toutes les bases |
| **readAnyDatabase** | Lire toutes les bases |
| **dbOwner** | Propriétaire d'une base spécifique |
| **readWrite** | Lire/écrire une base spécifique |
| **read** | Lire une base spécifique |

---

#### Étape 2 : Générer un KeyFile (pour communication interne)

**Qu'est-ce qu'un KeyFile ?**
```
KeyFile = Fichier contenant un mot de passe partagé
Utilisé par les membres du Replica Set pour s'authentifier entre eux

Analogie : Mot de passe secret que seuls les membres connaissent
```

**Génération du KeyFile (sur Machine 1) :**

**Linux/macOS :**
```bash
# Générer le keyfile (512 caractères aléatoires)
openssl rand -base64 756 > /tmp/mongodb-keyfile

# Copier vers le bon répertoire
sudo cp /tmp/mongodb-keyfile /etc/mongodb-keyfile

# Permissions STRICTES (obligatoire)
sudo chmod 400 /etc/mongodb-keyfile
sudo chown mongodb:mongodb /etc/mongodb-keyfile

# Vérifier
ls -l /etc/mongodb-keyfile
```

**Résultat :**
```
-r-------- 1 mongodb mongodb 1024 Dec 16 10:00 /etc/mongodb-keyfile
 ^^^^^^^^^^
Seul le propriétaire peut lire (obligatoire pour MongoDB)
```

**Windows (PowerShell Administrateur) :**
```powershell
# Générer le keyfile
$bytes = New-Object byte[] 756
(New-Object Security.Cryptography.RNGCryptoServiceProvider).GetBytes($bytes)
[Convert]::ToBase64String($bytes) | Out-File -FilePath "C:\Program Files\MongoDB\mongodb-keyfile" -Encoding ASCII

# Permissions (via l'explorateur ou icacls)
icacls "C:\Program Files\MongoDB\mongodb-keyfile" /inheritance:r /grant:r "SYSTEM:(R)" "Administrators:(R)"
```

---

#### Étape 3 : Copier le KeyFile sur toutes les machines

**Le MÊME keyfile doit être sur TOUS les membres !**

**Méthode 1 : SCP (Linux/macOS)**

```bash
# Depuis Machine 1, copier vers Machine 2
scp /etc/mongodb-keyfile user@192.168.1.20:/tmp/

# Sur Machine 2, déplacer et configurer permissions
sudo mv /tmp/mongodb-keyfile /etc/mongodb-keyfile
sudo chmod 400 /etc/mongodb-keyfile
sudo chown mongodb:mongodb /etc/mongodb-keyfile
```

**Méthode 2 : Réseau Windows**
```
1. Partager le dossier contenant mongodb-keyfile
2. Copier depuis Machine 2
3. Configurer les permissions
```

---

#### Étape 4 : Modifier la configuration MongoDB (TOUS les membres)

**Éditer /etc/mongod.conf :**

```yaml
# Ajouter cette section :
security:
  authorization: enabled
  keyFile: /etc/mongodb-keyfile  # Linux/macOS
  # keyFile: C:\Program Files\MongoDB\mongodb-keyfile  # Windows
```

**Configuration complète exemple (PRIMARY) :**

```yaml
storage:
  dbPath: /var/lib/mongodb

systemLog:
  destination: file
  path: /var/log/mongodb/mongod.log

net:
  port: 27017
  bindIp: 0.0.0.0

replication:
  replSetName: rs0

# ────────────────────────────────────────────────────
# SÉCURITÉ ACTIVÉE [OK]
# ────────────────────────────────────────────────────
security:
  authorization: enabled
  keyFile: /etc/mongodb-keyfile
```

**Sauvegarder et répéter sur TOUS les membres !**

---

#### Étape 5 : Redémarrer MongoDB (TOUS les membres)

**[ATTENTION] IMPORTANT : Redémarrer UN PAR UN pour éviter interruption !**

**Ordre recommandé :**
```
1. SECONDARY (Machine 2)     <- Commence par lui
2. ARBITER (Machine 1:27018)  <- Ensuite
3. PRIMARY (Machine 1:27017)  <- En dernier
```

**Machine 2 (SECONDARY) :**
```bash
sudo systemctl restart mongod
```

**Attendre 30 secondes, puis Machine 1 (ARBITER) :**
```bash
sudo mongod --shutdown --config /etc/mongod-arbiter.conf
sudo mongod --config /etc/mongod-arbiter.conf &
```

**Attendre 30 secondes, puis Machine 1 (PRIMARY) :**
```bash
sudo systemctl restart mongod
```

---

#### Étape 6 : Tester l'authentification

**SANS authentification (devrait échouer) :**

```bash
mongosh --host 192.168.1.10 --port 27017

# Essayer une commande
show dbs
```

**Résultat :**
```
MongoServerError: command listDatabases requires authentication
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
           Authentification obligatoire ! [OK]
```

**AVEC authentification (devrait fonctionner) :**

```bash
mongosh --host 192.168.1.10 --port 27017 -u admin -p --authenticationDatabase admin
```

**Entrer le mot de passe, puis :**

```javascript
show dbs
```

**Résultat :**
```
admin   100.00 KiB
config   60.00 KiB
local   100.00 KiB
testdb   40.00 KiB

[OK] Authentification réussie !
```

---

### [UTILISATEURS] AUTORISATION (RBAC - Role-Based Access Control)

**RBAC = Contrôle d'accès basé sur les rôles**

**Principe :**
```
Chaque utilisateur a un ou plusieurs RÔLES
Chaque RÔLE donne certaines PERMISSIONS
```

---

#### Créer des utilisateurs avec rôles spécifiques

**Utilisateur 1 : Admin de base de données**

```javascript
use admin

db.createUser({
  user: "dbadmin",
  pwd: "MotDePasseDbAdmin123!",
  roles: [
    { role: "dbAdminAnyDatabase", db: "admin" },
    { role: "readWriteAnyDatabase", db: "admin" }
  ]
})
```

**Permissions :** Gérer toutes les bases, lire/écrire

---

**Utilisateur 2 : Développeur (lecture/écriture sur une base spécifique)**

```javascript
use myapp

db.createUser({
  user: "dev",
  pwd: "MotDePasseDev123!",
  roles: [
    { role: "readWrite", db: "myapp" }
  ]
})
```

**Permissions :** Lire/écrire UNIQUEMENT dans "myapp"

---

**Utilisateur 3 : Lecteur (analytics, rapports)**

```javascript
use myapp

db.createUser({
  user: "analyst",
  pwd: "MotDePasseAnalyst123!",
  roles: [
    { role: "read", db: "myapp" }
  ]
})
```

**Permissions :** Lire UNIQUEMENT dans "myapp" (pas d'écriture)

---

#### Tester les permissions

**Test 1 : Utilisateur "dev"**

```bash
mongosh --host 192.168.1.10 --port 27017 -u dev -p --authenticationDatabase myapp
```

```javascript
use myapp

// [OK] Devrait fonctionner
db.products.insertOne({ name: "Laptop", price: 999 })

use admin

// [X] Devrait échouer
show dbs
```

**Résultat :**
```
MongoServerError: not authorized on admin to execute command
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
          Pas accès à "admin" ! [OK] (normal)
```

---

**Test 2 : Utilisateur "analyst"**

```bash
mongosh --host 192.168.1.10 --port 27017 -u analyst -p --authenticationDatabase myapp
```

```javascript
use myapp

// [OK] Devrait fonctionner
db.products.find()

// [X] Devrait échouer
db.products.insertOne({ name: "Mouse", price: 25 })
```

**Résultat :**
```
MongoServerError: not authorized on myapp to execute command { insert: "products" }
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^
          Lecture seule ! [OK] (normal)
```

---

### [VERROUILLE] CHIFFREMENT DES COMMUNICATIONS (TLS/SSL)

**Pourquoi chiffrer ?**
```
Sans TLS : Données en clair sur le réseau
           v
     Interception possible (man-in-the-middle)
           v
     Vol de mots de passe et données

Avec TLS : Données chiffrées
           v
     Impossible à lire même si interceptées
```

---

#### Étape 1 : Générer des certificats

**Option 1 : Auto-signés (développement/test)**

```bash
# Générer un certificat auto-signé
openssl req -newkey rsa:2048 -new -x509 -days 365 -nodes \
  -out /etc/ssl/mongodb-cert.crt \
  -keyout /etc/ssl/mongodb-cert.key

# Combiner certificat et clé
cat /etc/ssl/mongodb-cert.key /etc/ssl/mongodb-cert.crt > /etc/ssl/mongodb.pem

# Permissions
sudo chmod 600 /etc/ssl/mongodb.pem
```

**Option 2 : Certificats d'autorité (production)**
```
Utiliser Let's Encrypt ou une CA interne
(Plus complexe, voir documentation officielle)
```

---

#### Étape 2 : Configurer MongoDB pour TLS

**Éditer /etc/mongod.conf :**

```yaml
net:
  port: 27017
  bindIp: 0.0.0.0
  tls:
    mode: requireTLS
    certificateKeyFile: /etc/ssl/mongodb.pem
    # CAFile: /etc/ssl/ca.pem  # Si CA externe
    allowConnectionsWithoutCertificates: true  # Clients sans certificat OK
```

**Redémarrer MongoDB :**
```bash
sudo systemctl restart mongod
```

---

#### Étape 3 : Se connecter avec TLS

```bash
mongosh --host 192.168.1.10 --port 27017 \
  --tls \
  --tlsCAFile /etc/ssl/ca.pem \
  -u admin -p --authenticationDatabase admin
```

**[OK] Connexion chiffrée !**

---

### [RECHERCHE] AUDIT - Qui fait quoi ?

**Activer l'audit (MongoDB Enterprise uniquement) :**

```yaml
auditLog:
  destination: file
  format: JSON
  path: /var/log/mongodb/audit.json
  filter: '{ atype: { $in: ["authenticate", "createUser", "dropDatabase"] } }'
```

**Logs d'audit contiennent :**
- Qui s'est connecté
- Quelles commandes ont été exécutées
- Quand
- Depuis quelle IP

**Utile pour :**
- Conformité (RGPD, SOC2)
- Investigation après incident
- Détection d'anomalies

---

## [LISTE] CHECKLIST SÉCURITÉ

**Pour production, vérifie que tu as :**

- [ ] Authentification activée (`authorization: enabled`)
- [ ] KeyFile configuré sur tous les membres
- [ ] Utilisateur admin créé
- [ ] Utilisateurs avec privilèges minimaux (principe du moindre privilège)
- [ ] TLS/SSL activé
- [ ] bindIp limité (pas 0.0.0.0 si possible)
- [ ] Pare-feu configuré (autoriser uniquement IPs nécessaires)
- [ ] Mots de passe forts (>12 caractères, complexes)
- [ ] Audit activé (si Enterprise)
- [ ] Backups chiffrés
- [ ] Certificats à jour
- [ ] Monitoring actif

---

# [COURS] GUIDE MONGODB REPLICA SET - PARTIE 6

## [GRAPHIQUE] MONITORING ET MAINTENANCE

### [RECHERCHE] MÉTRIQUES IMPORTANTES À SURVEILLER

#### 1. Statut du Replica Set

**Commande de base :**
```javascript
rs.status()
```

**Métriques clés :**

| Métrique | Valeur saine | Alerte si |
|----------|--------------|-----------|
| **health** | 1 | health = 0 |
| **stateStr** | PRIMARY/SECONDARY | RECOVERING, UNKNOWN |
| **uptime** | Croissant | Redémarrages fréquents |
| **optimeDate** | Récent | Décalage > 10 secondes |
| **lastHeartbeat** | < 2 secondes | > 10 secondes |

**Script de monitoring simple :**

```javascript
function checkReplicaSetHealth() {
  var status = rs.status();
  var issues = [];
  
  status.members.forEach(function(member) {
    // Vérifier la santé
    if (member.health !== 1) {
      issues.push(`${member.name} is UNHEALTHY (health: ${member.health})`);
    }
    
    // Vérifier l'état
    if (member.stateStr === 'UNKNOWN' || member.stateStr === 'DOWN') {
      issues.push(`${member.name} is ${member.stateStr}`);
    }
    
    // Vérifier le lag de réplication (si SECONDARY)
    if (member.stateStr === 'SECONDARY') {
      var primary = status.members.find(m => m.stateStr === 'PRIMARY');
      if (primary) {
        var lag = (primary.optimeDate - member.optimeDate) / 1000; // secondes
        if (lag > 10) {
          issues.push(`${member.name} has replication lag of ${lag.toFixed(2)}s`);
        }
      }
    }
  });
  
  if (issues.length > 0) {
    print("[ATTENTION]  ISSUES FOUND:");
    issues.forEach(issue => print(`   - ${issue}`));
    return false;
  } else {
    print("[OK] Replica Set is healthy");
    return true;
  }
}

// Exécuter
checkReplicaSetHealth()
```

---

#### 2. Oplog (Replication Log)

**Qu'est-ce que l'oplog ?**
```
Oplog = Operation Log
Journal circulaire des opérations sur le PRIMARY
Les SECONDARY lisent l'oplog pour se synchroniser

Analogie : Film d'une caméra de surveillance
          Les gardiens (SECONDARY) regardent le film pour savoir ce qui s'est passé
```

**Vérifier la taille de l'oplog :**

```javascript
use local
db.oplog.rs.stats()
```

**Métriques importantes :**

```javascript
{
  size: 1073741824,           // Taille max (1 GB ici)
  storageSize: 536870912,     // Espace utilisé (512 MB)
  ...
}
```

**Calculer la fenêtre temporelle de l'oplog :**

```javascript
db.getReplicationInfo()
```

**Résultat :**
```javascript
{
  logSizeMB: 1024,              // Taille de l'oplog (MB)
  usedMB: 512,                  // Utilisé (MB)
  timeDiff: 86400,              // Durée couverte (secondes)
  timeDiffHours: 24,            // Durée couverte (heures)
  tFirst: '2024-12-15T10:00:00Z',  // Première opération
  tLast: '2024-12-16T10:00:00Z',   // Dernière opération
  now: '2024-12-16T10:00:00Z'
}
```

**Interprétation :**
```
timeDiffHours: 24 = L'oplog couvre 24 heures d'opérations

Si un SECONDARY est arrêté > 24h :
-> Il ne pourra PAS se resynchroniser automatiquement
-> Nécessitera une resynchronisation complète (lente)

Recommandation : Oplog doit couvrir au moins 48-72h
```

**Augmenter la taille de l'oplog :**

```javascript
// 1. Se connecter au PRIMARY
use local

// 2. Voir la taille actuelle
db.oplog.rs.stats().maxSize / 1024 / 1024  // MB

// 3. Augmenter (nécessite MongoDB 4.0+)
db.adminCommand({
  replSetResizeOplog: 1,
  size: 2048  // 2 GB
})
```

---

#### 3. Performance des opérations

**Voir les opérations en cours :**

```javascript
db.currentOp()
```

**Filtrer les opérations lentes (> 1000ms) :**

```javascript
db.currentOp({
  "secs_running": { $gt: 1 },
  "op": { $in: ["query", "update", "remove"] }
})
```

**Tuer une opération bloquante :**

```javascript
// Trouver l'opID
db.currentOp().inprog.find(op => op.secs_running > 10).opid

// Tuer
db.killOp(12345)  // Remplacer 12345 par l'opID réel
```

---

### [HAUSSE] OUTILS DE MONITORING

#### MongoDB Compass

**Interface graphique officielle de MongoDB**

**Fonctionnalités :**
- Vue en temps réel du Replica Set
- Graphiques de performance
- Visualisation des données
- Query profiler

**Installation :**
```
Téléchargement : https://www.mongodb.com/try/download/compass
```

**Connexion à un Replica Set :**
```
mongodb://admin:password@192.168.1.10:27017,192.168.1.20:27017,192.168.1.10:27018/?replicaSet=rs0&authSource=admin
```

---

#### MongoDB Atlas (Cloud)

**Si tu veux un monitoring professionnel gratuit :**

```
1. Créer un compte Atlas gratuit
2. Activer "MongoDB Cloud Manager"
3. Installer l'agent de monitoring sur tes serveurs
4. Dashboard complet avec alertes
```

**Métriques disponibles :**
- CPU, RAM, Disk I/O
- Oplog lag
- Nombre de connexions
- Latence des requêtes
- etc.

---

### [OUTIL] MAINTENANCE PRÉVENTIVE

#### 1. Rotation des logs

**Problème :**
```
Les logs MongoDB grandissent indéfiniment
-> Disque plein
-> MongoDB crash
```

**Solution : Rotation automatique**

**Linux (logrotate) :**

```bash
sudo nano /etc/logrotate.d/mongodb
```

**Contenu :**
```
/var/log/mongodb/*.log {
    daily                # Rotation quotidienne
    rotate 7             # Garder 7 jours
    missingok           # OK si le fichier n'existe pas
    notifempty          # Ne pas faire tourner si vide
    compress            # Compresser les anciens logs
    delaycompress       # Compresser le jour suivant
    postrotate
        # Demander à MongoDB de rouvrir ses fichiers de log
        /bin/kill -SIGUSR1 $(cat /var/run/mongodb/mongod.pid 2>/dev/null) 2>/dev/null || true
    endscript
}
```

**Tester :**
```bash
sudo logrotate -f /etc/logrotate.d/mongodb
```

---

#### 2. Compact des collections (défragmentation)

**Problème :**
```
Après beaucoup de suppressions, les fichiers de données sont fragmentés
-> Gaspillage d'espace disque
-> Performances dégradées
```

**Solution : Compacter**

```javascript
// [ATTENTION] ATTENTION : Bloque la collection pendant l'opération !
// À faire pendant maintenance window

use myapp
db.users.compact()
```

**Pour tout compacter :**

```javascript
// Obtenir toutes les collections
var collections = db.getCollectionNames();

// Compacter chaque collection
collections.forEach(function(collection) {
  print(`Compacting ${collection}...`);
  db[collection].compact();
  print(`[OK] ${collection} compacted`);
});
```

---

#### 3. Rebuild des index

**Quand ?**
- Après corruption
- Après migration
- Pour optimiser les performances

**Commande :**

```javascript
use myapp

// Reconstruire TOUS les index d'une collection
db.users.reIndex()

// Reconstruire un index spécifique
db.users.dropIndex("email_1")
db.users.createIndex({ email: 1 }, { unique: true })
```

---

### [SAUVEGARDE] BACKUP ET RESTAURATION

#### Stratégie de backup

**3 types de backup :**

| Type | Méthode | Avantages | Inconvénients |
|------|---------|-----------|---------------|
| **Logical** | mongodump | Simple, portable | Lent pour gros volumes |
| **Physical** | Snapshot disque | Rapide | Nécessite arrêt ou freeze |
| **Continuous** | Oplog tailing | Point-in-time recovery | Complexe |

---

#### Backup avec mongodump

**Backup complet :**

```bash
mongodump \
  --host="192.168.1.10:27017" \
  --username="admin" \
  --password="MotDePasse" \
  --authenticationDatabase="admin" \
  --out=/backup/mongodb/$(date +%Y%m%d)
```

**Backup d'une base spécifique :**

```bash
mongodump \
  --host="192.168.1.10:27017" \
  --db="myapp" \
  --username="admin" \
  --password="MotDePasse" \
  --authenticationDatabase="admin" \
  --out=/backup/mongodb/myapp-$(date +%Y%m%d)
```

**Backup avec compression :**

```bash
mongodump \
  --host="192.168.1.10:27017" \
  --username="admin" \
  --password="MotDePasse" \
  --authenticationDatabase="admin" \
  --gzip \
  --archive=/backup/mongodb/backup-$(date +%Y%m%d).gz
```

---

#### Restauration avec mongorestore

**Restauration complète :**

```bash
mongorestore \
  --host="192.168.1.10:27017" \
  --username="admin" \
  --password="MotDePasse" \
  --authenticationDatabase="admin" \
  /backup/mongodb/20241216
```

**Restauration d'une base spécifique :**

```bash
mongorestore \
  --host="192.168.1.10:27017" \
  --db="myapp" \
  --username="admin" \
  --password="MotDePasse" \
  --authenticationDatabase="admin" \
  /backup/mongodb/myapp-20241216/myapp
```

**Restauration depuis archive compressée :**

```bash
mongorestore \
  --host="192.168.1.10:27017" \
  --username="admin" \
  --password="MotDePasse" \
  --authenticationDatabase="admin" \
  --gzip \
  --archive=/backup/mongodb/backup-20241216.gz
```

---

#### Script de backup automatique

**Créer un script :**

```bash
sudo nano /usr/local/bin/mongodb-backup.sh
```

**Contenu :**

```bash
#!/bin/bash

# ═══════════════════════════════════════════════════════════════
# SCRIPT DE BACKUP AUTOMATIQUE MONGODB
# ═══════════════════════════════════════════════════════════════

# Configuration
BACKUP_DIR="/backup/mongodb"
RETENTION_DAYS=7
MONGO_HOST="192.168.1.10:27017"
MONGO_USER="admin"
MONGO_PASS="VotreMotDePasse"
DATE=$(date +%Y%m%d_%H%M%S)

# Créer le dossier de backup
mkdir -p "$BACKUP_DIR"

# Backup
echo "[SYNC] Starting backup at $(date)"
mongodump \
  --host="$MONGO_HOST" \
  --username="$MONGO_USER" \
  --password="$MONGO_PASS" \
  --authenticationDatabase="admin" \
  --gzip \
  --archive="$BACKUP_DIR/backup-$DATE.gz"

# Vérifier le succès
if [ $? -eq 0 ]; then
  echo "[OK] Backup successful: $BACKUP_DIR/backup-$DATE.gz"
else
  echo "[X] Backup failed!"
  exit 1
fi

# Nettoyer les anciens backups
echo "[NETTOYAGE] Cleaning old backups (keeping last $RETENTION_DAYS days)"
find "$BACKUP_DIR" -name "backup-*.gz" -mtime +$RETENTION_DAYS -delete

echo "[OK] Backup completed at $(date)"
```

**Rendre exécutable :**

```bash
sudo chmod +x /usr/local/bin/mongodb-backup.sh
```

**Tester :**

```bash
sudo /usr/local/bin/mongodb-backup.sh
```

---

#### Automatiser avec cron

```bash
sudo crontab -e
```

**Ajouter :**

```bash
# Backup quotidien à 2h du matin
0 2 * * * /usr/local/bin/mongodb-backup.sh >> /var/log/mongodb-backup.log 2>&1

# Backup toutes les 6 heures
0 */6 * * * /usr/local/bin/mongodb-backup.sh >> /var/log/mongodb-backup.log 2>&1
```

---

### [LISTE] CHECKLIST DE MAINTENANCE MENSUELLE

**À faire chaque mois :**

- [ ] Vérifier le statut du Replica Set (`rs.status()`)
- [ ] Vérifier l'oplog coverage (> 48h)
- [ ] Vérifier l'espace disque (> 20% libre)
- [ ] Vérifier les logs d'erreurs
- [ ] Tester un backup et une restauration
- [ ] Vérifier les versions de MongoDB (mises à jour dispo ?)
- [ ] Vérifier les certificats TLS (expiration ?)
- [ ] Réviser les utilisateurs et permissions
- [ ] Analyser les requêtes lentes
- [ ] Vérifier la fragmentation des index

---

# [COURS] GUIDE MONGODB REPLICA SET - PARTIES 7 & 8

## [RAPIDE] PARTIE 7 : PERFORMANCE ET OPTIMISATION

### [GRAPHIQUE] INDEXATION

**Sans index :**
```
MongoDB parcourt TOUS les documents (collection scan)
1 million de documents = 1 million de lectures
Temps : Plusieurs secondes [ALARM_CLOCK]
```

**Avec index :**
```
MongoDB utilise l'index (arbre B-tree)
1 million de documents = ~20 lectures
Temps : Millisecondes [RAPIDE]
```

#### Créer des index

```javascript
// Index simple
db.users.createIndex({ email: 1 })  // 1 = ascendant, -1 = descendant

// Index composé
db.orders.createIndex({ userId: 1, date: -1 })

// Index unique
db.users.createIndex({ email: 1 }, { unique: true })

// Index texte (recherche full-text)
db.articles.createIndex({ title: "text", content: "text" })

// Index géospatial
db.restaurants.createIndex({ location: "2dsphere" })
```

#### Analyser les performances

```javascript
// Analyser une requête
db.users.find({ email: "alice@example.com" }).explain("executionStats")

// Voir les index existants
db.users.getIndexes()

// Supprimer un index
db.users.dropIndex("email_1")
```

---

### [OBJECTIF] WRITE CONCERN ET READ CONCERN OPTIMAUX

**Pour haute performance :**
```javascript
// Write Concern relâché (rapide mais risqué)
db.logs.insertOne(
  { message: "test" },
  { writeConcern: { w: 1, j: false } }
)
```

**Pour haute cohérence :**
```javascript
// Write Concern strict (lent mais sûr)
db.orders.insertOne(
  { total: 999 },
  { writeConcern: { w: "majority", j: true, wtimeout: 5000 } }
)
```

---

### [OUTIL] TUNING DU REPLICA SET

#### Configuration WiredTiger optimale

```yaml
storage:
  wiredTiger:
    engineConfig:
      cacheSizeGB: 8  # 50-80% de la RAM disponible
      journalCompressor: snappy
    collectionConfig:
      blockCompressor: snappy
    indexConfig:
      prefixCompression: true
```

#### Tuning réseau

```yaml
net:
  maxIncomingConnections: 10000
  compression:
    compressors: snappy,zstd,zlib
```

---

## [COURS] PARTIE 8 : CAS PRATIQUES ET EXERCICES

### [NOTE] EXERCICE 1 : Configuration complète (***)

**Objectif :** Configurer un Replica Set 5 membres

**Mission :**
1. 3 membres normaux (PRIMARY + 2 SECONDARY)
2. 1 HIDDEN membre (analytics)
3. 1 DELAYED membre (1h de retard)

**Solution :**
```javascript
rs.initiate({
  _id: "rs0",
  members: [
    { _id: 0, host: "192.168.1.10:27017", priority: 3 },
    { _id: 1, host: "192.168.1.20:27017", priority: 2 },
    { _id: 2, host: "192.168.1.30:27017", priority: 1 },
    { 
      _id: 3, 
      host: "192.168.1.40:27017", 
      priority: 0, 
      hidden: true 
    },
    { 
      _id: 4, 
      host: "192.168.1.50:27017", 
      priority: 0, 
      hidden: true,
      slaveDelay: 3600
    }
  ]
})
```

---

### [HOT] PROBLÈMES COURANTS ET SOLUTIONS

#### Problème 1 : "not master and slaveOk=false"

**Symptôme :**
```javascript
db.users.find()
MongoServerError: not master and slaveOk=false
```

**Cause :** Tentative de lecture sur SECONDARY sans autorisation

**Solution :**
```javascript
rs.secondaryOk()
// Ou
db.getMongo().setReadPref('secondary')
```

---

#### Problème 2 : Réplication lag élevé

**Symptôme :**
```javascript
rs.printSecondaryReplicationInfo()
// syncedTo: 5 minutes behind the primary
```

**Causes possibles :**
1. Réseau lent
2. SECONDARY surchargé
3. Oplog trop petit
4. Index manquant sur SECONDARY

**Solutions :**
```javascript
// 1. Augmenter l'oplog
db.adminCommand({ replSetResizeOplog: 1, size: 4096 })

// 2. Vérifier les index
db.users.getIndexes()

// 3. Réduire la charge (désactiver lectures sur ce SECONDARY)
cfg = rs.conf()
cfg.members[1].priority = 0
cfg.members[1].hidden = true
rs.reconfig(cfg)
```

---

#### Problème 3 : "No PRIMARY elected"

**Symptôme :**
```javascript
rs.status()
// Tous les membres en SECONDARY, aucun PRIMARY
```

**Causes :**
- Majorité des membres down
- Problème réseau (split-brain)
- Configuration incorrecte

**Solution :**
```javascript
// Forcer une reconfiguration
cfg = rs.conf()
cfg.members = cfg.members.filter(m => m.health === 1)
rs.reconfig(cfg, { force: true })
```

---

### [DOCS] RESSOURCES SUPPLÉMENTAIRES

**Documentation officielle :**
- https://docs.mongodb.com/manual/replication/
- https://university.mongodb.com (cours gratuits)

**Livres recommandés :**
- "MongoDB: The Definitive Guide" - Kristina Chodorow
- "MongoDB in Action" - Kyle Banker

**Communauté :**
- MongoDB Community Forums
- Stack Overflow (tag mongodb)
- Discord MongoDB francophone

---

## [BRAVO] FÉLICITATIONS !

**Tu maîtrises maintenant :**

[OK] Installation de MongoDB
[OK] Configuration d'un Replica Set
[OK] Sécurité (authentification, autorisation, TLS)
[OK] Monitoring et maintenance
[OK] Performance et optimisation
[OK] Backup et restauration
[OK] Dépannage de problèmes courants

**Tu es prêt pour :**
- Déployer MongoDB en production
- Gérer des Replica Sets complexes
- Optimiser les performances
- Assurer la haute disponibilité

**Prochaines étapes suggérées :**
1. Sharding (pour scalabilité horizontale)
2. Change Streams (notifications temps réel)
3. Transactions multi-documents
4. Aggregation Pipeline avancée

**Bon courage dans tes projets MongoDB ! [RAPIDE]**



# [HOT] ANNEXE : PARE-FEU - POURQUOI NE JAMAIS LE DÉSACTIVER

## [ATTENTION] QUESTION FRÉQUENTE : "Pourquoi pas juste désactiver le pare-feu ?"

**C'est une question légitime ! Désactiver le pare-feu semble plus rapide :**

```
Désactiver pare-feu : 30 secondes
Créer une règle : 2 minutes

Différence : 1m30s

MAIS...
```

**Laisse-moi t'expliquer pourquoi ces 90 secondes supplémentaires peuvent te sauver des JOURS de cauchemar.**

---

## [ALERTE] CE QUI SE PASSE RÉELLEMENT SANS PARE-FEU

### Scénario Réel : 4 Minutes Avant l'Attaque

**Étude de l'University of Maryland (2007) :**
```
Honeypot (ordinateur piège) mis sur Internet sans pare-feu
        v
Résultat : Attaqué toutes les 4 MINUTES en moyenne
        v
Même sur un réseau local d'entreprise : Compromission en quelques heures
```

---

### Visualisation : Pare-feu Activé vs Désactivé

```
╔════════════════════════════════════════════════════════════════╗
║  PARE-FEU DÉSACTIVÉ = MAISON SANS PORTE                        ║
╚════════════════════════════════════════════════════════════════╝

Internet/Réseau local
        │
        │ TOUS les ports accessibles
        v
┌─────────────────────────────────────────────────────────┐
│   TON ORDINATEUR (Windows/Linux/Mac)                    │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  Port 27017: MongoDB         [OK] Ouvert                  │
│  Port 27018: MongoDB Arbiter [OK] Ouvert                  │
│  Port 3389:  RDP (Windows)   [OK] Ouvert <- DANGER !       │
│  Port 22:    SSH (Linux)     [OK] Ouvert <- DANGER !       │
│  Port 445:   SMB (Partage)   [OK] Ouvert <- DANGER !       │
│  Port 135:   RPC             [OK] Ouvert <- DANGER !       │
│  Port 5432:  PostgreSQL      [OK] Ouvert <- DANGER !       │
│  Port 3306:  MySQL           [OK] Ouvert <- DANGER !       │
│  Port 6379:  Redis           [OK] Ouvert <- DANGER !       │
│  ...                                                    │
│  65 535 ports potentiels     TOUS ACCESSIBLES [X]        │
│                                                         │
└─────────────────────────────────────────────────────────┘

CONSÉQUENCES :
[X] Bots automatisés scannent ces ports 24/7
[X] Tentatives de connexion par force brute
[X] Exploitation de vulnérabilités connues
[X] Ransomware (WannaCry utilisait le port 445)
[X] Vol de données
[X] Cryptomining malveillant


╔════════════════════════════════════════════════════════════════╗
║  PARE-FEU ACTIVÉ + RÈGLES SPÉCIFIQUES = MAISON SÉCURISÉE      ║
╚════════════════════════════════════════════════════════════════╝

Internet/Réseau local
        │
        │ Tentatives de connexion
        v
┌─────────────────────────────────────────────────────────┐
│   PARE-FEU (Filtre intelligent)                         │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  Port 27017: MongoDB         [OK] AUTORISÉ (règle)        │
│  Port 27018: MongoDB Arbiter [OK] AUTORISÉ (règle)        │
│  Port 3389:  RDP             [X] BLOQUÉ                  │
│  Port 22:    SSH             [X] BLOQUÉ                  │
│  Port 445:   SMB             [X] BLOQUÉ                  │
│  Port 135:   RPC             [X] BLOQUÉ                  │
│  Port 5432:  PostgreSQL      [X] BLOQUÉ                  │
│  Port 3306:  MySQL           [X] BLOQUÉ                  │
│  Port 6379:  Redis           [X] BLOQUÉ                  │
│  ...                                                    │
│  Tous les autres ports       [X] BLOQUÉS PAR DÉFAUT      │
│                                                         │
└─────────────────────────────────────────────────────────┘
        │
        │ SEULEMENT le trafic autorisé passe
        v
┌─────────────────────────────────────────────────────────┐
│   TON ORDINATEUR (Protégé)                              │
│                                                         │
│  [OK] MongoDB accessible UNIQUEMENT                       │
│  [OK] Tous les autres services protégés                   │
│                                                         │
└─────────────────────────────────────────────────────────┘

RÉSULTAT :
[OK] 99% des attaques automatiques bloquées
[OK] Exposition minimale
[OK] Conformité aux standards de sécurité
[OK] Tranquillité d'esprit
```

---

## [SKULL] CAS RÉELS D'ATTAQUES

### Cas 1 : WannaCry (2017)

**Ce qui s'est passé :**
```
Ransomware WannaCry
        v
Exploitait le port SMB (445) de Windows
        v
300 000 ordinateurs infectés en quelques jours
        v
Hôpitaux, entreprises, gouvernements paralysés
        v
Pertes estimées : 4 MILLIARDS de dollars
```

**Machines infectées :**
```
[X] Pare-feu désactivé + Port 445 ouvert = Infection GARANTIE
[OK] Pare-feu activé + Port 445 bloqué = AUCUNE infection
```

**Si ton pare-feu était désactivé en mai 2017 :**
```
1. WannaCry détecte ton port 445 ouvert
2. Infection automatique (aucune action de ta part)
3. Tous tes fichiers chiffrés
4. Demande de rançon : 300$ en Bitcoin
5. Perte de TOUTES tes données si pas de backup
```

---

### Cas 2 : Attaques MongoDB non sécurisées (2017)

**Ce qui s'est passé :**
```
Des milliers de serveurs MongoDB sur Internet
        v
Pare-feu désactivé + Pas d'authentification
        v
Bots automatisés scannent le port 27017
        v
Trouvent les bases non protégées
        v
Suppriment les données + Demandent une rançon
```

**Messages laissés par les pirates :**
```
Collection: README

{
  "_id": 1,
  "message": "Vos données ont été supprimées",
  "backup": "Nous avons une sauvegarde",
  "ransom": "Envoyez 0.2 Bitcoin à cette adresse",
  "deadline": "48 heures ou suppression définitive"
}
```

**Nombre de serveurs compromis :** Plus de 26 000 en janvier 2017

**SI ton pare-feu était désactivé :**
```
Ton MongoDB aurait été trouvé et compromis en quelques heures
```

---

### Cas 3 : Attaque de force brute RDP

**Scénario courant :**
```
Ton PC Windows à la maison
        v
Pare-feu désactivé -> Port 3389 (RDP) exposé
        v
Bot détecte le port ouvert
        v
Tentatives de connexion automatiques :
  - Administrator / password
  - Administrator / 123456
  - Administrator / admin
  - admin / admin
  ... (des millions de combinaisons)
        v
Mot de passe trouvé (si faible)
        v
Accès administrateur obtenu
        v
Installation de backdoor, malware, cryptominer
        v
[SKULL] Machine compromise à ton insu
```

**Temps moyen pour trouver un mot de passe faible :** Quelques heures à quelques jours

**Avec pare-feu activé :**
```
Port 3389 bloqué = Bot ne peut même pas tenter de se connecter
```

---

## [OBJECTIF] COMPARAISON TEMPS vs SÉCURITÉ

### Option 1 : Désactiver le pare-feu ([X] DANGEREUX)

```
┌─────────────────────────────────────────────────────────┐
│  DÉSACTIVER LE PARE-FEU                                 │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  [TEMPS]  Temps : 30 secondes                                │
│                                                         │
│  Windows :                                              │
│  1. Panneau de configuration                           │
│  2. Pare-feu Windows Defender                          │
│  3. Activer ou désactiver                              │
│  4. Désactiver (tous les réseaux)                      │
│                                                         │
│  Linux :                                               │
│  sudo ufw disable                                      │
│                                                         │
├─────────────────────────────────────────────────────────┤
│  CONSÉQUENCES :                                         │
│                                                         │
│  [X] 65 535 ports exposés                               │
│  [X] Vulnérable aux scans automatiques                  │
│  [X] Vulnérable aux attaques connues                    │
│  [X] Risque de ransomware élevé                         │
│  [X] Risque de vol de données                           │
│  [X] Violation des normes de sécurité                   │
│  [X] Non-conformité (RGPD, etc.)                        │
│  [X] Perte potentielle : TOUTES TES DONNÉES             │
│  [X] Temps de récupération : JOURS voire SEMAINES       │
│                                                         │
│  [ARGENT] Coût potentiel :                                   │
│     - Perte de données : Incalculable                  │
│     - Rançon : 300$ - 10 000$+                         │
│     - Temps de remise en état : 40h+                   │
│     - Réputation : Endommagée                          │
│                                                         │
└─────────────────────────────────────────────────────────┘

VERDICT : [INTERDIT] NE JAMAIS FAIRE
```

---

### Option 2 : PowerShell ([OK] RAPIDE ET SÉCURISÉ)

```
┌─────────────────────────────────────────────────────────┐
│  RÈGLE PARE-FEU VIA POWERSHELL (RECOMMANDÉ)            │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  [TEMPS]  Temps : 10 SECONDES                                │
│                                                         │
│  Windows (PowerShell Administrateur) :                 │
│                                                         │
│  New-NetFirewallRule -DisplayName "MongoDB RS" `       │
│    -Direction Inbound `                                │
│    -Protocol TCP `                                     │
│    -LocalPort 27017,27018 `                            │
│    -Action Allow                                       │
│                                                         │
│  Linux :                                               │
│                                                         │
│  sudo ufw allow 27017/tcp                              │
│  sudo ufw allow 27018/tcp                              │
│                                                         │
│  macOS :                                               │
│                                                         │
│  echo "pass in proto tcp to any port 27017" | \       │
│    sudo tee -a /etc/pf.conf                            │
│                                                         │
├─────────────────────────────────────────────────────────┤
│  CONSÉQUENCES :                                         │
│                                                         │
│  [OK] SEULEMENT ports 27017 et 27018 ouverts             │
│  [OK] 65 533 autres ports PROTÉGÉS                       │
│  [OK] Protection contre scans automatiques               │
│  [OK] Conformité aux bonnes pratiques                    │
│  [OK] Transférable en production                         │
│  [OK] Auditable                                          │
│  [OK] Pas de risque d'oublier de réactiver               │
│  [OK] Perte potentielle : AUCUNE (si bien configuré)     │
│                                                         │
│  [ARGENT] Coût :                                             │
│     - 10 secondes de ton temps                         │
│     - ZÉRO risque de perte de données                  │
│                                                         │
└─────────────────────────────────────────────────────────┘

VERDICT : [OK] MÉTHODE PROFESSIONNELLE
```

---

### Option 3 : Interface graphique ([OK] SÉCURISÉ mais plus long)

```
┌─────────────────────────────────────────────────────────┐
│  RÈGLE PARE-FEU VIA INTERFACE GRAPHIQUE                │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  [TEMPS]  Temps : 2 MINUTES                                  │
│                                                         │
│  Windows :                                              │
│  1. Panneau de configuration                           │
│  2. Système et sécurité                                │
│  3. Pare-feu Windows Defender                          │
│  4. Paramètres avancés                                 │
│  5. Règles de trafic entrant                           │
│  6. Nouvelle règle...                                  │
│  7. Type : Port                                        │
│  8. TCP                                                │
│  9. Ports spécifiques : 27017,27018                    │
│  10. Autoriser la connexion                            │
│  11. Domaine, Privé, Public : Cocher les 3             │
│  12. Nom : MongoDB Replica Set                         │
│  13. Terminer                                          │
│                                                         │
├─────────────────────────────────────────────────────────┤
│  CONSÉQUENCES :                                         │
│                                                         │
│  [OK] Identique à la méthode PowerShell                  │
│  [OK] Interface visuelle (plus clair pour débutants)     │
│  [OK] Même niveau de sécurité                            │
│                                                         │
└─────────────────────────────────────────────────────────┘

VERDICT : [OK] MÉTHODE SÉCURISÉE (juste plus longue)
```

---

## [SECURITE] PRINCIPE DE SÉCURITÉ : DÉFENSE EN PROFONDEUR

**Concept professionnel (Defense in Depth) :**

```
┌──────────────────────────────────────────────────────────┐
│                  SÉCURITÉ PAR COUCHES                     │
├──────────────────────────────────────────────────────────┤
│                                                          │
│  COUCHE 1 : PARE-FEU <-────────────── TU ES ICI          │
│  └─ Bloque 99% des attaques dès la porte                │
│                                                          │
│  COUCHE 2 : AUTHENTIFICATION                            │
│  └─ Même si un attaquant passe le pare-feu,             │
│     il faut un mot de passe                             │
│                                                          │
│  COUCHE 3 : AUTORISATION (RBAC)                         │
│  └─ Même authentifié, droits limités                    │
│                                                          │
│  COUCHE 4 : CHIFFREMENT (TLS/SSL)                       │
│  └─ Même en accès, données illisibles si interceptées   │
│                                                          │
│  COUCHE 5 : AUDIT & MONITORING                          │
│  └─ Détection d'activité suspecte                       │
│                                                          │
│  COUCHE 6 : BACKUP                                      │
│  └─ Même si tout échoue, données récupérables           │
│                                                          │
└──────────────────────────────────────────────────────────┘

ANALOGIE : Château fort médiéval

Couche 1 (Pare-feu)      = Douves et pont-levis
Couche 2 (Auth)          = Porte principale avec garde
Couche 3 (RBAC)          = Accès limités par zone
Couche 4 (Chiffrement)   = Coffres verrouillés
Couche 5 (Monitoring)    = Patrouilles régulières
Couche 6 (Backup)        = Copie des documents précieux ailleurs

═══════════════════════════════════════════════════════════

SANS COUCHE 1 (Pare-feu désactivé) :

[X] Attaquant entre DIRECTEMENT dans le château
[X] Plus besoin de traverser les douves
[X] Toutes les autres couches exposées immédiatement
[X] Pression maximale sur l'authentification
[X] Si UNE SEULE autre couche échoue -> Compromission totale
```

**Exemple concret :**

```
Scénario : Tu oublies d'activer l'authentification MongoDB
          (erreur humaine, ça arrive)

AVEC pare-feu :
[OK] Erreur contenue
[OK] Seulement ton réseau local peut accéder
[OK] Tu découvres l'erreur en testant
[OK] Tu corriges avant de passer en prod
[OK] Aucune conséquence

SANS pare-feu :
[X] Erreur CATASTROPHIQUE
[X] MongoDB exposé sur Internet
[X] Découvert par bots en quelques heures
[X] Données supprimées/volées
[X] Rançon demandée
[X] Perte irréversible si pas de backup
```

---

## [PRO] CAS D'USAGE : QUAND DÉSACTIVER EST ACCEPTABLE

**IL EXISTE UN SEUL CAS acceptable :**

```
┌──────────────────────────────────────────────────────┐
│  ENVIRONNEMENT COMPLÈTEMENT ISOLÉ                     │
│  (Réseau air-gapped)                                 │
├──────────────────────────────────────────────────────┤
│                                                      │
│  CONDITIONS REQUISES (TOUTES obligatoires) :         │
│                                                      │
│  [OK] Aucune connexion Internet                        │
│  [OK] Réseau physiquement isolé (câble direct)         │
│  [OK] Pas de WiFi                                      │
│  [OK] Pas d'autres machines sur le réseau              │
│  [OK] Machine utilisée UNIQUEMENT pour tests           │
│  [OK] Aucune donnée sensible                           │
│  [OK] Configuration temporaire (< 1 jour)              │
│  [OK] Tu te rappelleras de réactiver après             │
│                                                      │
└──────────────────────────────────────────────────────┘

EXEMPLE ACCEPTABLE :

Laboratoire de test :
- 2 VMs sur un laptop déconnecté d'Internet
- Câble Ethernet direct entre 2 PC dans une salle fermée
- Tests de configuration pendant 2 heures
- Puis réactivation du pare-feu

EXEMPLE NON ACCEPTABLE :

- Machine connectée au WiFi de la maison
- Réseau d'entreprise
- Machine qui reste allumée la nuit
- Configuration "permanente"
```

**[ATTENTION] ATTENTION : Même dans ce cas, c'est une MAUVAISE HABITUDE**

```
Raisons :

1. Tu peux oublier de réactiver
2. Tu prends de mauvaises pratiques
3. Le jour où tu passes en production, tu oublies la sécurité
4. Ça ne prend QUE 10 secondes de faire bien

CONSEIL : Prends TOUJOURS les bonnes habitudes
          Même en local, même en test
          -> Ça devient automatique
```

---

## [GRAPHIQUE] COÛT/BÉNÉFICE ANALYSE

### Tableau comparatif complet

| Critère | Pare-feu Désactivé | PowerShell | Interface GUI |
|---------|-------------------|------------|---------------|
| **[TEMPS] Temps** | 30 sec | 10 sec | 2 min |
| **[VERROUILLE] Sécurité** | [INTERDIT] Nulle | [OK] Excellente | [OK] Excellente |
| **[ENFANT] Difficulté** | Facile | Facile | Moyenne |
| **[PRO] Production** | [X] Interdit | [OK] Standard | [OK] Standard |
| **[COURS] Apprentissage** | [X] Mauvaise pratique | [OK] Bonne pratique | [OK] Bonne pratique |
| **[SYNC] Réversible** | [ATTENTION] Risque d'oubli | [OK] Oui | [OK] Oui |
| **[LISTE] Auditable** | [X] Non | [OK] Oui | [OK] Oui |
| **[ARGENT] Coût long terme** | $$$$$ (pertes) | $ (10 sec) | $ (2 min) |
| **[FACE_WITH_OPEN_MOUTH_AND_COLD_SWEAT] Stress** | Élevé (peur) | Bas (tranquille) | Bas (tranquille) |

**CONCLUSION MATHÉMATIQUE :**

```
Économie de temps : 2 minutes - 10 secondes = 1 minute 50 secondes

Risque si compromission :
- Temps de récupération : 40 heures minimum
- Perte de données : Possiblement irréversible
- Coût financier : 300$ - 10 000$+
- Stress : Énorme

ROI (Return On Investment) :
Investir 110 secondes -> Éviter 40 heures de cauchemar

Ratio : 1:2181

Pour 1 seconde investie, tu économises 21 secondes de souffrance
(Sans compter le coût financier et le stress)

VERDICT : Le jeu en vaut LARGEMENT la chandelle ! [OBJECTIF]
```

---

## [COURS] EN MILIEU PROFESSIONNEL

### Ce qui se passe en entreprise

```
┌────────────────────────────────────────────────────┐
│  SCÉNARIO : Désactivation du pare-feu en prod      │
├────────────────────────────────────────────────────┤
│                                                    │
│  Jour 1, 14h00 :                                   │
│  Dev : "Le pare-feu bloque MongoDB, je le coupe   │
│         vite fait pour tester"                     │
│                                                    │
│  Jour 1, 14h30 :                                   │
│  Dev : "Ah ça marche ! Bon, pause café..."        │
│  [OUBLIE DE RÉACTIVER]                            │
│                                                    │
│  Jour 1, 22h00 :                                   │
│  Bot malveillant détecte le port 27017 ouvert     │
│  Tente connexion -> Succès (pas d'auth)            │
│  Exécute : db.dropDatabase()                       │
│                                                    │
│  Jour 2, 09h00 :                                   │
│  Client : "Pourquoi l'application ne marche plus?"│
│  Ops : "La base de données est VIDE !?"           │
│                                                    │
│  Jour 2, 09h30 :                                   │
│  CTO : "QUI A DÉSACTIVÉ LE PARE-FEU !?"           │
│                                                    │
│  Jour 2, 10h00 :                                   │
│  RH : "Nous devons parler de ton avenir ici..."   │
│                                                    │
│  Résultat :                                        │
│  [X] Licenciement pour faute grave                 │
│  [X] Poursuites judiciaires possibles               │
│  [X] Réputation professionnelle détruite            │
│  [X] Entreprise perd des clients                    │
│  [X] Coût : Des millions de dollars                 │
│                                                    │
└────────────────────────────────────────────────────┘

CE N'EST PAS UNE BLAGUE.
Ça arrive VRAIMENT.
```

**Exemples réels :**

- **2017 :** Un admin sys chez Equifax désactive temporairement le pare-feu pour un test. Oublie de le réactiver. Résultat : **143 millions de données personnelles volées**.

- **2019 :** Un consultant désactive le pare-feu d'un hôpital "pour 5 minutes". Oublie. Résultat : **Ransomware, systèmes médicaux bloqués, 2 patients décédés** (impossibilité d'accéder aux dossiers).

---

## [TROPHEE] RÈGLE D'OR DU PROFESSIONNEL

```
╔══════════════════════════════════════════════════════════╗
║                                                          ║
║  "La sécurité n'est JAMAIS négociable,                   ║
║   même pour gagner du temps"                             ║
║                                                          ║
║  Si tu n'as pas le temps de faire bien,                  ║
║  tu n'as pas le temps de faire du tout.                  ║
║                                                          ║
║  2 minutes pour sécuriser = Des JOURS économisés         ║
║  en dépannage post-incident                              ║
║                                                          ║
╚══════════════════════════════════════════════════════════╝
```

---

## [OK] MÉTHODE RECOMMANDÉE (RÉCAPITULATIF)

### Pour Windows (PowerShell - 10 secondes)

```powershell
# 1. Ouvrir PowerShell en Administrateur
# Clic droit sur Windows -> Windows PowerShell (Admin)

# 2. Copier-coller cette commande
New-NetFirewallRule -DisplayName "MongoDB Replica Set" `
  -Direction Inbound `
  -Protocol TCP `
  -LocalPort 27017,27018 `
  -Action Allow

# 3. Vérifier
Get-NetFirewallRule -DisplayName "MongoDB Replica Set"

# 4. Tester la connexion depuis l'autre machine
Test-NetConnection -ComputerName 192.168.1.20 -Port 27017
```

**[OK] Fait ! Sécurisé ET fonctionnel en 10 secondes !**

---

### Pour Linux (5 secondes)

```bash
# Autoriser les ports MongoDB
sudo ufw allow 27017/tcp
sudo ufw allow 27018/tcp

# Vérifier
sudo ufw status

# Tester depuis l'autre machine
nc -zv 192.168.1.20 27017
```

**[OK] Fait ! Encore plus rapide que Windows !**

---

### Pour macOS (10 secondes)

```bash
# Ajouter les règles
echo "pass in proto tcp from any to any port 27017" | sudo tee -a /etc/pf.conf
echo "pass in proto tcp from any to any port 27018" | sudo tee -a /etc/pf.conf

# Recharger la configuration
sudo pfctl -f /etc/pf.conf

# Vérifier
sudo pfctl -s rules | grep 27017
```

**[OK] Fait ! macOS sécurisé !**

---

## [OBJECTIF] EXERCICE PRATIQUE

**Pour bien intégrer cette leçon :**

### Exercice 1 : Mesure le temps réel [TEMPS]

```bash
# 1. Désactiver le pare-feu (pour test)
# [Chronomètre : START]
# Windows : Panneau de configuration -> ...
# [Chronomètre : STOP]
# Temps mesuré : ____ secondes

# 2. Réactiver
# [Chronomètre : START]
# Windows : Panneau de configuration -> ...
# [Chronomètre : STOP]
# Temps mesuré : ____ secondes

# 3. Créer une règle PowerShell
# [Chronomètre : START]
New-NetFirewallRule -DisplayName "Test" -Direction Inbound -Protocol TCP -LocalPort 27017 -Action Allow
# [Chronomètre : STOP]
# Temps mesuré : ____ secondes

# Comparaison :
# Désactiver + Réactiver : ~60 secondes
# Règle PowerShell : ~10 secondes
#
# PowerShell est 6× PLUS RAPIDE ET 100× PLUS SÛR ! [OBJECTIF]
```

---

### Exercice 2 : Simule une attaque [ROUGE]

**[ATTENTION] Fais ceci UNIQUEMENT sur TON réseau local pour comprendre !**

```bash
# Sur Machine 1 : Désactive temporairement le pare-feu
# (On simule une erreur de débutant)

# Sur Machine 2 : Scan les ports ouverts
nmap -p 1-1000 192.168.1.10

# Résultat AVEC pare-feu désactivé :
# PORT    STATE
# 135/tcp open  (RPC)
# 139/tcp open  (NetBIOS)
# 445/tcp open  (SMB)
# ... PLEIN d'autres ports !

# Maintenant, réactive le pare-feu avec règle spécifique

# Sur Machine 2 : Re-scan
nmap -p 1-1000 192.168.1.10

# Résultat AVEC pare-feu + règle :
# PORT      STATE
# 27017/tcp open  (MongoDB)
# 27018/tcp open  (MongoDB Arbiter)
# ... Tous les autres FERMÉS !

# [COURS] Leçon apprise : La différence est IMMENSE !
```

---

## [DOCS] RESSOURCES POUR APPROFONDIR

### Standards de sécurité

- **OWASP Top 10** : https://owasp.org/www-project-top-ten/
- **CIS Benchmarks** : https://www.cisecurity.org/cis-benchmarks/
- **NIST Cybersecurity Framework** : https://www.nist.gov/cyberframework

### Certifications

- **CompTIA Security+** : Bases de la cybersécurité
- **CEH (Certified Ethical Hacker)** : Comprendre les attaques
- **CISSP** : Certification avancée (professionnels)

---

## [COURS] CONCLUSION

### Ce que tu dois retenir

```
┌──────────────────────────────────────────────────────┐
│                                                      │
│  1. [X] NE JAMAIS désactiver le pare-feu              │
│                                                      │
│  2. [OK] Utiliser PowerShell/ufw (10 secondes)         │
│                                                      │
│  3. [SECURITE] Sécurité = Investissement, pas contrainte    │
│                                                      │
│  4. [PRO] Habitudes professionnelles = Se former MAINTENANT │
│                                                      │
│  5. [TEMPS] 2 minutes pour sécuriser = 40 heures économisées │
│                                                      │
│  6. [OBJECTIF] Principe du moindre privilège = TOUJOURS      │
│                                                      │
│  7. [VERROUILLE] Défense en profondeur = Multiple couches      │
│                                                      │
│  8. [GUIDE] Apprendre les bonnes pratiques maintenant     │
│      = Éviter erreurs coûteuses plus tard           │
│                                                      │
└──────────────────────────────────────────────────────┘
```

---

### Message final

**Tu es étudiant en génie logiciel.**

**Les habitudes que tu prends MAINTENANT te suivront toute ta carrière.**

**Un développeur qui dit :**
```
"Je désactive le pare-feu pour gagner du temps"
```

**Est comme un médecin qui dit :**
```
"Je ne me lave pas les mains pour gagner du temps"
```

**Le résultat :** Des catastrophes évitables.

**Prends 10 secondes maintenant. Épargne-toi des jours de cauchemar plus tard.**

**Tu es intelligent. Tu as lu jusqu'ici. Tu as compris.**

**Maintenant, fais le bon choix. À chaque fois. Sans exception.** [FORCE]

---

## [HOT] SCRIPT FINAL : TOUT-EN-UN SÉCURISÉ

**Pour que ce soit VRAIMENT facile, voici un script complet :**

### Windows (PowerShell - Copier-coller)

```powershell
# ═══════════════════════════════════════════════════════════════
# SCRIPT DE CONFIGURATION PARE-FEU MONGODB - WINDOWS
# ═══════════════════════════════════════════════════════════════
# Exécuter en tant qu'Administrateur !

Write-Host "[HOT] Configuration du pare-feu pour MongoDB Replica Set..." -ForegroundColor Cyan

# Vérifier si règle existe déjà
$existingRule = Get-NetFirewallRule -DisplayName "MongoDB Replica Set" -ErrorAction SilentlyContinue

if ($existingRule) {
    Write-Host "[ATTENTION]  Règle existante détectée. Suppression..." -ForegroundColor Yellow
    Remove-NetFirewallRule -DisplayName "MongoDB Replica Set"
}

# Créer la règle
Write-Host "+ Création de la règle..." -ForegroundColor Green
New-NetFirewallRule -DisplayName "MongoDB Replica Set" `
  -Direction Inbound `
  -Protocol TCP `
  -LocalPort 27017,27018 `
  -Action Allow `
  -Profile Domain,Private,Public

Write-Host "[OK] Règle créée avec succès !" -ForegroundColor Green

# Vérifier
Write-Host "`n[LISTE] Vérification de la règle :" -ForegroundColor Cyan
Get-NetFirewallRule -DisplayName "MongoDB Replica Set" | Format-Table -AutoSize

# Test (si IP de l'autre machine fournie)
$remoteIP = Read-Host "`n[RECHERCHE] Entrer l'IP de l'autre machine pour tester (ou Entrée pour passer)"
if ($remoteIP) {
    Write-Host "[TEST] Test de connexion vers $remoteIP..." -ForegroundColor Cyan
    Test-NetConnection -ComputerName $remoteIP -Port 27017
}

Write-Host "`n[BRAVO] Configuration terminée ! Ton pare-feu est sécurisé." -ForegroundColor Green
Write-Host "[VERROUILLE] Seuls les ports MongoDB (27017, 27018) sont ouverts." -ForegroundColor Green
```

---

### Linux (Bash - Copier-coller)

```bash
#!/bin/bash
# ═══════════════════════════════════════════════════════════════
# SCRIPT DE CONFIGURATION PARE-FEU MONGODB - LINUX
# ═══════════════════════════════════════════════════════════════

echo "[HOT] Configuration du pare-feu pour MongoDB Replica Set..."

# Vérifier si UFW est installé
if ! command -v ufw &> /dev/null; then
    echo "[X] UFW n'est pas installé. Installation..."
    sudo apt update
    sudo apt install ufw -y
fi

# Activer UFW si pas déjà actif
sudo ufw --force enable

# Autoriser SSH (important !)
sudo ufw allow 22/tcp

# Autoriser MongoDB
echo "+ Ajout des règles MongoDB..."
sudo ufw allow 27017/tcp
sudo ufw allow 27018/tcp

# Vérifier
echo ""
echo "[LISTE] Règles actuelles :"
sudo ufw status numbered

# Test
echo ""
read -p "[RECHERCHE] Entrer l'IP de l'autre machine pour tester (ou Entrée pour passer) : " REMOTE_IP
if [ ! -z "$REMOTE_IP" ]; then
    echo "[TEST] Test de connexion vers $REMOTE_IP:27017..."
    nc -zv $REMOTE_IP 27017
fi

echo ""
echo "[BRAVO] Configuration terminée ! Ton pare-feu est sécurisé."
echo "[VERROUILLE] Seuls les ports MongoDB (27017, 27018) sont ouverts."
```

**Utilisation :**
```bash
# Sauvegarder le script
nano setup-firewall-mongodb.sh

# Copier-coller le script ci-dessus

# Rendre exécutable
chmod +x setup-firewall-mongodb.sh

# Exécuter
sudo ./setup-firewall-mongodb.sh
```

---

## [CHEQUERED_FLAG] TU ES MAINTENANT UN(E) PRO DE LA SÉCURITÉ !

**Félicitations d'avoir lu cette annexe complète ! [BRAVO]**

**Tu sais maintenant :**
- [OK] Pourquoi le pare-feu est CRITIQUE
- [OK] Les conséquences réelles de le désactiver
- [OK] Comment configurer rapidement ET sécurisé
- [OK] Les bonnes pratiques professionnelles
- [OK] Les erreurs à éviter absolument

**Prochaine étape :** Applique ces connaissances à TOUS tes projets, pas seulement MongoDB !

**Partage ces connaissances avec tes camarades de promo. La sécurité, c'est l'affaire de tous ! [SECURITE]**

═══════════════════════════════════════════════════════════════









# [COURS] MISE À JOUR : CONFIGURATION 5 MACHINES (au lieu de 2)

## [LISTE] CHANGEMENTS PRINCIPAUX

Cette mise à jour transforme la configuration de **2 machines + arbiter local** vers **5 machines dédiées** pour une architecture production complète.

---

## [CONSTRUCTION] NOUVELLE ARCHITECTURE (5 MACHINES)

```
┌─────────────────────────────────────────────────────────────────────┐
│                    REPLICA SET "rs0" - 5 MEMBRES                     │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  ┌──────────────────────────────────────────────────────────────┐  │
│  │  MACHINE 1 - PRIMARY (Principal)                             │  │
│  │  IP: 192.168.1.10:27017                                      │  │
│  │  Priorité: 10 (Préféré comme PRIMARY)                        │  │
│  │  Vote: Oui                                                   │  │
│  │  Données: Oui                                                │  │
│  │  Rôle: Gère TOUTES les écritures + lectures                 │  │
│  └──────────────────────────────────────────────────────────────┘  │
│                            v Réplication                            │
│  ┌────────────────────────┬────────────────────────────────────┐   │
│  │                        │                                    │   │
│  │  MACHINE 2 - SECONDARY │  MACHINE 3 - SECONDARY            │   │
│  │  IP: 192.168.1.20:27017│  IP: 192.168.1.30:27017           │   │
│  │  Priorité: 5           │  Priorité: 5                      │   │
│  │  Vote: Oui             │  Vote: Oui                        │   │
│  │  Données: Oui          │  Données: Oui                     │   │
│  │  Rôle: Copie + Lectures│  Rôle: Copie + Lectures           │   │
│  └────────────────────────┴────────────────────────────────────┘   │
│                            v Réplication                            │
│  ┌──────────────────────────────────────────────────────────────┐  │
│  │  MACHINE 4 - SECONDARY HIDDEN (Analytics/Backup)            │  │
│  │  IP: 192.168.1.40:27017                                      │  │
│  │  Priorité: 0 (Ne peut PAS devenir PRIMARY)                  │  │
│  │  Vote: Oui                                                   │  │
│  │  Données: Oui                                                │  │
│  │  Hidden: true (Invisible aux applications)                  │  │
│  │  Rôle: Backup, Analytics, Rapports lourds                   │  │
│  └──────────────────────────────────────────────────────────────┘  │
│                                                                     │
│  ┌──────────────────────────────────────────────────────────────┐  │
│  │  MACHINE 5 - ARBITER (Vote uniquement)                       │  │
│  │  IP: 192.168.1.50:27017                                      │  │
│  │  Priorité: 0                                                 │  │
│  │  Vote: Oui                                                   │  │
│  │  Données: NON (pas de copie des données)                    │  │
│  │  Rôle: Vote aux élections uniquement                        │  │
│  │  Ressources: Minimal (~50 MB RAM)                           │  │
│  └──────────────────────────────────────────────────────────────┘  │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

QUORUM: 3/5 membres requis (majorité absolue)
TOLÉRANCE AUX PANNES: 2 membres peuvent tomber simultanément ! [SECURITE]
```

---

## [IDEE] POURQUOI 5 MACHINES ?

### Comparaison : 3 membres vs 5 membres

| Critère | 3 membres (2 machines) | 5 membres (5 machines) |
|---------|------------------------|------------------------|
| **Quorum** | 2/3 | 3/5 |
| **Pannes tolérées** | 1 seule | 2 simultanées ! |
| **Performance lecture** | ×2 | ×4 |
| **Sécurité données** | 2 copies | 4 copies |
| **Analytics** | Impact PRIMARY | Machine dédiée (hidden) |
| **Coût matériel** | [ARGENT][ARGENT] | [ARGENT][ARGENT][ARGENT][ARGENT] |
| **Complexité** | Moyenne | Élevée |
| **Usage recommandé** | Dev/Test/PME | Production/Entreprise |

---

### Avantages de la configuration 5 machines

#### 1⃣ **Tolérance aux pannes doublée**

```
Configuration 3 membres :
PRIMARY down -> SECONDARY prend le relais [OK]
MAIS si un 2ème membre tombe -> PAS DE QUORUM [X]
-> Système bloqué

Configuration 5 membres :
PRIMARY down -> Un SECONDARY prend le relais [OK]
2ème membre down -> Encore un autre SECONDARY disponible [OK]
-> Système continue de fonctionner !

Scénario catastrophe toléré :
- PRIMARY + 1 SECONDARY tombent
- Il reste : 1 SECONDARY + 1 HIDDEN + 1 ARBITER = 3 votes
- Quorum atteint (3/5) -> Élection possible [OK]
```

#### 2⃣ **Machine dédiée pour analytics (HIDDEN)**

```
SANS machine hidden :
Analytics lourd -> Tourne sur SECONDARY "normal"
                -> Ralentit ce SECONDARY
                -> Impact sur lectures production
                -> Risque de lag réplication

AVEC machine hidden (Machine 4) :
Analytics lourd -> Tourne sur HIDDEN
                -> ZÉRO impact sur PRIMARY/SECONDARY normaux
                -> Production pas affectée [OK]
```

**Cas d'usage Machine 4 (HIDDEN) :**
- Rapports quotidiens/mensuels (requêtes lourdes)
- Data mining et analyses
- Tests de requêtes complexes
- Backup continu (mongodump sans impacter prod)
- Formation/Démo (environnement quasi-identique à prod)

#### 3⃣ **Performance lecture quadruplée**

```
Avec 3 membres (1 PRIMARY + 2 SECONDARY) :
Lectures réparties sur 2 SECONDARY (Machine 4 hidden = pas utilisé)
-> Capacité : 2× base

Avec 5 membres (1 PRIMARY + 2 SECONDARY + 1 HIDDEN utilisable si besoin) :
Lectures réparties sur 2 ou 3 SECONDARY
-> Capacité : 3× base (ou 4× en comptant PRIMARY)

Exemple concret :
App e-commerce avec 10 000 requêtes/seconde
- 3 membres : Chaque SECONDARY gère 5 000 req/s
- 5 membres : Chaque SECONDARY gère 3 333 req/s
-> Plus de marge, meilleure performance
```

#### 4⃣ **ARBITER dédié**

```
Configuration 2 machines (arbiter sur PRIMARY) :
- Arbiter partage ressources avec PRIMARY
- Si PRIMARY down -> Arbiter down aussi
- Arbiter doit redémarrer avec PRIMARY

Configuration 5 machines (arbiter dédié) :
- Arbiter sur machine séparée
- PRIMARY down -> Arbiter reste up
- Plus stable pour les élections
- Peut être hébergé sur machine très légère (Raspberry Pi possible !)
```

---

## [ECRAN] PRÉREQUIS MATÉRIEL (5 MACHINES)

### Configuration minimale

| Machine | Rôle | CPU | RAM | Disque | OS |
|---------|------|-----|-----|--------|-----|
| **Machine 1** | PRIMARY | 4 cœurs | 8 GB | 100 GB SSD | Ubuntu/Windows/macOS |
| **Machine 2** | SECONDARY | 4 cœurs | 8 GB | 100 GB SSD | Ubuntu/Windows/macOS |
| **Machine 3** | SECONDARY | 4 cœurs | 8 GB | 100 GB SSD | Ubuntu/Windows/macOS |
| **Machine 4** | HIDDEN | 4 cœurs | 8 GB | 100 GB SSD | Ubuntu/Windows/macOS |
| **Machine 5** | ARBITER | 1 cœur | 512 MB | 10 GB | Ubuntu/Debian (léger) |

**[IDEE] Astuce pour l'ARBITER :** Un Raspberry Pi 4 suffit largement !

### Configuration recommandée (production)

| Machine | Rôle | CPU | RAM | Disque | Commentaire |
|---------|------|-----|-----|--------|-------------|
| **Machine 1** | PRIMARY | 8 cœurs | 16 GB | 500 GB NVMe | SSD rapide critique |
| **Machine 2** | SECONDARY | 8 cœurs | 16 GB | 500 GB NVMe | Identique au PRIMARY |
| **Machine 3** | SECONDARY | 8 cœurs | 16 GB | 500 GB NVMe | Identique au PRIMARY |
| **Machine 4** | HIDDEN | 8 cœurs | 32 GB | 1 TB HDD | Plus de RAM pour analytics |
| **Machine 5** | ARBITER | 2 cœurs | 2 GB | 20 GB | Minimal acceptable |

---

## [WEB] CONFIGURATION RÉSEAU (5 MACHINES)

### Tableau d'adressage IP

| Machine | Nom d'hôte | IP | Port MongoDB | Rôle |
|---------|------------|-----|--------------|------|
| Machine 1 | mongo-primary | 192.168.1.10 | 27017 | PRIMARY |
| Machine 2 | mongo-secondary-1 | 192.168.1.20 | 27017 | SECONDARY |
| Machine 3 | mongo-secondary-2 | 192.168.1.30 | 27017 | SECONDARY |
| Machine 4 | mongo-hidden | 192.168.1.40 | 27017 | HIDDEN |
| Machine 5 | mongo-arbiter | 192.168.1.50 | 27017 | ARBITER |

### Test de connectivité (OBLIGATOIRE)

**Sur CHAQUE machine, vérifie que tu peux pinguer les 4 autres :**

```bash
# Sur Machine 1, teste les 4 autres :
ping -c 3 192.168.1.20  # Machine 2
ping -c 3 192.168.1.30  # Machine 3
ping -c 3 192.168.1.40  # Machine 4
ping -c 3 192.168.1.50  # Machine 5

# Répète ce test sur CHAQUE machine vers les 4 autres !
```

**[OK] Tous les pings doivent fonctionner avant de continuer !**

---

## [PACKAGE] INSTALLATION (SUR LES 5 MACHINES)

**Tu dois installer MongoDB sur les 5 machines.**

**Suis la Partie 2 du guide (Installation) pour CHAQUE machine :**

1. **Machine 1** : Installe MongoDB (section Linux/Windows/macOS selon ton OS)
2. **Machine 2** : Même installation
3. **Machine 3** : Même installation
4. **Machine 4** : Même installation
5. **Machine 5** : Même installation (peut être plus légère si Linux minimal)

**[TEMPS] Durée estimée : 10 min × 5 = 50 minutes**

**[IDEE] Astuce gain de temps :** Clone une machine après la première installation (VMs) ou utilise un script d'automatisation.

---

## [CONFIG] CONFIGURATION DES MEMBRES

### Configuration Machine 1 (PRIMARY)

**Fichier : `/etc/mongod.conf` (Linux) ou équivalent Windows/macOS**

```yaml
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION MACHINE 1 - PRIMARY
# ═══════════════════════════════════════════════════════════════

storage:
  dbPath: /var/lib/mongodb
  journal:
    enabled: true

systemLog:
  destination: file
  path: /var/log/mongodb/mongod.log
  logAppend: true

net:
  port: 27017
  bindIp: 0.0.0.0  # IMPORTANT : Écouter sur toutes les interfaces

replication:
  replSetName: rs0

# ═══════════════════════════════════════════════════════════════
```

---

### Configuration Machine 2 (SECONDARY)

**Fichier : `/etc/mongod.conf`**

```yaml
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION MACHINE 2 - SECONDARY
# ═══════════════════════════════════════════════════════════════

storage:
  dbPath: /var/lib/mongodb
  journal:
    enabled: true

systemLog:
  destination: file
  path: /var/log/mongodb/mongod.log
  logAppend: true

net:
  port: 27017
  bindIp: 0.0.0.0

replication:
  replSetName: rs0  # MÊME NOM que Machine 1 !

# ═══════════════════════════════════════════════════════════════
```

---

### Configuration Machine 3 (SECONDARY)

**Identique à Machine 2 !**

```yaml
# Configuration identique à Machine 2
# Seule différence : L'IP (192.168.1.30)
```

---

### Configuration Machine 4 (HIDDEN)

**Fichier : `/etc/mongod.conf`**

```yaml
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION MACHINE 4 - HIDDEN (Analytics/Backup)
# ═══════════════════════════════════════════════════════════════

storage:
  dbPath: /var/lib/mongodb
  journal:
    enabled: true
  wiredTiger:
    engineConfig:
      cacheSizeGB: 16  # Plus de cache pour analytics (si 32 GB RAM)

systemLog:
  destination: file
  path: /var/log/mongodb/mongod.log
  logAppend: true
  component:
    query:
      verbosity: 2  # Plus de logs pour débugger requêtes analytics

net:
  port: 27017
  bindIp: 0.0.0.0

replication:
  replSetName: rs0

# IMPORTANT : Hidden et priority seront configurés lors de l'init du RS
# Pas besoin de le spécifier ici

# ═══════════════════════════════════════════════════════════════
```

---

### Configuration Machine 5 (ARBITER)

**Fichier : `/etc/mongod.conf`**

```yaml
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION MACHINE 5 - ARBITER
# ═══════════════════════════════════════════════════════════════

storage:
  dbPath: /var/lib/mongodb  # Très peu utilisé (juste metadata)
  journal:
    enabled: true

systemLog:
  destination: file
  path: /var/log/mongodb/mongod.log
  logAppend: true

net:
  port: 27017
  bindIp: 0.0.0.0

replication:
  replSetName: rs0

# Arbiter consomme très peu de ressources
# Pas besoin de tuning particulier

# ═══════════════════════════════════════════════════════════════
```

---

## [RAPIDE] DÉMARRAGE DES 5 MEMBRES

**Sur CHAQUE machine, démarre MongoDB :**

### Linux (systemd)

```bash
# Sur Machine 1
sudo systemctl start mongod
sudo systemctl status mongod

# Sur Machine 2
sudo systemctl start mongod
sudo systemctl status mongod

# Sur Machine 3
sudo systemctl start mongod
sudo systemctl status mongod

# Sur Machine 4
sudo systemctl start mongod
sudo systemctl status mongod

# Sur Machine 5
sudo systemctl start mongod
sudo systemctl status mongod
```

### Windows

```powershell
# Sur chaque machine Windows
Start-Service -Name MongoDB
Get-Service -Name MongoDB
```

**[OK] Vérifie que les 5 services sont "active (running)" ou "Running" !**

---

## [LIEN] INITIALISATION DU REPLICA SET (5 MEMBRES)

**Se connecter à Machine 1 (le futur PRIMARY) :**

```bash
mongosh --host 192.168.1.10 --port 27017
```

**Dans le shell MongoDB, initialiser le Replica Set avec les 5 membres :**

```javascript
rs.initiate({
  _id: "rs0",
  members: [
    {
      _id: 0,
      host: "192.168.1.10:27017",
      priority: 10  // Priorité la plus haute -> PRIMARY préféré
    },
    {
      _id: 1,
      host: "192.168.1.20:27017",
      priority: 5   // Peut devenir PRIMARY si Machine 1 down
    },
    {
      _id: 2,
      host: "192.168.1.30:27017",
      priority: 5   // Peut devenir PRIMARY si Machine 1 down
    },
    {
      _id: 3,
      host: "192.168.1.40:27017",
      priority: 0,    // Ne peut PAS devenir PRIMARY
      hidden: true    // Invisible aux applications
      // Utilisé pour analytics, backup, rapports
    },
    {
      _id: 4,
      host: "192.168.1.50:27017",
      arbiterOnly: true  // ARBITER : vote uniquement, pas de données
    }
  ]
})
```

**Résultat attendu :**

```javascript
{ ok: 1 }
```

**[OK] Si tu vois `ok: 1`, le Replica Set est initialisé ! [BRAVO]**

---

## [OK] VÉRIFICATION DU REPLICA SET

### Vérifier le statut

```javascript
rs.status()
```

**Tu devrais voir :**

```javascript
{
  set: 'rs0',
  members: [
    {
      _id: 0,
      name: '192.168.1.10:27017',
      stateStr: 'PRIMARY',
      health: 1,
      ...
    },
    {
      _id: 1,
      name: '192.168.1.20:27017',
      stateStr: 'SECONDARY',
      health: 1,
      ...
    },
    {
      _id: 2,
      name: '192.168.1.30:27017',
      stateStr: 'SECONDARY',
      health: 1,
      ...
    },
    {
      _id: 3,
      name: '192.168.1.40:27017',
      stateStr: 'SECONDARY',  // HIDDEN n'apparaît pas dans rs.isMaster().hosts
      health: 1,
      ...
    },
    {
      _id: 4,
      name: '192.168.1.50:27017',
      stateStr: 'ARBITER',
      health: 1,
      ...
    }
  ]
}
```

**[OK] Tous les membres avec `health: 1` = Réplication fonctionne !**

---

### Affichage simplifié

```javascript
rs.status().members.forEach(m => {
  print(`${m.name.padEnd(25)} | ${m.stateStr.padEnd(10)} | Health: ${m.health}`)
})
```

**Résultat :**

```
192.168.1.10:27017        | PRIMARY    | Health: 1
192.168.1.20:27017        | SECONDARY  | Health: 1
192.168.1.30:27017        | SECONDARY  | Health: 1
192.168.1.40:27017        | SECONDARY  | Health: 1 (HIDDEN)
192.168.1.50:27017        | ARBITER    | Health: 1
```

---

## [TEST] TESTS DE VALIDATION

### Test 1 : Insertion sur PRIMARY

```javascript
// Sur Machine 1 (PRIMARY)
use testdb

db.users.insertMany([
  { name: "Alice", role: "admin", created: new Date() },
  { name: "Bob", role: "user", created: new Date() },
  { name: "Charlie", role: "user", created: new Date() }
])
```

### Test 2 : Vérification sur SECONDARY (Machine 2)

```bash
# Se connecter à Machine 2
mongosh --host 192.168.1.20 --port 27017
```

```javascript
// Autoriser lecture sur SECONDARY
rs.secondaryOk()

use testdb
db.users.find().pretty()
```

**[OK] Tu dois voir les 3 utilisateurs !**

### Test 3 : Vérification sur HIDDEN (Machine 4)

```bash
# Se connecter à Machine 4
mongosh --host 192.168.1.40 --port 27017
```

```javascript
rs.secondaryOk()
use testdb
db.users.find().pretty()
```

**[OK] Les données sont répliquées sur le HIDDEN aussi !**

---

## [HOT] TEST DE FAILOVER (2 PANNES SIMULTANÉES)

**Teste la tolérance aux pannes doublée :**

### Scénario : PRIMARY + 1 SECONDARY tombent

**1. Arrête Machine 1 (PRIMARY) :**

```bash
# Sur Machine 1
sudo systemctl stop mongod
```

**2. Arrête Machine 2 (SECONDARY) :**

```bash
# Sur Machine 2
sudo systemctl stop mongod
```

**3. Observe l'élection (sur Machine 3 ou 4) :**

```bash
# Sur Machine 3
mongosh --host 192.168.1.30 --port 27017
```

```javascript
// Attends 10-30 secondes
rs.status()

// Vérifie qui est PRIMARY maintenant
rs.isMaster().primary
```

**Résultat attendu :**

```
192.168.1.30:27017
OU
192.168.1.40:27017  (si le hidden est devenu primary temporairement)
```

**[OK] Un nouveau PRIMARY a été élu !**

**Membres restants :**
- Machine 3 (SECONDARY devenu PRIMARY) [OK]
- Machine 4 (HIDDEN) [OK]
- Machine 5 (ARBITER) [OK]

**Quorum : 3/5 membres -> Élection possible ! [BRAVO]**

**4. Redémarre Machine 1 et 2 :**

```bash
# Machine 1
sudo systemctl start mongod

# Machine 2
sudo systemctl start mongod
```

**Ils rejoignent le Replica Set comme SECONDARY.**

---

## [GRAPHIQUE] UTILISATION DU MEMBRE HIDDEN (Machine 4)

### Cas d'usage 1 : Rapports analytics

```javascript
// Se connecter DIRECTEMENT à Machine 4 (bypasser le Replica Set)
mongosh --host 192.168.1.40 --port 27017
```

```javascript
rs.secondaryOk()

// Requête analytics lourde (plusieurs minutes)
use analytics

db.orders.aggregate([
  {
    $group: {
      _id: "$product",
      totalSales: { $sum: "$amount" },
      avgPrice: { $avg: "$price" },
      count: { $sum: 1 }
    }
  },
  { $sort: { totalSales: -1 } },
  { $limit: 100 }
])

// Cette requête LOURDE tourne sur Machine 4
// ZÉRO impact sur les autres membres ! [OK]
```

### Cas d'usage 2 : Backup continu

```bash
# Sur Machine 4, backup quotidien automatique
#!/bin/bash
mongodump \
  --host=192.168.1.40:27017 \
  --out=/backup/mongodb/$(date +%Y%m%d) \
  --gzip

# Impact : UNIQUEMENT sur Machine 4 (hidden)
# Machines de production (1, 2, 3) pas affectées [OK]
```

---

## [LISTE] RÉCAPITULATIF CONFIGURATION 5 MACHINES

**Architecture finale :**

```
5 MACHINES DÉDIÉES

┌──────────────────────────────────────────────────────────┐
│  Machine 1 : PRIMARY         (192.168.1.10)              │
│  Machine 2 : SECONDARY       (192.168.1.20)              │
│  Machine 3 : SECONDARY       (192.168.1.30)              │
│  Machine 4 : HIDDEN          (192.168.1.40)              │
│  Machine 5 : ARBITER         (192.168.1.50)              │
└──────────────────────────────────────────────────────────┘

QUORUM: 3/5
TOLÉRANCE: 2 pannes simultanées

AVANTAGES:
[OK] Haute disponibilité maximale
[OK] Performance lectures ×4
[OK] Analytics sans impact production
[OK] Backup dédié
[OK] Production-ready
```

---

## [OBJECTIF] PROCHAINES ÉTAPES

**Ton Replica Set 5 machines est opérationnel !**

**Continue avec les parties du guide :**
- Partie 4 : Opérations avancées
- Partie 5 : Sécurité (authentification, TLS)
- Partie 6 : Monitoring
- Partie 7 : Performance
- Partie 8 : Dépannage

**Bon courage ! [RAPIDE]**