Idempotence, Error Handling, Shellcheck
Utilisez les flèches, cliquez ou glissez pour naviguer
1. Idempotence
Le script doit pouvoir tourner N fois sans problème
2. Gestion d'erreurs robuste
set -euo pipefail et trap
3. Scripts modulaires
Fonctions réutilisables
4. shellcheck
Détecter et corriger les erreurs
5. Script de provisioning complet
Node.js, PostgreSQL, Nginx, pare-feu, déploiement application
Recap de la semaine
Bash, processus, réseau, SSH — aujourd'hui on combine tout
Patterns de scripting avancés
Idempotence, fonctions réutilisables, gestion d'erreurs
set -euo pipefail
Le mode strict Bash et ses subtilités
trap
Nettoyer les ressources en cas d'erreur
shellcheck
Linter pour scripts Bash, détecte les erreurs courantes
Live coding
Construire ensemble le début du script de provisioning
Planifier l'après-midi
Les étudiants finissent le script en autonomie
Aujourd'hui on combine tout
Bash & Scripting
Variables, conditions, boucles, fonctions
Processus & Services
systemd, journalctl, cron
Réseau & Diagnostic
TCP/IP, IP, Ports, DNS, Pare-feu
SSH
Connexion distante, clés, sécurité
💡 Le script doit pouvoir tourner N fois sans problème
❌ Sans idempotence
apt install nginx
# Erreur si déjà installé
âś… Avec idempotence
apt install -y nginx
# -y = auto-confirm
⚠️ Pattern : Vérifier avant d'agir
if
! command -v nginx ; thenapt install -y nginx
fi
📦 Encapsuler la logique dans des fonctions
install_package() {
# Vérifier si déjà installé
if ! command -v "$1"; then
apt install -y "$1"
else
echo "$1 already installed"
fi
}
install_package nginx
Réutilisable
install_package postgresql
Testable
install_package nodejs
Maintenable
❌ Sans gestion d'erreurs
apt install nginx
systemctl start nginx
cp config /etc/nginx/
# Continue même si échec
âś… Avec gestion d'erreurs
set -e
apt install nginx
systemctl start nginx
# Stop à la première erreur
🛡️ Deux outils essentiels :
set -euo pipefail pour arrĂŞter aux erreurs
trap pour nettoyer les ressources
đź’ˇ Qu'est-ce que trap ?
Une commande qui exécute du code quand le script se termine (succès ou erreur)
Comme un finally en JavaScript
Utile pour : supprimer fichiers temporaires, libérer verrous, arrêter services
Le mode strict Bash
-e
Exit immédiatement si une commande échoue
Comme throw en JS
-u
Erreur si variable non définie
Évite les bugs silencieux
-o pipefail
Le pipe échoue si ANY commande échoue
Par défaut, seul le dernier compte
set -e
# ArrĂŞte le script si une commande retourne non-zero
❌ Attention aux commandes qui échouent volontairement
grep "pattern" file.txt
# Si pas trouvé = exit code 1 = script s'arrête!
âś… Solution : || true
grep "pattern" file.txt || true
# Continue même si pas trouvé
đź’ˇ Pattern : if command
if grep "pattern" file.txt; then
# trouvé
fi
# if gère le exit code, pas besoin de || true
set -u
# Erreur si une variable non définie est utilisée
❌ Sans set -u
echo $UNDEFINED_VAR
# Affiche une ligne vide
# Bug silencieux!
âś… Avec set -u
echo $UNDEFINED_VAR
# UNDEFINED_VAR: unbound variable
# Script s'arrête immédiatement
💡 Pattern : Valeurs par défaut
echo "${VAR:-default}"
# Utilise "default" si VAR non définie
set -o pipefail
# Le pipe échoue si ANY commande échoue
❌ Sans pipefail
cat nonexistent.txt | grep "pattern"
# cat échoue mais grep réussit
# Exit code = 0 (succès!)
âś… Avec pipefail
cat nonexistent.txt | grep "pattern"
# cat échoue
# Exit code = 1 (échec)
⚠️ Pourquoi c'est important
Sans pipefail, les erreurs dans les pipes sont ignorées silencieusement
Avec pipefail, set -e fonctionne correctement avec les pipes
đź’ˇ Toujours en haut de vos scripts
#!/bin/bash
# Mode strict
set -euo pipefail
set -e
ArrĂŞte aux erreurs
set -u
Variables définies
set -o pipefail
Pipes robustes
📝 Règle d'or
Commencez TOUJOURS vos scripts avec set -euo pipefail
C'est le "use strict" de Bash
Nettoyer les ressources en cas d'erreur
Comme un finally en JavaScript
Exécute du code quand le script se termine (succès ou erreur)
Cas d'usage typiques
Signaux capturés
cleanup() {
# Nettoyer les ressources
rm -f /tmp/provisioning.lock
echo "Cleanup completed"
}
trap cleanup EXIT
# ... suite du script
✅ Succès
Script termine normalement → cleanup() appelé
❌ Erreur
Script échoue (set -e) → cleanup() quand même appelé
đź’ˇ Pattern : Verrouillage
touch /tmp/provisioning.lock
trap 'rm -f /tmp/provisioning.lock' EXIT
# Le verrou est toujours supprimé, même en cas d'erreur
Linter pour scripts Bash
Détecte les erreurs courantes avant l'exécution
Comme ESLint pour JavaScript
Erreurs de syntaxe
Problèmes de style
Bugs potentiels
❌ Code avec erreurs
name=$1
echo $name
rm -rf $name
⚠️ SC2086: Double quote to prevent globbing
⚠️ SC2115: Use "${var:?}" to check
✅ Code corrigé
name="$1"
echo "$name"
rm -rf "$name"
✅ Variables correctement quotées
đź’ˇ Installation et usage
# Installation
apt install shellcheck
# Usage
shellcheck script.sh
Construire ensemble le script de provisioning
Objectif : Installer et configurer
Logiciels
Configuration
#!/bin/bash
# Mode strict
set -euo pipefail
# Variables de configuration
APP_DIR="/var/www/myapp"
DB_NAME="myapp_db"
# Fonctions utilitaires
install_package() { ... }
configure_nginx() { ... }
# Cleanup
trap cleanup EXIT
# Installation
main() { ... }
main
install_nodejs() {
# Vérifier si déjà installé
if ! command -v node; then
# Ajouter repo NodeSource
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
# Installer Node.js
apt install -y nodejs
else
echo "Node.js already installed: $(node -v)"
fi
}
âś… Idempotence
Vérifie si Node.js est déjà installé avant de tenter l'installation
install_postgresql() {
# Vérifier si déjà installé
if ! command -v psql; then
# Installer PostgreSQL
apt install -y postgresql postgresql-contrib
# Démarrer le service
systemctl start postgresql
systemctl enable postgresql
else
echo "PostgreSQL already installed"
fi
}
âś… Services systemd
Utilise systemctl pour démarrer et activer les services au boot
install_nginx() {
# Vérifier si déjà installé
if ! command -v nginx; then
# Installer Nginx
apt install -y nginx
# Démarrer le service
systemctl start nginx
systemctl enable nginx
else
echo "Nginx already installed"
fi
}
💡 Prochaines étapes
Configurer le virtual host, SSL, et reverse proxy vers l'application Node.js
configure_nginx_vhost() {
# Créer le fichier de configuration
cat > /etc/nginx/sites-available/myapp <
server {
listen 80;
server_name myapp.example.com;
root /var/www/myapp/public;
index index.html;
}
EOF
# Activer le site
ln -sf /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
# Tester la configuration
nginx -t
# Recharger Nginx
systemctl reload nginx
}
đź’ˇ Nginx comme reverse proxy vers Node.js
configure_nginx_proxy() {
cat > /etc/nginx/sites-available/myapp <
server {
listen 80;
server_name myapp.example.com;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
EOF
nginx -t && systemctl reload nginx
}
âś… Toujours tester avant de recharger
test_nginx_config() {
# Tester la syntaxe
nginx -t
# Si succès, recharger
if nginx -t; then
systemctl reload nginx
echo "Nginx reloaded successfully"
else
echo "Nginx config test failed"
exit 1
fi
}
âś… nginx -t
Teste la syntaxe sans appliquer les changements
âś… systemctl reload
Recharge sans couper les connexions existantes
configure_firewall() {
# Autoriser SSH
ufw allow ssh
# Autoriser HTTP/HTTPS
ufw allow 80/tcp
ufw allow 443/tcp
# Activer le pare-feu
ufw --force enable
}
⚠️ Attention
Toujours autoriser SSH AVANT d'activer le pare-feu pour ne pas se bloquer!
âś… Idempotence
UFW est idempotent par défaut — les règles existantes ne sont pas dupliquées
deploy_app() {
# Créer répertoire
mkdir -p "$APP_DIR"
# Copier les fichiers (git clone ou scp)
git clone "$REPO_URL" "$APP_DIR"
# Installer dépendances
cd "$APP_DIR" && npm install
# Créer service systemd
setup_systemd_service
# Démarrer l'application
systemctl start myapp
systemctl enable myapp
}
1. L'idempotence est le concept le plus important
Le script doit pouvoir tourner N fois sans problème
2. set -e arrête le script à la première erreur
Mais attention aux commandes qui échouent volontairement (grep, test)
3. Montrer shellcheck en live
Coller un script avec des erreurs et les corriger une par une
4. trap EXIT permet de nettoyer mĂŞme en cas d'erreur
Comme un finally en JavaScript
5. Le script final est le résumé pratique de toute la semaine
Combine Bash, processus, réseau, SSH
❌ set -e interagit mal avec les pipes
C'est pour ça qu'on ajoute pipefail — sans pipefail, seule la dernière commande compte
❌ Oublier de tester l'idempotence
Le script marche une fois mais crash la deuxième — toujours tester plusieurs fois!
❌ Ne pas gérer les différences entre distributions
apt vs yum vs dnf — détecter la distribution et adapter les commandes
❌ Hardcoder des chemins
Utiliser des variables en haut du script pour faciliter la maintenance
Les étudiants finissent le script en autonomie
📝 Tâches à compléter
🎯 Objectif
Un script idempotent qui provisionne un serveur complet de A Ă Z
đź’ˇ Bon courage!
N'hésitez pas à utiliser shellcheck et à demander de l'aide