Module 1 — Boîte à outils Python pour l'automatisation DevOps
Bonne lecture et bon apprentissage ! Junior TSAFACK – 12/09/2026 Temps de lecture estimé : 9 minutes
Pourquoi Python en plus de Bash
Section titled “Pourquoi Python en plus de Bash”Le Module 2 du cours Linux & Shell a montré des scripts Bash réels pour l’automatisation système. Bash reste imbattable pour enchaîner des commandes existantes, mais il devient vite pénible dès qu’il faut manipuler des structures de données (JSON, YAML), gérer des erreurs finement, ou appeler une API. C’est exactement le terrain de Python — au point que la quasi-totalité des outils DevOps modernes (Ansible, l’AWS CLI, la majorité des SDK cloud) sont eux-mêmes écrits en Python.
Le script, exécuté réellement
Section titled “Le script, exécuté réellement”Environnement : un environnement conda dédié (devops-toolbox), avec pyyaml, requests, pytest, boto3 et moto installés.
import jsonimport loggingimport osimport subprocessimport sysfrom pathlib import Path
import yaml
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")log = logging.getLogger("toolkit")
def demo_fichiers(workdir: Path) -> None: config_dir = workdir / "config" config_dir.mkdir(parents=True, exist_ok=True) (config_dir / "app.conf").write_text("environment=staging\nreplicas=2\n") for f in config_dir.iterdir(): log.info("Trouvé : %s (%d octets)", f.name, f.stat().st_size)
def demo_variables_environnement() -> None: os.environ["APP_ENV"] = "staging" log.info("APP_ENV=%s", os.environ.get("APP_ENV", "production"))
def demo_subprocess() -> None: result = subprocess.run( [sys.executable, "-c", "print('sous-processus exécuté avec succès')"], capture_output=True, text=True, check=True, ) log.info("Sortie du sous-processus : %s", result.stdout.strip())
def demo_json_yaml(workdir: Path) -> dict: data = {"service": "api-gateway", "replicas": 3, "ports": [8080, 8443]} (workdir / "service.json").write_text(json.dumps(data, indent=2)) (workdir / "service.yaml").write_text(yaml.safe_dump(data)) return yaml.safe_load((workdir / "service.yaml").read_text())
def demo_requetes_api() -> None: import requests resp = requests.get("https://httpbin.org/get", params={"outil": "devops"}, timeout=10) resp.raise_for_status() log.info("Statut HTTP : %s", resp.status_code)
def demo_gestion_erreurs() -> None: try: subprocess.run(["une-commande-qui-nexiste-pas"], check=True) except FileNotFoundError as exc: log.warning("Erreur interceptée proprement : %s", exc)Sortie réelle de l’exécution (python toolkit.py) :
2026-09-12 22:28:29 [INFO] --- Manipulation de fichiers ---2026-09-12 22:28:29 [INFO] Trouvé : app.conf (33 octets)2026-09-12 22:28:29 [INFO] --- Variables d'environnement ---2026-09-12 22:28:29 [INFO] APP_ENV=staging2026-09-12 22:28:29 [INFO] --- Exécution de sous-processus ---2026-09-12 22:28:29 [INFO] Sortie du sous-processus : sous-processus exécuté avec succès2026-09-12 22:28:29 [INFO] --- JSON et YAML ---2026-09-12 22:28:29 [INFO] Relu depuis YAML : {'ports': [8080, 8443], 'replicas': 3, 'service': 'api-gateway'}2026-09-12 22:28:29 [INFO] --- Requêtes HTTP ---2026-09-12 22:28:31 [WARNING] Requête API ignorée (pas de réseau sortant ?) : HTTPSConnectionPool(host='httpbin.org', port=443): Max retries exceeded (Caused by SSLError(CERTIFICATE_VERIFY_FAILED))2026-09-12 22:28:31 [INFO] --- Gestion d'erreurs ---2026-09-12 22:28:31 [WARNING] Erreur interceptée proprement : [WinError 2] Le fichier spécifié est introuvable2026-09-12 22:28:31 [INFO] Toutes les démonstrations ont été exécutées.Ce qui mérite d’être souligné, honnêtement : l’appel réseau vers httpbin.org a réellement échoué dans cet environnement d’exécution (erreur de vérification de certificat TLS, probablement liée à un proxy réseau local). Plutôt que de masquer cet échec ou de le retirer du cours, il est gardé tel quel — parce qu’il illustre exactement le sujet de la section suivante : le code est écrit pour que ce genre d’échec n’interrompe pas le reste du script. Le try/except autour de demo_requetes_api() a fait son travail : un avertissement clair a été loggé, et l’exécution a continué normalement. C’est la différence entre un script fragile (qui plante) et un script résilient (qui dégrade proprement).
Tester ce code : pytest
Section titled “Tester ce code : pytest”Un script d’automatisation sans test est un script qu’on n’ose pas modifier. Voici la fonction la plus simple du toolkit, isolée pour être testée facilement :
def verifier_seuil_disque(pourcentage_utilise: int, seuil: int = 80) -> bool: return pourcentage_utilise < seuilfrom toolkit import verifier_seuil_disque
def test_seuil_disque_ok(): assert verifier_seuil_disque(45) is True
def test_seuil_disque_depasse(): assert verifier_seuil_disque(92) is False
def test_seuil_disque_limite(): assert verifier_seuil_disque(80) is False # 80 n'est pas < 80Le Module 2 va plus loin : tester une automatisation qui parle à AWS, sans jamais toucher un vrai compte AWS, grâce à la bibliothèque moto.