AnsibleVoici le quatorzième article de la formation Ansible. Dans mon précédent article, je vous ai présenté les variables enregistrées et les possibilités qu’elles offrent dans un playbook. Aujourd’hui, nous allons nous intéresser à deux autres types de variables dont nous allons nous servir assez régulièrement dans nos playbooks.

Atelier pratique

Placez-vous dans le répertoire du seizième atelier pratique :

$ cd ~/formation-ansible/atelier-16

Voici les quatre machines virtuelles de cet atelier :

Machine virtuelle Adresse IP
ansible 10.23.45.10
rocky 10.23.45.20
debian 10.23.45.30
suse 10.23.45.40

Démarrez les VM :

$ vagrant up

Connectez-vous au Control Host :

$ vagrant ssh ansible

L’environnement de cet atelier est préconfiguré et prêt à l’emploi :

  • Ansible est installé sur le Control Host.
  • Le fichier /etc/hosts du Control Host est correctement renseigné.
  • L’authentification par clé SSH est établie sur les trois Target Hosts.
  • Le répertoire du projet existe et contient une configuration de base et un inventaire.
  • Direnv est installé et activé pour le projet.
  • Le validateur de syntaxe yamllint est également disponible.

Rendez-vous dans le répertoire des playbooks :

$ cd ansible/projets/ema/playbooks/
direnv: loading ~/ansible/projets/ema/.envrc
direnv: export +ANSIBLE_CONFIG

Les facts et les variables implicites

Dans la configuration par défaut, Ansible va commencer par recueillir tout un tas d’informations diverses et variées sur les hôtes lorsque vous exécutez un playbook. Ce comportement est défini par le paramètre gather_facts, dont la valeur par défaut est true.

TASK [Gathering Facts] **************************************
ok: [debian]
ok: [suse]
ok: [rocky]

Toutes ces informations sont soigneusement rangées dans un dictionnaire ansible_facts et pourront être utilisées par la suite comme n’importe quelle série de variables.

Pour avoir une première idée des facts, exécutez la commande ad hoc suivante sur l’hôte debian :

$ ansible debian -m setup

Le résultat dépasse de loin la taille d’un écran. On va donc réitérer la commande comme ceci :

$ ansible debian -m setup | less

L’affichage des facts de notre hôte dépasse les 600 lignes :

$ ansible debian -m setup | wc -l
607

En mode ad hoc, les facts peuvent être filtrés. Voici par exemple toutes les infos relatives à la distribution :

$ ansible debian -m setup -a "filter=ansible_distribution*"
debian | SUCCESS => {
    "ansible_facts": {
        "ansible_distribution": "Debian",
        "ansible_distribution_file_parsed": true,
        "ansible_distribution_file_path": "/etc/os-release",
        "ansible_distribution_file_variety": "Debian",
        "ansible_distribution_major_version": "12",
        "ansible_distribution_minor_version": "4",
        "ansible_distribution_release": "bookworm",
        "ansible_distribution_version": "12"
    },
    "changed": false
}

Les informations affichées par le module setup peuvent nous induire en erreur. À titre d’exemple, jetez un œil à la clé ansible_architecture avec la valeur correspondante x86_64 :

$ ansible debian -m setup | head -n 12
debian | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "192.168.121.33",
            "10.23.45.30"
        ],
        "ansible_all_ipv6_addresses": [],
        "ansible_apparmor": {
            "status": "enabled"
        },
        "ansible_architecture": "x86_64",
        "ansible_bios_date": "04/01/2014",

Si vous voulez utiliser ces informations dans un playbook, vous serez probablement tentés d’écrire quelque chose comme ceci :

---  # facts1.yml

- hosts: debian

  tasks:

    - debug:
        var: ansible_facts.ansible_architecture

    - debug:  # alternative syntax
        var: ansible_facts['ansible_architecture']

...

Malheureusement, les deux variantes ne vous affichent qu’une valeur UNDEFINED :

TASK [debug] **********************************************************
ok: [debian] => {
    "ansible_facts.ansible_architecture": "VARIABLE IS NOT DEFINED!"
}

TASK [debug] **********************************************************
ok: [debian] => {
    "ansible_facts['ansible_architecture']": "VARIABLE IS NOT DEFINED!"
}

Essayez plutôt ceci :

---  # facts2.yml

- hosts: debian

  tasks:

    - debug:
        var: ansible_facts.architecture

    - debug:  # alternative syntax 1
        var: ansible_facts['architecture']

    - debug:  # alternative syntax 2
        var: ansible_architecture

...

Voici ce que ça donne :

TASK [debug] ********************************
ok: [debian] => {
    "ansible_facts.architecture": "x86_64"
}

TASK [debug] ********************************
ok: [debian] => {
    "ansible_facts['architecture']": "x86_64"
}

TASK [debug] ********************************
ok: [debian] => {
    "ansible_architecture": "x86_64"
}

Essayons de tirer une première conclusion :

  • Lorsque vous utilisez des facts dans le dictionnaire ansible_facts, vous devez impérativement écrire la clé de premier niveau sans le préfixe ansible_.
  • Les clés de premier niveau sont également disponibles sous forme de variable directe avec le préfixe ansible_.

En dehors des facts, vous avez également les variables implicites (magic vars) qui sont toujours disponibles :

  • inventory_hostname : le nom de l’hôte dans l’inventaire
  • playbook_dir : répertoire dans lequel se trouve le playbook en cours
  • inventory_dir : répertoire dans lequel se trouve l’inventaire
  • etc.

Le meilleur moyen pour assimiler tout ce joyeux mélange de facts et de variables implicites, c’est de les utiliser dans des petits playbooks. C’est ce que nous allons faire. Commençons par afficher quelques infos sur les distributions Linux utilisées sur nos systèmes :

---  # distribution-info.yml

- hosts: all

  tasks:

    - name: Display distribution information
      debug:
        msg: >-
          Host [{{inventory_hostname}}] is running {{ansible_distribution}}
          version {{ansible_distribution_version}}
          (family {{ansible_distribution_file_variety}}).

...

Résultat :

TASK [Display distribution information] *************************************
ok: [rocky] => {
    "msg": "Host [rocky] is running Rocky version 9.3 (family RedHat)."
}
ok: [debian] => {
    "msg": "Host [debian] is running Debian version 12 (family Debian)."
}
ok: [suse] => {
    "msg": "Host [suse] is running openSUSE Leap version 15.5 (family SUSE)."
}

Ici on utilise deux variables implicites (magic vars) pour afficher les informations sur l’emplacement du playbook et de l’inventaire :

---  # playbook-info.yml

- hosts: all

  tasks:

    - name: Playbook information
      debug:
        msg: Your playbook is in {{playbook_dir}}.
      run_once: true

    - name: Inventory information
      debug:
        msg: Your inventory is in {{inventory_dir}}.
      run_once: true

...

Le paramètre run_once évite que la tâche ne soit répétée pour chaque système cible, ce qui n’aurait pas de sens ici :

TASK [Playbook information] *************************************************
ok: [rocky] => {
    "msg": "Your playbook is in /home/vagrant/ansible/projets/ema/playbooks."
}

TASK [Inventory information] ************************************************
ok: [rocky] => {
    "msg": "Your inventory is in /home/vagrant/ansible/projets/ema."
}

Voici un playbook qui affiche simplement la liste de tous les Target Hosts :

---  # hosts-info.yml

- hosts: all

  tasks:

    - name: Display host information
      debug:
        msg: "Your hosts are: {{groups.all}}"
      run_once: true

...

Résultat :

TASK [Display host information] ************************
ok: [rocky] => {
    "msg": "Your hosts are: ['rocky', 'debian', 'suse']"
}

Enfin, on va afficher les adresses IPv4 de chacun de nos systèmes cible :

---  # ip-info.yml

- hosts: all

  tasks:

    - name: Display IPv4 addresses
      debug:
        msg: "{{ansible_host}}'s IPv4 addresses: {{ansible_all_ipv4_addresses}}"

...

Résultat :

TASK [Display IPv4 addresses] ****************************************
ok: [rocky] => {
    "msg": "rocky's IPv4 addresses: ['10.23.45.20', '192.168.121.82']"
}
ok: [debian] => {
    "msg": "debian's IPv4 addresses: ['192.168.121.33', '10.23.45.30']"
}
ok: [suse] => {
    "msg": "suse's IPv4 addresses: ['10.23.45.40', '192.168.121.109']"
}

Exercice

Écrivez trois playbooks pour afficher des informations sur chacun des Target Hosts :

  • pkg-info.yml pour afficher le gestionnaire de paquets utilisé
  • python-info.yml pour afficher la version de Python installée
  • dns-info.yml pour afficher le(s) serveur(s) DNS utilisé(s)

Quittez le Control Host :

$ exit

Supprimez toutes les VM :

$ vagrant destroy -f

Lire la suite : Cibles hétérogènes


La rédaction de cette documentation demande du temps et des quantités significatives de café espresso. Vous appréciez ce blog ? Offrez un café au rédacteur en cliquant sur la tasse.

 

Catégories : Formation

0 commentaire

Laisser un commentaire

Emplacement de l’avatar

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *