Files
BaC/content/2022-09-08-ansible-et-la-génération-magique-de-variables.md
2025-02-27 12:52:48 +01:00

154 lines
6.4 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

+++
title = "Ansible et la génération magique de variables"
date = 2022-09-08
[taxonomies]
tags = [ "ansible", "système" ]
+++
> Ansible, cest de la merde.
*Schtroumpf grognon, 2022*
<!-- more -->
Je naime pas _Ansible_. Venant à lorigine de _SaltStack_, je le trouve hyper limité et étriqué dans sa façon de fonctionner: ne favorise pas vraiment la réutilisabilité, les variables sont toutes mises dans le même sac à la fin, accéder à nimporte quelle variable est hyper confus, il ny a pas de système de signaux permettant déchanger avec le serveur.
Sans compter le fait que même lexécution des modules de base inclus dans _Ansible_ nécessite parfois linstallation de la moitié de _pypi_.
Mais il a néamoins deux ou trois trucs pour lui: pas dagent (jai du mal à classer ça dans les avantages, mais dans certaines circonstances, ne pas avoir à se préoccuper de lagent, cest plutôt une bonne chose) et surtout une courbe dapprentissage nettement moins raide que _SaltStack_ (où tu rotes du sang régulièrement…).
Bref, laisse-moi te conter la mésaventure qui mest arrivé au détour dun _role_ _Ansible_
# Les données du problème
Admettons que jai un _role_ dont le but est de tester le retour dun _GET_ HTTP. On lui done une liste avec pour chaque entrée:
* lURI
* lURN
* le résultat attendu
Et ce _role_ se charge daller faire la requête _GET_ et de vérifier que le mot-clé est bien dans le résultat. Un truc plutôt basique.
Tu pourrais imaginer de faire un truc comme ça:
```yaml
test_http:
- uri: "https://blog.libertus.eu"
urn: "/ne-m-appelez-plus-prive"
result: "LOLILOL"
- uri: "https://www.elysee.fr"
urn: "/emmanuel-macron"
result: "connard"
```
Le _role_ va donc faire une boucle simple (probablement avec `loop`) sur le contenu de la variable `test_http` et renvoyer à chaque fois le résultat dun `assert`.
Jusquici tout va bien. Mais admettons que je doive générer cette liste. Elle nest plus bêtement statique, je dois la générer. Mettons par exemple que je veuille vérifier que lensemble des serveurs dans un groupe donné sont bien enregistrés dans un `consul` ou un système de gestions de parc ou nimporte quoi dautres.
# This is *SALTSTACK*!!
Côté _SaltStack_, il ny a pas de souci particulier: tous les fichiers sont interprétés en _Jinja_ avant dêtre interprétés en _Yaml_. On peut donc finalement _templater_ un peu nimporte où, cela ne pose jamais de problème.
Pour résoudre un problème de ce type, on aurait probablement faire qqch du genre:
```yaml
test_http:
{% for host in hosts %} # on admettra ici que la variable hosts contient ce quil faut
- uri: "http://consul.server"
urn: "/v1/catalog/nodes"
result: "{{ host }}"
{% endfor %}
```
Tout ceci dans un _pillar_ quelconque avec le _state_ qui va bien derrière, rien de bien compliqué en soi.
Le très gros avantage davoir du _Jinja_ à tous les étages, cest quon peut finalement _templater_ un peu nimporte quoi, un peu nimporte où sans trop se préoccuper. Cest ainsi quil nexiste pas vraiment déquivalent de `loop` dans _SaltStack_: on te dira toujours te de débrouiller pour faire la même chose en _Jinja_ et puis voilà.
# Le Chad _SaltStack_ / Le Virgin _Ansible_
Dans _Ansible_, on ne peut pas coller du _Jinja_ nimporte où. Lensemble des fichiers que manipulent _Ansible_ (à lexception du `ansible.cfg` et des fichiers dinventaire qui peuvent être en _INI_), tout doit être du pur _Yaml_.
Doù un certain nombre daberrations genre `loop` et la tétrachiée de `filters` quil faut se trimballer pour arriver à lutiliser (jetez juste un œil à [cette page](https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#migrating-from-with-x-to-loop) si vous voulez vous en convaincre…).
Mais, ça ne veut pas dire quon ne peut pas du tout utiliser des _templates_ _Jinja_. On peut, simplement, il faut les limiter aux variables.
Une première approche consisterait donc à tenter de produire un _template_ pour essayer de générer du _Yaml_:
```yaml
hosts:
- ta
- mere
- lol
test_http: |-
{% for host in hosts %}
- uri: "http://consul.server"
urn: "/v1/catalog/nodes"
result: "{{ host }}"
{% endfor %}
```
Sauf que quand on essaie dafficher cette variable, on obtient juste une chaîne de caractères:
```bash
TASK [display var] **********
ok: [localhost] => {
"msg": "- uri: \"http://consul.server\"\n urn: \"/v1/catalog/nodes\"\n result: \"ta\"\n- uri: \"http://consul.server\"\n urn: \"/v1/catalog/nodes\"\n result: \"mere\"\n- uri: \"http://consul.server\"\n urn: \"/v1/catalog/nodes\"\n result: \"lol\"\n"
}
```
**PERDU !**
Si on remet les retours chariot un peu dans lordre, on se rend pourtant bien compte quon a effectivement généré ce quil faut, mais visiblement, _Ansible_ na pas vraiment envie de sen servir.
En vrai, il y a un astuce… Il ne faut pas _templater_ du _Yaml_, il faut _templater_ du _JSON_. Oui, cest vraiment un truc de clown…
Donc en fait, si tu fais **exactement** la même chose mais avec cette syntaxe:
```yaml
hosts:
- ta
- mere
- lol
test_http: |-
[
{% for host in hosts %}
{
"uri": "http://consul.server",
"urn": "/v1/catalog/nodes",
"result": "{{ host }}"
},
{% endfor %}
]
```
Et là, le miracle saccomplit:
```bash
TASK [display var] *********
ok: [localhost] => {
"msg": [
{
"result": "ta",
"uri": "http://consul.server",
"urn": "/v1/catalog/nodes"
},
{
"result": "mere",
"uri": "http://consul.server",
"urn": "/v1/catalog/nodes"
},
{
"result": "lol",
"uri": "http://consul.server",
"urn": "/v1/catalog/nodes"
}
]
}
```
Mais attention, hein! Il ne faut surtout pas oublier la moindre virgule et en particulier celle qui se trouve en toute fin de variable `},`, sinon tout est de nouveau interprété comme une chaîne de caractères générée.
# Foutaises
Donc, oui, on peut génerer des variables dans _Ansible_ mais juste, cest tellement bordélique quon peut quand même se poser des questions de pourquoi, cest foutu comme ça. Générer une variable _Yaml_ en passant par du _JSON_ _templaté_ en _Jinja_, cest pas vraiment le truc le plus instinctif de la planète…