Ansible: échapper un caractère point ('.')

Tags: #<Tag:0x00007f63f452a620>

Bonjour,

j’essaie de me servir d’ansible comme solution d’inventaire sur un petit parc de serveurs, et notamment pour recenser les versions installées de tels ou tels paquets.
Pour ça il y a le module package_facts qui est très pratique, mais je n’arrive pas à m’en servir pour les paquets dont le nom comporte le cractère . (comme php7.4).
Mon playbook est comme ceci:

- hosts: ct
  vars:
    - debug: 1
  tasks:
    - name: "Gather packages informations"
      package_facts:
        manager: apt
    - name: Print
      debug:
        var: ansible_facts.packages
      when: debug == 1
    - name: "Check apache version"
      debug:
        msg: "Apache {{ ansible_facts.packages.apache2[0].version }} installé"
      when: "'apache2' in ansible_facts.packages"
    - name: "Check PHP version"
      debug:
        msg: "PHP version {{ ansible_facts.packages.php7.4[0].version }} installé"
      when: "'php7.4' in ansible_facts.packages"

Mais si pour la tâche pour les versions apache, ça fonctionne bien, pour celle des versions php7.4, j’ai cette erreur, qui semble logique:

 FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'php7'}

J’ai tenté de remplacer la ligne

 msg: "PHP version {{ ansible_facts.packages.php7.4[0].version }} installé"

par

msg: "PHP version {{ ansible_facts.packages.['php7.4'][0].version }} installé"

et d’autres combinaisons du même genre, comme msg: "PHP version {{ ansible_facts.packages.['php7.4'][0].version }} installé", mais l’erreur devient:

FAILED! => {"msg": "template error while templating string: expected name or number. String: PHP version {{ ansible_facts.packages.['php7.4'][0].version }} installé"}

La variable

 "ansible_facts.packages": {
[...]
        "php7.4": [
            {
                "arch": "all",
                "category": "php",
                "name": "php7.4",
                "origin": "deb.sury.org",
                "source": "apt",
                "version": "7.4.27-1+0~20211220.57+debian11~1.gbp832572"
            }
        ],
[...]
    }
}

J’ai visiblement un soucis pour parcourir efficacement ce genre de structure mêlant des listes et des dictionnaires, si un ninja d’ansible ou python peut m’expliquer le topo, je lui en serais très reconnaissant :grinning_face_with_smiling_eyes:

D’après la Doc on fait plus comme ça :

- name: Gather the package facts
  ansible.builtin.package_facts:
    manager: auto

- name: Print the package facts
  ansible.builtin.debug:
    var: ansible_facts.packages

- name: Check whether a package called foobar is installed
  ansible.builtin.debug:
    msg: "{{ ansible_facts.packages['foobar'] | length }} versions of foobar are installed!"
  when: "'foobar' in ansible_facts.packages"

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/package_facts_module.html

Du coup tu doit récupérer un string :wink:

J’ai commencé par cette doc, oui.
L’exemple donné permet d’afficher le nombre de versions installées d’un même paquet, en fait foobar est une liste de dictionnaires (le | lenght permet d’avoir le nombre de dictionnaires), comme php7.4 dans mon exemple, même si dans mon cas cette liste ne contient qu’un seul dictionnaire (d’où le [0]).
Mais comme je disais, mon playbook fonctionne nickel pour apache et d’autres paquets, je bute juste sur les paquets qui ont un point dans leur nom, vu qu’avec ansible on utilise ce caractère pour accéder aux sous-éléments d’un élément

Salut. Regard par là Escaping all Special Characters Using Ansible Shell | by Ardhi, Muhammad | Medium

Il y a un exemple avec le point.

Salut,
l’article parle du module shell d’ansible, que je n’utilise pas.
J’ai aussi essayé d’échapper le point avec un \ mais j’ai dans ce cas une erreur de syntaxe.

Mais j’ai continué à expérimenter suivant la doc sur les variables imbriquées, et la solution est d’utiliser la notation avec des crochets comme ceci:

    - name: "Check PHP version"
      debug:
        msg: "PHP version {{ ansible_facts['packages']['php7.4'][0]['version'] }} installé"
      when: "'php7.4' in ansible_facts.packages"

Et le résultat est là:

TASK [Check PHP version] ******************************************************************************************************************************************************************************************
ok: [nextcloud] => {
    "msg": "PHP version 7.4.27-1+0~20211220.57+debian11~1.gbp832572 installé"
}
skipping: [ansible]
ok: [zabbix] => {
    "msg": "PHP version 7.4.27-1+0~20211220.57+debian11~1.gbp832572 installé"
}
skipping: [grafana]
skipping: [openldap]
ok: [glpi] => {
    "msg": "PHP version 7.4.25-1+deb11u1 installé"
}
skipping: [dns]

Youpi !

1 J'aime