Les facts Ansible đŸ±â€đŸ

Si vous avez dĂ©jĂ  eu l'occasion de lancer un playbook Ansible, vous avez dĂ©jĂ  sĂ»rement dĂ» remarquer, lors de son exĂ©cution, que la premiĂšre tĂąche qui est rĂ©alisĂ©e par celui-ci n'est pas une tĂąche que vous lui avez ordonnĂ©. đŸ€Šâ€â™‚ïž

Mais alors, à quoi ça lui sert à Ansible de récupérer les informations de notre machine avant d'appliquer notre playbook?

Eh bien, c'est tout simple, ces informations sont rĂ©cupĂ©rĂ©es, dans le but de pouvoir Ă©ventuellement ĂȘtre appelĂ©e dans notre playbook par la suite via des variables "magiques" ansible_*.

Je vous conseil, dans le cas oĂč vous ne souhaitez justement pas utiliser des informations provenant des facts 😒, de dĂ©clarer la configuration suivante dans votre playbook:

---
- name: print out operating system
  hosts: all
  gather_facts: no

La tùche [Gathering Facts], qui ne fait à premiÚre vue rien, correspond en réalité à la connexion à la ou les différentes machines sur lesquelles seront exécutées les playbooks.

A noter que dans le cas oĂč la connexion Ă©choue, le playbook Ă©chouera sur cette cible, et continuera Ă©ventuellement sur les autres machines.

Enfin, si l'hÎte répond, alors Ansible en profite pour récupérer un nombre incalculable d'informations en rapport direct avec cette/ces machine(s) et les stockents dans une variable citée plus haut.

Sinon, quelle tronche ça a ? 😎

Il est possible d'utiliser le module "setup", le mĂȘme module qui est appelĂ© lors de l'Ă©tape [Gathering facts], pour afficher les donnĂ©es rĂ©cupĂ©rer!

Vous obtiendrez un magnifique retour au format JSON, ce qui n'est pas forcément trÚs digeste. Mais avec jq, vous pouvez facilement traiter le résultat.

Pour l'exemple:

ansible vps -m setup
srv | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
...

J'ai pas mis la totalitĂ© par que 587 lignes... C'est encore moins digeste. Il y a une quantitĂ© d'informations disponible extrĂȘmement impressionnante.

Certaines informations sont superbes pour alimenter sa CMDB.😉Vous n'avez plus d'excuse!

Et je fais quoi de tout ça ? đŸ€·â€â™‚ïž

Parce qu'il n'y a rien de mieux que l'explication par l'exemple, que je vais ainsi vous montrer différentes astuces utilisables pour récupérer des informations.

Quelle distrib' ? 🙌

# Récupérer des informmations sur la distrib'
ansible vps -m setup -a 'filter=ansible_distribution*'
srv | 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": "10",
        "ansible_distribution_release": "buster",
        "ansible_distribution_version": "10",
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false
}

# Récupérer la famille de distrib'
ansible vps -m setup -a 'filter=ansible_os_family*'
srv | SUCCESS => {
    "ansible_facts": {
        "ansible_os_family": "Debian",
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false
}

Comme vous pouvez le constater, j'ai spécifier l'option -a pour pouvoir utiliser un filtrer sur le résultat (sans avoir à utiliser un utilitaire comme jq dans un pipe).

Les facts sont vraiment trĂšs puissant pour alimenter un inventaire de nos machines, qui plus est, Ă  jour!

De beaux rapports HTML 😎

Dans certains cas, il peut ĂȘtre intĂ©ressant d'utiliser le systĂšme de template Jinja2 qu'intĂšgre Ansible.

Par exemple, on peut obtenir le résultat suivant:

En ayant ainsi configuré la chose de la maniÚre suivante:

    - name: "Generate HTML report"
      template:
        src: templates/html-report.html.j2
        dest: "$HOME/{{ inventory_hostname }}.html"
playbook.yml

Au niveau du template Jinja2:

<!DOCTYPE html>
<html lang=en>
    <head>
        <title>Integration report of {{ inventory_hostname }}</title>

        <!-- Required meta tags -->
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

        <!-- Material Design for Bootstrap fonts and icons -->
        <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons">

        <!-- Material Design for Bootstrap CSS -->
        <link rel="stylesheet" href="https://unpkg.com/bootstrap-material-design@4.1.1/dist/css/bootstrap-material-design.min.css" integrity="sha384-wXznGJNEXNG1NFsbm0ugrLFMQPWswR3lds2VeinahP8N0zJw9VWSopbjv2x7WCvX" crossorigin="anonymous">

        <!-- jQuery first, then Popper.js, then Bootstrap JS -->
        <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
        <script src="https://unpkg.com/popper.js@1.12.6/dist/umd/popper.js" integrity="sha384-fA23ZRQ3G/J53mElWqVJEGJzU0sTs+SvzG8fXVWP+kJQ1lwFAOkcUOysnlKJC33U" crossorigin="anonymous"></script>
        <script src="https://unpkg.com/bootstrap-material-design@4.1.1/dist/js/bootstrap-material-design.js" integrity="sha384-CauSuKpEqAFajSpkdjv3z9t8E7RlpJ1UP0lKM/+NdtSarroVKu069AlsRPKkFBz9" crossorigin="anonymous"></script>
        <script>$(document).ready(function() { $('body').bootstrapMaterialDesign(); });</script>
    </head>
    <body>
        <nav class="navbar navbar-dark bg-primary">
            <!-- Navbar content -->
            <a class="navbar-brand" href="#">Report of: <b>{{ inventory_hostname }}</b></a>
          </nav>
        <ul>
            <br>
            <li>Interfaces : {{ ansible_default_ipv4.alias }}</li>
            <li>Architecture : {{ ansible_architecture }}</li>
            <li>OS : {{ ansible_distribution }} {{ ansible_distribution_major_version }} {{ ansible_distribution_release }}</li>
            <li>Node name: {{ ansible_nodename }}</li>
        </ul>
    </body>
    <footer>
    </footer>
</html>
html-report.html.j2

Comme vous pouvez le constater, les facts sont super pratiques. On peut pousser le vis encore plus loins.

En effet, par exemple, dans le playbook suivant:

    - name: Specific configuration for Debian Only
      lineinfile:
        path: /etc/apt/apt.conf.d/50unattended-upgrades
        backup: yes
        create: yes
        state: present
        regexp: "{{ item.line }}"
        line: "{{ item.new }}"

      loop:
        - {
            line: '^(//)?      "o=Debian(,a=stable)?"',
            new: '      "o=Debian"',
          }
      when: ansible_distribution == 'Debian'
playbook.yml

Nous avons la configuration:

when: ansible_distribution == 'Debian'

Ainsi, nous pourrons donc appliquer la configuration que lorsque le fact ansible_distribution est à Debian. Ainsi, la configuration ne sera appliqué que lorsque la machine est une machine Debian (Nannnnn sans déconner...).

Vous voyez donc ainsi le nombre incalculable de possibilités avec ces facts.

Bien entendu, il est possible d'en faire bien plus avec tout ça, mais le but de cet article est d'expliquer simplement ce que sont les facts Ansible.

Tout ça avec des exemples, pour moi, la compréhension passe en grande partie par l'exemple.