Aller au contenu

Path Units (.path)

Les unités .path surveillent des fichiers ou répertoires et déclenchent des services lorsque des modifications sont détectées. Elles utilisent les APIs inotify du noyau Linux pour une surveillance efficace.

Principe de fonctionnement

  1. systemd surveille un chemin spécifié
  2. Une condition se produit (fichier créé, modifié, supprimé...)
  3. systemd active automatiquement le service associé
  4. Le service traite l'événement

Structure d'un path unit

[Unit]
Description=Watch for configuration changes

[Path]
PathModified=/etc/myapp/config.yaml
Unit=myapp-reload.service

[Install]
WantedBy=multi-user.target

Section [Path]

Types de surveillance

PathExists

Déclenche quand le fichier ou répertoire existe

[Path]
PathExists=/tmp/trigger-file

Utilisé pour : déclenchement manuel, fichiers de verrouillage.

PathExistsGlob

Comme PathExists mais supporte les wildcards

[Path]
PathExistsGlob=/var/spool/mail/*
PathChanged

Déclenche quand le fichier ou répertoire change (création, modification, suppression)

[Path]
PathChanged=/etc/myapp/

Détecte les changements de métadonnées (permissions, propriétaire) mais pas le contenu.

PathModified

Déclenche quand le contenu change (plus précis que PathChanged)

[Path]
PathModified=/etc/myapp/config.yaml

Détecte les modifications réelles du contenu du fichier.

DirectoryNotEmpty

Déclenche quand le répertoire contient au moins un fichier

[Path]
DirectoryNotEmpty=/var/spool/myapp

Utilisé pour : traitement de files d'attente, spool directories.

Options

Unit

Service à activer (par défaut : même nom avec .service)

Unit=my-handler.service
MakeDirectory

Créer le répertoire s'il n'existe pas

MakeDirectory=yes
DirectoryMode=0755
TriggerLimitBurst / TriggerLimitIntervalSec

Limite le nombre de déclenchements

TriggerLimitBurst=5
TriggerLimitIntervalSec=60s

Protège contre les boucles infinies.

Exemples pratiques

Rechargement automatique de configuration

# /etc/systemd/system/nginx-config-watch.path
[Unit]
Description=Watch Nginx Configuration

[Path]
PathModified=/etc/nginx/nginx.conf
PathModified=/etc/nginx/conf.d/
Unit=nginx-reload.service

[Install]
WantedBy=multi-user.target
# /etc/systemd/system/nginx-reload.service
[Unit]
Description=Reload Nginx Configuration

[Service]
Type=oneshot
ExecStart=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx -s reload

Activation :

systemctl enable nginx-config-watch.path
systemctl start nginx-config-watch.path

# Nginx se recharge automatiquement quand la config change

Traitement de files d'attente

# /etc/systemd/system/process-queue.path
[Unit]
Description=Watch Upload Queue

[Path]
DirectoryNotEmpty=/var/spool/uploads
MakeDirectory=yes

[Install]
WantedBy=multi-user.target
# /etc/systemd/system/process-queue.service
[Unit]
Description=Process Upload Queue

[Service]
Type=oneshot
ExecStart=/usr/local/bin/process-uploads.sh
User=processor

Déclenchement manuel

# /etc/systemd/system/backup-trigger.path
[Unit]
Description=Manual Backup Trigger

[Path]
PathExists=/tmp/trigger-backup
Unit=backup.service

[Install]
WantedBy=multi-user.target

Utilisation :

# Déclencher la sauvegarde
touch /tmp/trigger-backup

# Le service backup.service se lance automatiquement

Surveillance de certificats

# /etc/systemd/system/ssl-cert-watch.path
[Unit]
Description=Watch SSL Certificates

[Path]
PathChanged=/etc/ssl/certs/mysite.crt
PathChanged=/etc/ssl/private/mysite.key
Unit=ssl-cert-reload.service

[Install]
WantedBy=multi-user.target
# /etc/systemd/system/ssl-cert-reload.service
[Unit]
Description=Reload Services After Cert Change

[Service]
Type=oneshot
ExecStart=/usr/bin/systemctl reload nginx.service
ExecStart=/usr/bin/systemctl reload postfix.service

Surveillance de logs

# /etc/systemd/system/error-log-watch.path
[Unit]
Description=Watch Error Logs

[Path]
PathModified=/var/log/myapp/error.log
Unit=error-alert.service
TriggerLimitBurst=10
TriggerLimitIntervalSec=300s

[Install]
WantedBy=multi-user.target
# /etc/systemd/system/error-alert.service
[Unit]
Description=Send Error Alert

[Service]
Type=oneshot
ExecStart=/usr/local/bin/send-alert.sh "Errors detected in log"

Hot-reload d'application

# /etc/systemd/system/app-reload.path
[Unit]
Description=Watch Application Files

[Path]
PathModified=/opt/myapp/app.py
PathModified=/opt/myapp/config.py
Unit=myapp-reload.service

[Install]
WantedBy=multi-user.target
# /etc/systemd/system/myapp-reload.service
[Unit]
Description=Reload My Application

[Service]
Type=oneshot
ExecStart=/usr/bin/systemctl reload myapp.service

Traitement batch de fichiers

# /etc/systemd/system/file-processor.path
[Unit]
Description=Watch for Files to Process

[Path]
PathExistsGlob=/var/spool/input/*.csv
Unit=file-processor.service

[Install]
WantedBy=multi-user.target
# /etc/systemd/system/file-processor.service
[Unit]
Description=Process CSV Files

[Service]
Type=oneshot
ExecStart=/usr/local/bin/process-csv-files.sh
User=processor

Gestion des path units

Commandes de base

# Lister les path units
systemctl list-units --type=path
systemctl list-units --type=path --all

# Activer
systemctl enable mywatch.path
systemctl start mywatch.path

# Désactiver
systemctl stop mywatch.path
systemctl disable mywatch.path

# Voir l'état
systemctl status mywatch.path

# Voir les chemins surveillés
systemctl show mywatch.path -p Paths

Tester un path unit

# Démarrer la surveillance
systemctl start mywatch.path

# Dans un autre terminal, surveiller les logs
journalctl -u mywatch.path -f
journalctl -u mywatch.service -f

# Modifier le fichier surveillé
echo "test" >> /path/to/watched/file

# Observer l'activation du service

Cas d'usage avancés

Multiple chemins, un seul service

[Path]
PathModified=/etc/app/config1.yaml
PathModified=/etc/app/config2.yaml
PathModified=/etc/app/includes/
Unit=app-reload.service

Tout changement déclenche le même service.

Chaînes de traitement

# Stage 1: Détection de fichiers
# process-stage1.path
[Path]
DirectoryNotEmpty=/var/spool/stage1
Unit=process-stage1.service
# process-stage1.service déplace vers stage2
[Service]
Type=oneshot
ExecStart=/usr/local/bin/stage1-to-stage2.sh
# Stage 2: Traitement
# process-stage2.path
[Path]
DirectoryNotEmpty=/var/spool/stage2
Unit=process-stage2.service

Avec dépendances

# config-watch.path
[Unit]
Description=Configuration Watcher
After=myapp.service

[Path]
PathModified=/etc/myapp/config.yaml
Unit=myapp-reload.service

[Install]
WantedBy=multi-user.target

Le path unit ne démarre qu'après le service principal.

Limitations et considérations

Limitations inotify

Linux limite le nombre de watches inotify :

# Voir la limite actuelle
cat /proc/sys/fs/inotify/max_user_watches

# Augmenter temporairement
echo 524288 | sudo tee /proc/sys/fs/inotify/max_user_watches

# Permanent (/etc/sysctl.conf)
fs.inotify.max_user_watches=524288

Performance

La surveillance de nombreux fichiers peut consommer des ressources :

  • Privilégier DirectoryNotEmpty plutôt que PathExistsGlob
  • Éviter de surveiller des répertoires avec des milliers de fichiers
  • Utiliser des patterns spécifiques plutôt que génériques

Systèmes de fichiers réseau

inotify ne fonctionne pas sur tous les systèmes de fichiers réseau (NFS, CIFS).

Alternative : utiliser des timers avec polling.

Boucles infinies

Attention aux services qui modifient les fichiers surveillés :

# Protection
[Path]
TriggerLimitBurst=3
TriggerLimitIntervalSec=60s

Débogage

Path unit ne déclenche pas

# Vérifier l'état
systemctl status mywatch.path

# Le path est-il correct ?
systemctl show mywatch.path -p Paths

# Le fichier existe ?
ls -l /path/to/watched/file

# Logs
journalctl -u mywatch.path

# Tester manuellement le service
systemctl start mywatch.service

Déclenchements trop fréquents

# Voir l'historique des déclenchements
journalctl -u mywatch.path
journalctl -u mywatch.service

# Ajuster les limites
[Path]
TriggerLimitBurst=5
TriggerLimitIntervalSec=120s

Service ne s'exécute pas

# Vérifier que le service existe
systemctl cat mywatch.service

# Tester le service indépendamment
systemctl start mywatch.service
systemctl status mywatch.service

# Logs du service
journalctl -u mywatch.service -n 50

Comparaison avec d'autres approches

Path units vs inotifywait

inotifywait :

#!/bin/bash
while inotifywait -e modify /etc/myapp/config.yaml; do
    systemctl reload myapp.service
done

Path units :

  • Intégration systemd native
  • Logs dans journald
  • Gestion automatique du cycle de vie
  • Redémarrage automatique en cas d'échec

Path units vs Timers

Timers : Vérification périodique (polling)

[Timer]
OnUnitActiveSec=5min

Path units : Réaction immédiate (inotify)

  • Plus réactif
  • Moins de charge système
  • Mais ne fonctionne pas sur tous les FS

Bonnes pratiques

  1. Utiliser Type=oneshot pour les services déclenchés
[Service]
Type=oneshot
  1. Toujours définir des limites
TriggerLimitBurst=5
TriggerLimitIntervalSec=60s
  1. Créer les répertoires si nécessaire
MakeDirectory=yes
DirectoryMode=0755
  1. Surveiller les répertoires plutôt que les fichiers individuels
PathModified=/etc/myapp/
  1. Documenter clairement
[Unit]
Description=Clear description of what triggers this
  1. Tester les limites inotify
cat /proc/sys/fs/inotify/max_user_watches
  1. Logger les déclenchements
[Service]
Type=oneshot
ExecStartPre=/usr/bin/logger "Path triggered: processing"

Les path units sont un outil puissant pour réagir aux changements du système de fichiers, permettant une automatisation élégante de nombreuses tâches administratives.