Lancer puppet depuis cron

February 24, 2011 by nono
Catégories geekeries - Mots-clés cron puppet

Puppet, c'est bien. Ça a juste un tout petit inconvénient : c'est écrit en ruby, avec la consommation mémoire que ça implique. Vous me direz, 200 Mo, sur une machine moderne, c'est rien. Sauf que si vous commencez à jouer avec des isolateurs, vous allez vite vous rendre compte que 30 fois 200 Mo, ça finit par faire beaucoup. Surtout pour un outil qui passe 98% de son temps à dormir (non, il ne libère pas la mémoire pour autant).

J'ai donc pondu un petit bout de script shell pour lancer puppetd uniquement quand on a besoin de lui. J'en ai profité pour améliorer un peu la gestion de la périodicité. En gros,

  • par défaut, puppetd tourne une fois par heure,
  • si le fichier /var/run/puppet/run-often existe, il tourne toutes les 5 minutes pendant une heure au plus (il supprime le fichier après ce délai),
  • si le fichier /var/run/puppet/never-auto-run existe, il refuse de tourner (pratique pour les maintenances où on ne veut pas se battre contre puppet).

Tout ça, c'est géré par cron de cette façon :

*/5 * * * * /usr/local/sbin/run-puppet -often
42 * * * * /usr/local/sbin/run-puppet

Notez que ces deux invocations ne lancent pas puppetd immédiatement ; elles attendent «un certain temps» (calculé en fonction de l'adresse IPv4 de la machine, je voulais des intervalles fixes entre deux passages de Puppet).

Le script accepte aussi une option -now qui lui indique de lancer puppet immédiatement ; cette option est conçue pour invoquer le script directement en ligne de commande.

Finalement, le script lui-même :

#!/bin/bash
#
# Arnaud Gomes 2010
#
# Trigger a puppet run.
#
# Usage:
#
#   run-puppet
#       Run sometime in the next hour.
#
#   run-puppet -often
#       Run sometime in the next 5 minutes if $runoftenfile exists.
#
#   run-puppet -now
#       Run now.
#
# This script will exit immediately if $dontrunfile exists.
#
# Needs /usr/bin/lockfile (from procmail).

flagdir="/var/run/puppet"
runoftenfile=${flagdir}"/run-often"
dontrunfile=${flagdir}"/never-auto-run"
lockfile=${flagdir}"/lock"
puppetd="/usr/sbin/puppetd"
flags="--no-daemonize --onetime --no-splay"

usage () {
        echo "Usage: $0 [ -often | -now ]"
        exit 1
}

dontrun () {
        echo "$dontrunfile present, skipping this run."
        exit 0
}

run () {
        lockfile $lockfile
        $puppetd $flags
        rm -f $lockfile
}

[ $# -le 1 ] || usage
[ -f $dontrunfile ] && dontrun

# $seed is used for computing splay time. We do not make it random
# as we want each machine to run puppet every hour (or whatever), not
# "more or less randomely averaging to once every hour".
#
# This horrible perl thing just means "last two bytes from IPv4 address,
# reversed". We reverse them as the last byte probably is more evenly
# distributed.
seed=$(($(facter ipaddress | perl -pe 's/^([0-9]+\.){2}([0-9]+)\.([0-9]+)$/$3 * 256 + $2/')))
splay=$(($seed % 3600))

# Exit if called with -often and no $runoftenfile.
# If $runoftenfile is here, we run within 5 minutes instead of within
# an hour.
if [ "$1" = "-often" ]
then
        [ -f $runoftenfile ] || exit 0
        splay=$(($seed % 300))
fi

# Of course option -now removes any splay time.
if [ "$1" = "-now" ]
then
        splay=0
        flags="$flags --verbose"
fi

sleep $splay
run

# Remove $runoftenfile after an hour. We don't want to run every 5 minutes
# for ever, only when needed.
[ -f $runoftenfile ] && find $runoftenfile -cmin +60 -exec rm -f {} \;