28 juin 2019

Ansible tip: configuration, assemble and idempotence

Il arrive parfois que vous ayez à configurer avec Ansible un logiciel n’acceptant qu’un fichier de configuration, et où il est impossible d’inclure un autre fichier ou dossier depuis ce fichier. Je présenterais ici une astuce pour gérer cela avec Ansible et le module assemble.

Le problème

Prenons par exemple haproxy. Il est impossible d’inclure depuis le fichier de configuration principal d’autres fichiers ou dossiers (bien qu’il soit possible de passer plusieurs fichiers de configuration en passant plusieurs fois le paramètre -f` à la commande de lancement).
EDIT: faux ! Il est en fait possible de passer un répertoire à HAProxy. Mais nous utiliserons quand même HAProxy comme exemple dans cet article ;)

Il existe une solution élégante avec Ansible permettant de découper cette configuration en plusieurs fichiers dans un dossier, tout en ayant un déploiemnt idempotent.

La solution

Nous allons créer plusieurs fichiers dans un dossier, puis les concaténer pour obtenir le fichier final.

On commence par supprimer ledit dossier, par exemple /etc/haproxy/haproxy.d:

- name: delete haproxy.d directory
  become: true
  file:
    path: /etc/haproxy/haproxy.d
    state: absent
  changed_when: false

Notez le changed_when: false: Ansible ne considérera pas qu’il y a eu un changement si le dossier est effectivement supprimé.

Puis on recrée ce répertoire:

- name: create haproxy.d directory
  become: true
  file:
    path: /etc/haproxy/haproxy.d
    state: directory
    owner: root
    group: root
    mode: 0755
  changed_when: false

Là aussi, on a un changed_when: false. A cette étape du rôle, on a donc la garantie d’avoir un dossier /etc/haproxy/haproxy.d vide.

Ensuite, on utilise la directive template pour déployer dans ce nouveau dossier nos fichiers de configuration. Attention, il faut que les fichiers soient ordonnés par ordre alphabétique. Par exemple, je pourrais préfixer chaque fichier par un numéro:

haproxy_configuration_templates:
  - src: haproxy/haproxy.cfg.j2
    dest: 01_haproxy.cfg
  - src: haproxy/frontend.j2
    dest: 02_frontend.cfg
  - src: haproxy/blog.j2
    dest: 03_blog.cfg
  - src: haproxy/meuse.j2
    dest: 03_meuse.cfg
  - src: haproxy/tour.j2
    dest: 03_tour.cfg

Ensuite, je template ces fichiers:

- name: template haproxy configuration in haproxy.d
  become: true
  template:
    src: "{{ item.src }}"
    dest: "/etc/haproxy/haproxy.d/{{ item.dest }}"
    owner: root
    group: root
    mode: 0644
  with_items: "{{ haproxy_configuration_templates }}"
  changed_when: false

Ici aussi on a un changed_when: false, ce qui est très important. Cette tâche ne provoquera aucun changement lors de son exécution.

Ensuite, je concatène tous ces fichiers ensemble en utilisant assemble:

- name: assemble haproxy.d configuration
  become: true
  assemble:
    src: /etc/haproxy/haproxy.d
    dest: /etc/haproxy/haproxy.cfg
    owner: root
    group: root
    mode: 0644
  notify: haproxy | reload

Un handler me permet de reload HAProxy en cas de changement. assemble ne provoquera un changement que si le résultat de l’assemblage des fichiers est différent de l’état existant.

Et c’est fini.

Si une configuration identique est déployée, les changed_when: false feront qu’Ansible ne détectera pas de changement. Si une configuration différente est déployée, on aura un changement sur la tâche assemble.

Le fait de supprimer et recréer le dossier contenant les fichiers est obligatoire pour gérer le cas d’un fichier template qui serait supprimé de la liste des fichiers à déployer. Dans ce cas, on ne veut pas avoir des fichiers non voulus dans /etc/haproxy/haproxy.d venant d’un ancien déploiement (d’où le nettoyage).

Tags: devops ansible
Top of page