Aller au contenu principal

Les filtres Ansible - 2ème partie

· 3 minutes de lecture
Stéphane ROBERT
Consultant DevOps

Json est le format de données utiliser par les Api Rest. Nous allons voir comment utiliser le filtre json_query pour rechercher des éléments dans une variable JSON. json_query utilise jmespath, un langage de requête pour analyser des contenu au format JSON.

Par exemple si vous utilisez Ansible pour manager des clusters kubernetes vous serez obligé de parser des données au format JSON.

Transformer des variables au format json

Avant de voir comment récupérer des données d'une API. Voyons comment transformer une variable en json. Vous avez deux filtres votre disposition to_json et to_nice_json.

---
- hosts: localhost
  vars:
    apps:
      - name: app1
        jvm: &jvm_opts
          opts: '-Xms1G -Xmx2G'
          port: 1000
          path: /usr/lib/app1
      - name: app2
        jvm:
          <<: *jvm_opts
          path: /usr/lib/app2

  tasks:
    - name: to_json
      debug:
        msg: "{{ apps | to_json }}"

    - name: to_nice_json
      debug:
        msg: "{{ apps | to_nice_json(indent=2) }}"

Ici une astuce permettant à app1 et app2 de partager les mêmes valeurs pour opts et port. On utilise l'ancre &jvm_opts et l'alias *jvm_opts. La valeur du chemin est fusionnée par <<.

Exemples de données au format JSON

Nous allons utiliser comme exemple les données du site jsonplaceholder. Nous prendrons les données du schéma users:

[
  {
    "id": 1,
    "name": "Leanne Graham",
    "username": "Bret",
    "email": "Sincere@april.biz",
    "address": {
      "street": "Kulas Light",
      "suite": "Apt. 556",
      "city": "Gwenborough",
      "zipcode": "92998-3874",
      "geo": {
        "lat": "-37.3159",
        "lng": "81.1496"
      }
    },
    "phone": "1-770-736-8031 x56442",
    "website": "hildegard.org",
    "company": {
      "name": "Romaguera-Crona",
      "catchPhrase": "Multi-layered client-server neural-net",
      "bs": "harness real-time e-markets"
    }
  },
  ...
]

Pour récupérer les données nous allons utiliser le bon vieux module uri

---
 - name: Parse json
   hosts: localhost
   gather_facts: no
   tasks:
     - name: Obtention des users
       uri:
         url: https://jsonplaceholder.typicode.com/users
         return_content: yes
       register: jsondata
     - name: Business Card
       debug:
          msg: "{{ jsondata.json }}"

Extraire un champ particulier d'un json

Nous aimerions par exemple obtenir la liste de tous users de la liste. Pour cela nous allons utiliser une requete jmespath. Il faut dans un premier temps installer le module pip correspondant :

pip install jmespath --user

Maintenant transformons notre playbook en intégrant un vars à notre debug:

---
- name: Parse json
  hosts: localhost
  gather_facts: no
  tasks:
    - name: Obtention des users
      uri:
        url: https://jsonplaceholder.typicode.com/users
        return_content: yes
      register: jsondata
    - name: Business Card
      vars:
        jmesquery: "[*].{Name: name}"
      debug:
        msg: "{{ jsondata.json  | json_query(jmesquery) }}"

Retrouver une donnée particulière

Cette fois nous aimerions retrouver un user en particulier, par exemple celui avec l'id 1. Faites bien attention au format des quotes `

---
- name: Parse json
  hosts: localhost
  gather_facts: no
  tasks:
    - name: Obtention des users
      uri:
        url: https://jsonplaceholder.typicode.com/users
        return_content: yes
      register: jsondata
    - name: Business Card
      vars:
        jmesquery: "[? id==`1`]"
      debug:
        msg: "{{ jsondata.json  | json_query(jmesquery) }}"

Il est possible d'ajouter des ou et et pour sélectionner d'autres users. Ici nous allons demander à afficher seulement le nom de leur company:

    - name: Business Card
      vars:
        jmesquery: "[? id==`1` ||  id==`5`].{Company: company.name}"
      debug:
        msg: "{{ jsondata.json  | json_query(jmesquery) }}"

Utiliser combine pour créer ses propres données extraites du json

Plus tot nous avions vu l'utilisation de combine permettant de combiner des données. Nous allons ici extraire le nom et l'associer à son email :

    - name: user - Email
      set_fact:
        my_data: "{{my_data|default({}) | combine ( {item.name : item.email}) }}"
      with_items: "{{ jsondata.json | json_query('[? id==`1` || id==`5`]')}}"
    - name: debug
      debug:
        msg: "{{my_data}}"

Si vous voulez plus de tutorials Ansible je vous renvoie sur le billet de l'introduction à ansible