Skip to content

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


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.

Environnement : un environnement conda dédié (devops-toolbox), avec pyyaml, requests, pytest, boto3 et moto installés.

toolkit.py
import json
import logging
import os
import subprocess
import sys
from 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=staging
2026-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ès
2026-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 introuvable
2026-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).

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 < seuil
test_toolkit.py (extrait)
from 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 < 80

Le Module 2 va plus loin : tester une automatisation qui parle à AWS, sans jamais toucher un vrai compte AWS, grâce à la bibliothèque moto.

Module 2 : Tests et simulation d’un service cloud avec moto