Aller au contenu principal

Utiliser correctement les modules Ansible shell et command

· 3 minutes de lecture
Stéphane ROBERT
Consultant DevOps

Même si les modules Ansible command 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éfautsh pour exécuter les commandes (il est possible de définir d'autres shell via l'option executable). Avec le module command, 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 commandque 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

  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"

Plus d'infos sur Ansible