Aller au contenu

Les filtres Ansible - 2ème partie

logo

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 :

Terminal window
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