Mini Projet : Collecteur de Métriques WiFi

Objectifs

À la fin de cette séance, vous serez capables de :

  • Implémenter les bases du scraper SNMP
  • Utiliser les environnements virtuels et gérer les dépendances
  • Configurer le scraper de manière flexible (pas de hardcoding)
  • Mettre en place le logging pour tracer l’exécution
  • Utiliser le debugger pour tester votre code

Introduction

À partir de cette séance, vous démarrez un mini projet : un scraper SNMP pour des points d’accès Schneider Electric (les APs utilisés dans nos déploiements résidentiels).

Ce projet représente un vrai défi que vous rencontrerez en tant que technicien réseau :

  • Les APs Schneider ont des métriques SNMP non-standard
  • Vous disposez d’une MIB file qui documente les OID disponibles
  • Vous apprendrez à lire une MIB et déboguer du matériel réseau réel

Ce projet regroupe tout ce que vous avez appris dans les 3 séances précédentes :

  • Environnements virtuels (séance 2)
  • Logging (séance 2)
  • Debugging (séance 3)
  • Fonctions et bonnes pratiques (séance 1)

Sur les 3 prochaines séances, vous allez construire progressivement :

  1. Séance 4 : Le scraper de base et découverte des OID (ce que vous faites aujourd’hui)
  2. Séance 5 : Finalisation et robustesse du scraper
  3. Séance 6 : Dashboard pour présenter les données collectées

Fichiers fournis :

  • Mib OIDs: MIB file documentant les OID des APs Schneider
  • Structure de base du projet: Structure de base du projet avec les fichiers nécessaires (config.py, scraper.py vide, etc.)

1. Contexte et cas d’usage

1.1 Le problème réel

Schneider déploie des APs dans des résidences. L’administrateur réseau a besoin de :

  • Savoir combien de clients sont connectés en temps réel
  • Avoir un historique pour identifier les pics d’utilisation
  • Surveiller la santé des APs (CPU, mémoire, signal, etc.)

Situation : Les APs Schneider Electric n’utilisent pas les OID SNMP standard. Vous disposez d’une MIB file (SE_mibs.csv) qui documente tous les OID disponibles.

Solution : Un scraper customisé qui interroge les APs Schneider via SNMP en utilisant les OID spécifiques définis dans la MIB.

1.2 SNMP et les OID non-standard

SNMP (Simple Network Management Protocol) est un protocole d’interrogation d’équipements réseau. Les données sont identifiées par des OID (Object Identifier).

OID Standard (Cisco, par exemple) :

OID: 1.3.6.1.4.1.9.9.46.1.6.1.1.6
Signification: Nombre de clients WiFi

2. Architecture du scraper

2.1 Structure générale

Organisez votre projet de la manière suivante :

scraper_wifi/
├── venv/                    # Environnement virtuel
├── scraper.py              # Code principal du scraper
├── config.py               # Configuration (hosts, OID, etc.)
├── data/
│   └── metrics.csv         # Données collectées
├── logs/
│   └── scraper.log         # Logs d'exécution
├── requirements.txt        # Dépendances
└── README.md              # Documentation

Principes :

  • Les credentials et config ne sont JAMAIS dans le code principal
  • Les données sont séparées du code
  • Les logs permettent de déboguer

2.2 Flux général du scraper

1. Charger configuration (hosts, credentials, OID)
   ↓
2. Pour chaque Access Point :
   - Se connecter via SNMP
   - Récupérer le nombre de clients
   - Sauvegarder dans le CSV
   ↓
3. Logger chaque opération
   ↓
4. Attendre et recommencer

3. Gestion des credentials et configuration

3.1 Pourquoi externaliser la configuration ?

# ❌ MAUVAIS : Secrets en dur dans le code
def scraper_principal():
    host = "192.168.1.1"
    username = "snmp_user"
    auth_password = "auth_pass"
    privacy_password = "priv_pass"
    # ...

Risques :

  • Les credentials se retrouvent dans Git
  • Les mots de passe sont visibles dans le code source
  • Impossible de changer de serveur sans modifier le code
  • Sécurité compromise

3.2 Solution : Fichier config.py

Créez un fichier config.py :

# config.py - Configuration du scraper

# Serveurs SNMP à interroger (SNMPv3)
SNMP_HOSTS = [
    {
        "name": "AP1",
        "host": "192.168.1.1",
        "version": 3,
        "username": "snmp_user",
        "auth_protocol": "SHA",
        "auth_password": "auth_password",
        "privacy_protocol": "AES",
        "privacy_password": "privacy_password"
    },
]

# OID à interroger (nombre de clients WiFi)
OID_CLIENTS = "1.3.6.1.4.1.102.2"

# Fichiers de sortie
CSV_FILE = "data/metrics.csv"
LOG_FILE = "logs/scraper.log"

# Paramètres SNMP
SNMP_TIMEOUT = 5  # secondes
SNMP_RETRIES = 3

# Fréquence de scraping
SCRAPE_INTERVAL = 60  # secondes

Ainsi, pour changer de serveur, vous modifiez juste config.py, pas le code du scraper !

3.3 Dépendances requises

Créez un requirements.txt :

pysnmp

Installez avec :

pip install -r requirements.txt

Note : SNMPv3 nécessite les modules pysnmp et pyasn1 pour l’authentification SHA et le chiffrement AES.


3bis. Découverte des OID Schneider

3bis.1 Comment découvrir les OID disponibles ?

Sur un équipement non-standard (comme les APs Schneider), vous disposez d’une MIB file documentant tous les OID. Voici comment l’utiliser efficacement.

Snmpwalk

# Inspecter une branche spécifique avec SNMPv3
snmpwalk -v 3 -u username -a SHA -A password -x AES -X password 192.168.1.1 1.3.6.1.4.1

# Cela affiche tous les OID commençant par 1.3.6.1.4.1

3bis.2 Tester rapidement un OID

Une fois que vous avez trouvé un OID candidat, testez-le :

# Tester rapidement si c'est le bon OID avec SNMPv3
snmpget -v 3 -u username -a SHA -A password -x AES -X password 192.168.1.1 1.3.6.1.4.1.XXXX.X.X

# Si c'est le bon OID, vous verrez :
# SNMPv2-SMI::enterprises.XXXX.X.X.0 = INTEGER: 42

3bis.3 Enregistrer les OID trouvés

Une fois les OID découverts, les ajouter à config.py :

# Schneider AP-specific OID (from schneider_mib.csv)
OID_CLIENTS = "1.3.6.1.4.1.XXXX.1.1.1"
OID_SIGNAL = "1.3.6.1.4.1.XXXX.1.1.2"
OID_NAME = "1.3.6.1.4.1.XXXX.1.1.3"

Cela permet à votre scraper de rester flexible et facilement adaptable à d’autres APs.


4. Implémentation du scraper de base

4.1 Code de base (boilerplate)

Voici la structure de base de votre scraper.

# scraper.py
import logging
import csv
import os
from datetime import datetime

from pysnmp.hlapi import *
from config import *


# Configuration du logging
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler(LOG_FILE),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)


def recuperer_clients_wifi(host, username, auth_password, privacy_password, oid):
    """Récupère le nombre de clients WiFi via SNMPv3"""
    logger.debug(f"Récupération de {oid} sur {host}")
    
    try:
        # À implémenter: Utiliser nextCmd() avec UsmUserData pour SNMPv3
        # À implémenter: Compter les entrées retournées
        pass
    except Exception as e:
        logger.error(f"Erreur SNMP sur {host}: {e}")
        return -1


def sauvegarder_csv(timestamp, host, nombre_clients, status):
    """Sauvegarde une mesure dans le CSV"""
    logger.debug(f"Sauvegarde des données pour {host}")
    
    try:
        os.makedirs(os.path.dirname(CSV_FILE), exist_ok=True)
        
        # À implémenter: Ajouter la ligne au CSV
        
        logger.info(f"Données sauvegardées pour {host}")
    except IOError as e:
        logger.error(f"Impossible d'écrire dans {CSV_FILE}: {e}")


def main():
    """Point d'entrée du scraper"""
    logger.info("Démarrage du scraper WiFi")
    
    for ap in SNMP_HOSTS:
        try:
            logger.info(f"Interrogation de {ap['name']}")
            
            # À implémenter:
            # - Récupérer les données avec recuperer_clients_wifi()
            # - Sauvegarder avec sauvegarder_csv()
            
        except Exception as e:
            logger.error(f"Erreur sur {ap['name']}: {e}")


if __name__ == "__main__":
    main()

À compléter :

  • recuperer_clients_wifi() : Implémenter la logique SNMPv3
  • sauvegarder_csv() : Écrire au CSV avec les colonnes timestamp, host, nombre_clients, status
  • main() : Boucler sur les APs, récupérer les données, les sauvegarder

4.2 Concepts clés

SNMPv3 avec pysnmp :

Pour compter les clients, vous devez “marcher” (walk) sur la table OID avec nextCmd():

from pysnmp.hlapi import *

UsmUserData(username, auth_password, privacy_password,
            authProtocol=usmHMACSHAAuthProtocol,
            privProtocol=usmAesCfb128Protocol)

Chaque entrée retournée par nextCmd() = 1 client WiFi connecté.

CSV Header :

timestamp,host,nombre_clients,status

5. Format attendu du CSV

Votre CSV doit avoir cette structure :

timestamp,host,nombre_clients,status
2026-03-12 14:30:00,AP1,42,success
2026-03-12 14:31:00,AP1,43,success
2026-03-12 14:32:00,AP1,43,success
2026-03-12 14:33:00,AP2,15,success
2026-03-12 14:33:00,AP2,-1,error

Colonnes :

  • timestamp : ISO 8601 (YYYY-MM-DD HH:MM:SS)
  • host : Nom de l’AP (ex: “AP1”)
  • nombre_clients : Nombre détecté (-1 si erreur)
  • status : “success” ou “error”

6. Debugging du scraper

6.1 Scénarios de test

Testez votre scraper dans ces situations :

  1. Cas normal : Tous les APs répondent
    • La connexion se fait
    • Les données sont récupérées
    • Le CSV est rempli correctement
  2. Host inaccessible : Un AP ne répond pas
    • La fonction gère le timeout
    • Une erreur est loggée
    • Le scraper continue sur l’autre AP
  3. Authentification échouée (SNMPv3) : Mauvais identifiants SNMP (username/auth/priv)
    • Une SNMPError devrait être levée
    • Loggée correctement
    • Le scraper continue
  4. OID invalide : L’OID demandé n’existe pas
    • SNMP retourne “NoSuchObject”
    • C’est géré comme une erreur
    • Loggé
Exercice 1 : Mise en place de l'environnement et découverte des OID

Partie 1 : Infrastructure

  1. Téléchargez et extrayez mini-projet.tar.gz (contient scraper.py, config.py skeleton, etc.)
  2. Activez l’environnement virtuel : source venv/bin/activate
  3. Installez les dépendances : pip install -r requirements.txt

Partie 2 : Découverte des OID

  1. Testez la connexion SNMPv3 à l’AP (IP fournie)
  2. Utilisez snmpwalk avec vos credentials pour explorer :
    snmpwalk -v 3 -u <username> -a SHA -A <auth_pass> -x AES -X <priv_pass> <AP_IP> 1.3.6.1.4.1.102
    
  3. Identifiez l’OID pour les clients (1.3.6.1.4.1.102.2)
  4. Documentez votre découverte dans config.py

Exercice 2 : Implémentation des fonctions

Complétez les TODO dans scraper.py :

  1. recuperer_clients_wifi() :
    • Utiliser nextCmd() avec UsmUserData() pour SNMPv3
    • Boucler sur les résultats et compter les entrées
    • Retourner le count
  2. sauvegarder_csv() :
    • Vérifier si le fichier existe
    • Si non, créer l’en-tête : timestamp,host,nombre_clients,status
    • Ajouter la ligne de données
  3. main() :
    • Pour chaque AP dans SNMP_HOSTS
    • Appeler recuperer_clients_wifi() avec ses paramètres
    • Appeler sauvegarder_csv() avec le résultat
    • Logger les étapes

Test :

python scraper.py
# Vérifiez que data/metrics.csv est créé et rempli

7. Scraper amélioré : boucle infinie (Autonomie)

7.1 Lancer le scraper en continu

import time

def main():
    logger.info("Démarrage du scraper WiFi")
    
    while True:
        try:
            for ap in SNMP_HOSTS:
                # Récupérer Les données
                logger.info(f"Interrogation de {ap['name']}")
                
            logger.debug(f"Prochain scraping dans {SCRAPE_INTERVAL} secondes")
            time.sleep(SCRAPE_INTERVAL)
            
        except KeyboardInterrupt:
            logger.info("Arrêt du scraper (Ctrl+C)")
            break
        except Exception as e:
            logger.error(f"Erreur inattendue: {e}")
            time.sleep(SCRAPE_INTERVAL)

This site uses Just the Docs, a documentation theme for Jekyll.