Même si les modules
Ansiblecommand
et shell
sont fortement déconseillés, il est des cas où il est
impossible de s'en passer, Voyons donc comment les utiliser correctement .
Quand utilisez les modules shell et command ?
Les modules de commandes ne doivent être exécutés que si les modules permettant
d'exécuter l'action dont vous avez besoin n'existe pas. Par exemple, les commandes
permettant de remettre en état le système de packages du système d'exploitation
de vos cibles. Si vous avez un script a exécuté utiliser le module script
.
- name: Run a script with arguments (free form)
ansible.builtin.script: /some/local/script.sh --some-argument 1234
Différences entre les modules shell et command
Même si la finalité de ces deux modules sont identiques, ils existent des différences :
- Le module
Ansible
shell exécute les commandes directement via le shell des hôtes cibles. Par
défaut, le module shell utilise par défaut
sh
pour exécuter les commandes (il est possible de définir d'autres shell via l'optionexecutable
). Avec le modulecommand
, les commandes ne sont pas exécutées via le shell. - Le module
command
ne prend pas en charge les variables d'environnement, les pipes et les opérateurs tels que<
,>
,&
,;
...
Il est ainsi plus sécurisant d'utiliser le module command
que shell
puisqu'il
ne pourra être affecté par les variables du shell de l'utilisateur. Par contre
comme les opérateurs ne sont pas disponibles, il faut traiter les valeurs dans
votre playbook
Ansible
via les filtres Jinja.
Utilisation des options creates et removes
Peu utilisé et pourtant si pratique ces options permettent de ne faire tourner
les commandes que si un fichier est absent avec creates
ou présent removes
.
Par exemple pour éviter de démarrer un script démarrant un service, vous pouvez
utiliser le paramètre creates
.
- name: Start the service when the PID file is not present
become: yes
become_user: user_application
ansible.builtin.command: "start_service.sh && touch /var/run/service.pid"
creates: "/var/run/service.pid"
Pour faire le contraire, utilisez l'option remove
.x
- name: Stop the service when the PID file is present
become: yes
become_user: user_application
ansible.builtin.command: "stop_service.sh && rm /var/run/service.pid"
removes: "/var/run/service.pid"
Utilisation des instructions failed_when et changed_when
Un point important, les modules shell
et command
s'il ne plante pas retourne
toujours le status changed
. Pour définir réellement quand une commande échoue
ou change quelque chose sur le système, vous devez utiliser les instructions
changed_when
et failed_when
.
changed_when
L'instruction changed_when
permet de définir quand une tâche réalise
concrètement un changement sur la cible.
- name: Install dependencies via Composer.
ansible.builtin.command: "/usr/local/bin/composer global require phpunit/phpunit --prefer-dist"
register: composer
changed_when: "'Nothing to install or update' not in composer.stdout"
Si les modules php sont déjà présents sur la cible, la commande composer ne fait rien et retourne juste le message
failed_when
Il peut arriver des cas où que certaines erreurs soient acceptables. C'est dans
ce genre de cas que nous allons utiliser l'instruction failed_when
.
- name:
ansible.builtin.shell: "ls | grep wp-config.php"
register: thecommand
failed_when: thecommand.rc not in [0, 1]
On peut aussi l'utiliser au démarrage d'un playbook, pour éviter qu'un outil d'installation ne plante par manque de ressources
- name: Making sure the /tmp has more than 2gb
ansible.builtin.shell: "df -h /tmp|grep -v Filesystem|awk '{print $4}'|cut -d G -f1"
register: tmpspace
failed_when: "tmpspace.stdout|float < 2"