SecOps Toolkit

Convertisseur bidirectionnel de crontab vers minuteur systemd

Migrer des tâches cron vers des minuteurs systemd améliore la journalisation, le contrôle et le rattrapage des exécutions manquées, mais traduire la syntaxe à la main est source d’erreurs. Cet outil valide votre expression cron, l’explique en langage clair, calcule les cinq prochaines exécutions et génère les fichiers .service et .timer prêts à copier.

Il fonctionne aussi dans l’autre sens : collez une expression OnCalendar et obtenez l’expression cron équivalente lorsque c’est possible.

Pourquoi migrer de cron vers les minuteurs systemd

Cron planifie des tâches sous Linux depuis des décennies, mais systemd offre des avantages opérationnels nets : chaque exécution est enregistrée dans le journal avec son code de sortie, les unités peuvent déclarer des dépendances et des limites de ressources, l’état se consulte avec systemctl list-timers, et Persistent=true permet de rattraper les exécutions manquées lorsque la machine était éteinte. Cet outil convertit dans les deux sens entre une expression cron et les fichiers .service et .timer équivalents.

Anatomie d’une expression cron

Une ligne de crontab comporte cinq champs lus de gauche à droite :

  • minute (0-59), heure (0-23), jour du mois (1-31), mois (1-12 ou noms) et jour de la semaine (0-7 ou noms, où 0 et 7 désignent le dimanche).
  • Opérateurs : * (tous), , (liste), - (plage) et / (pas). Par exemple, */15 dans les minutes correspond à 0, 15, 30 et 45.
  • Macros : @hourly, @daily, @weekly, @monthly et @yearly.

Il existe une règle méconnue : lorsque le jour du mois et le jour de la semaine sont tous deux restreints, cron exécute la tâche si l’un ou l’autre correspond (opération OU). systemd, lui, exige que les deux correspondent. C’est pourquoi l’outil génère deux lignes OnCalendar dans ce cas.

Anatomie d’OnCalendar

Le format de systemd est JourSemaine AAAA-MM-JJ HH:MM:SS, où chaque composant accepte *, des listes séparées par des virgules, des plages avec .. et des répétitions avec /. Les secondes sont complétées par :00 pour reproduire la granularité d’une minute de cron.

  • 30 2 * * * devient *-*-* 02:30:00.
  • */15 * * * * devient *-*-* *:00/15:00.
  • 0 9 * * 1-5 devient Mon..Fri *-*-* 09:00:00.
  • 0 4 1 * * devient *-*-1 04:00:00.

Les deux fichiers : service et minuteur

Le fichier .service décrit ce qui est exécuté. Il est déclaré en Type=oneshot, car la tâche démarre, se termine et quitte. Il accepte User=, WorkingDirectory= et ExecStart= avec le chemin absolu de l’exécutable. Le fichier .timer décrit quand l’exécution a lieu :

  • OnCalendar= : le calendrier équivalent à l’expression cron.
  • Persistent=true : enregistre sur disque la dernière activation et, si une activation a été manquée pendant que la machine était éteinte, la déclenche au démarrage.
  • AccuracySec= : marge de tolérance pour regrouper les activations et économiser l’énergie. La valeur par défaut est de 1 minute ; avec 1s, l’exécution est quasi exacte.
  • Unit= et la section [Install] avec WantedBy=timers.target, afin que le minuteur démarre avec le système.

Différences d’environnement à l’origine des échecs

  • PATH minimal : systemd n’hérite pas de l’environnement de votre shell. Utilisez des chemins absolus dans ExecStart.
  • Pas de shell par défaut : les tubes, redirections et variables nécessitent /bin/sh -c '...', que l’outil ajoute automatiquement.
  • Caractères spéciaux : dans un fichier d’unité, % et $ ont une signification propre et s’échappent en %% et $$. Dans un crontab, un % non échappé équivaut à un saut de ligne.
  • Pas d’e-mail : cron envoie la sortie par courrier (MAILTO) ; systemd la conserve dans le journal, que l’on consulte avec journalctl -u nom.service.

Vérification recommandée

Avant d’activer le minuteur, validez le calendrier avec systemd-analyze calendar "*-*-* 02:30:00", qui affiche la forme normalisée et la prochaine exécution, et contrôlez la syntaxe des unités avec systemd-analyze verify. Après l’activation, systemctl list-timers confirme à quel moment la prochaine exécution aura lieu.

Cas d’usage concrets

  • Sauvegardes nocturnes avec Persistent=true, pour qu’elles ne soient pas perdues si le serveur était éteint.
  • Rotation et nettoyage des logs avec des exécutions à faible priorité et un AccuracySec large.
  • Renouvellement de certificats et synchronisations avec une traçabilité auditable dans le journal.
  • Audits de migration : convertir en bloc un crontab hérité et repérer les tâches qui dépendent de variables d’environnement.

Fuseau horaire

Cron et systemd exécutent les tâches selon le fuseau horaire du serveur, sauf indication contraire. L’outil affiche les cinq prochaines exécutions à l’heure locale de votre navigateur ou en UTC afin que vous puissiez vérifier que le calendrier correspond à vos attentes.

Questions fréquentes

Que fait exactement Persistent=true dans un minuteur systemd ?
Avec Persistent=true, systemd enregistre sur disque la date de la dernière activation du minuteur. Si la machine était éteinte ou en veille au moment où la tâche devait s’exécuter, elle la lance immédiatement au démarrage suivant pour rattraper l’exécution manquée. Le comportement est équivalent à celui d’anacron et n’a d’effet qu’avec les minuteurs basés sur un calendrier (OnCalendar). C’est particulièrement utile sur les portables, les machines virtuelles éteintes régulièrement et les serveurs soumis à des fenêtres de maintenance.
Pourquoi une expression cron avec jour du mois et jour de la semaine génère-t-elle deux lignes OnCalendar ?
Parce que cron et systemd n’interprètent pas cette combinaison de la même manière. Dans cron, si les deux champs sont restreints, la tâche s’exécute lorsque l’un ou l’autre correspond (OU). Dans OnCalendar, le jour du mois et le jour de la semaine doivent correspondre simultanément (ET). Pour reproduire le comportement de cron, l’outil génère une ligne pour le jour du mois et une autre pour le jour de la semaine, et systemd déclenche le minuteur dès que l’une des deux correspond.
Quelle valeur d’AccuracySec choisir ?
La valeur par défaut de systemd est de 1 minute, ce qui permet de regrouper des activations proches et de réduire les réveils du processeur. Si vous avez besoin que la tâche démarre presque exactement à la seconde prévue, utilisez 1s, l’option présélectionnée dans l’outil. Pour les tâches peu sensibles au temps, comme les nettoyages ou les rapports, 1min voire 1h économisent de l’énergie. Pour répartir la charge de nombreux serveurs, associez un AccuracySec large à RandomizedDelaySec.
Pourquoi ma commande fonctionne-t-elle dans cron mais échoue-t-elle dans le service systemd ?
Les causes les plus fréquentes sont un PATH différent, l’absence de variables d’environnement, l’usage de fonctions de shell sans invoquer de shell et les caractères spéciaux. systemd n’exécute pas la commande dans un shell : les tubes, redirections et expansions de variables nécessitent donc /bin/sh -c. De plus, % et $ doivent être échappés en %% et $$ dans le fichier d’unité. Utilisez des chemins absolus, examinez l’erreur avec journalctl -u nom.service et testez le service avec systemctl start avant d’activer le minuteur.
Puis-je planifier des tâches en tant qu’utilisateur normal, sans être root ?
Oui. Placez les unités dans ~/.config/systemd/user/ et gérez-les avec systemctl --user, par exemple systemctl --user enable --now nom.timer. Pour qu’elles s’exécutent même sans session ouverte, un administrateur doit activer la persistance de votre utilisateur avec loginctl enable-linger. Dans ce cas, la directive User= n’est pas utilisée dans le service, car l’unité s’exécute déjà sous votre propre utilisateur. L’outil génère des fichiers système, que vous pouvez facilement adapter à cette modalité.