« Ansible : Quirks » : différence entre les versions
(Page créée avec « = Variables Utiles & Quirks divers= Ansible contient des variable globales assez utiles. Il contient également beaucoup de fonctions particulières et part un peu dans to... ») |
Aucun résumé des modifications |
||
(16 versions intermédiaires par la même utilisatrice non affichées) | |||
Ligne 1 : | Ligne 1 : | ||
[[Category:Ansible]] | |||
= Variables Utiles & Quirks divers= | = Variables Utiles & Quirks divers= | ||
Ansible contient des variable globales assez utiles. Il contient également beaucoup de fonctions particulières et part un peu dans tous les sens; cependant, on trouve toujours réponse à ses problèmes. | Ansible contient des variable globales assez utiles. Il contient également beaucoup de fonctions particulières et part un peu dans tous les sens; cependant, on trouve toujours réponse à ses problèmes. | ||
Ligne 5 : | Ligne 6 : | ||
Ajouter dans la partie [group:vars]: | Ajouter dans la partie [group:vars]: | ||
ansible_ssh_common_args='-o StrictHostKeyChecking=no' | ansible_ssh_common_args='-o StrictHostKeyChecking=no' | ||
== Sudo no password pose problème == | |||
Quand il est utilisé avec un user nopassword, ansible nous casse les pieds quand il faut faire du sudo. | |||
Il faut ajouter la conf suivante dans ansible.cfg: | |||
[defaults] | |||
sudo_flags=-H -S | |||
==Des caractères spéciaux dans les mots de passe== | ==Des caractères spéciaux dans les mots de passe== | ||
Ligne 71 : | Ligne 80 : | ||
... | ... | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== tag spécial === | |||
Il existe un tags spécial : always. Placer ce tag fait en sorte que l'élément associé sera toujours exécuté. | |||
== Accéder à la documentation == | |||
La documentation est intégrée ! Il suffit d'utiliser Ansible-doc : | |||
<syntaxhighlight lang='bash'> | |||
[justine@argonaut filetree]$ ansible-doc --help | |||
Usage: ansible-doc [-l|-F|-s] [options] [-t <plugin type> ] [plugin] | |||
plugin documentation tool | |||
Options: | |||
-h, --help show this help message and exit | |||
-j, --json **For internal testing only** Dump json metadata for | |||
all plugins. | |||
-l, --list List available plugins | |||
-F, --list_files Show plugin names and their source files without | |||
summaries (implies --list) | |||
-M MODULE_PATH, --module-path=MODULE_PATH | |||
prepend colon-separated path(s) to module library (def | |||
ault=~/.ansible/plugins/modules:/usr/share/ansible/plu | |||
gins/modules) | |||
-s, --snippet Show playbook snippet for specified plugin(s) | |||
-t TYPE, --type=TYPE Choose which plugin type (defaults to module). | |||
Available plugin types are : ('become', 'cache', | |||
'callback', 'cliconf', 'connection', 'httpapi', | |||
'inventory', 'lookup', 'shell', 'module', 'strategy', | |||
'vars') | |||
-v, --verbose verbose mode (-vvv for more, -vvvv to enable | |||
connection debugging) | |||
--version show program's version number, config file location, | |||
configured module search path, module location, | |||
executable location and exit | |||
See man pages for Ansible CLI options or website for tutorials | |||
https://docs.ansible.com | |||
</syntaxhighlight> | |||
== Le module find == | |||
Le module find est un peu casse-pieds. Il si je le register dans "fichiers", alors ma variable fichiers contiendra une liste appellée "files" (et d'autres : cf la doc), laquelle sera une liste de collection clefs-valeurs : | |||
<syntaxhighlight lang="yaml"> | |||
[ | |||
{ path: "/var/tmp/test1", | |||
mode: "0644", | |||
"...": "...", | |||
checksum: 16fac7be61a6e4591a33ef4b729c5c3302307523 | |||
}, | |||
{ path: "/var/tmp/test2", | |||
"...": "..." | |||
}, | |||
] | |||
</syntaxhighlight> | |||
Y accéder est un peu embêtant. Mettons que j'ai besoin d'accéder au path, je peux faire ça : | |||
<syntaxhighlight lang='yaml'> | |||
--- | |||
- hosts: all | |||
become: true | |||
tasks: | |||
- name: Récupérer les fichiers | |||
find: | |||
patterns: "*log" | |||
paths: /var/log | |||
recurse: yes | |||
register: fichiers | |||
- name: debuggage | |||
debug: | |||
msg: "{{ item.path }}" | |||
with_items: "{{ fichiers.files }}" | |||
</syntaxhighlight> | |||
Mais bon, ce n'est pas génial... Ici, on doit faire une itération sur la liste et extraire les paths à chaque fois. | |||
On peut aussi utiliser un filtre Jinja2: | |||
<syntaxhighlight lang='yaml'> | |||
--- | |||
- hosts: all | |||
become: true | |||
tasks: | |||
- name: Récupérer les fichiers | |||
find: | |||
patterns: "*log" | |||
paths: /var/log | |||
recurse: yes | |||
register: fichiers | |||
- name: debuggage | |||
debug: | |||
msg: "{{ fichiers['files'] | map(attribute='path') | list }}" | |||
</syntaxhighlight> | |||
Cette fois-ci, on a une liste de tous les paths. Mais bon, ce n'est pas génial non plus. Si j'avais des listes dans des listes, je devrais utiliser with_nested. | |||
== Assigner des variables au milieu d'un playbook == | |||
Pour cela, il faut utiliser le module set_fact. En reprenant l'exemple juste avant : | |||
<syntaxhighlight lang='yaml'> | |||
--- | |||
- hosts: all | |||
become: true | |||
tasks: | |||
- name: Récupérer les fichiers | |||
find: | |||
patterns: "*log" | |||
paths: /var/log | |||
recurse: yes | |||
register: fichiers | |||
- name: Une nouvelle variable | |||
set_fact: | |||
chemins: "{{ fichiers['files'] | map(attribute='path') | list }}" | |||
- name: debuggage | |||
debug: | |||
msg: "{{ chemins }}" | |||
</syntaxhighlight> | |||
== Register les sorties de tasks == | |||
On capturer les sorties de tâches avec register. Non seulement ça marche de façon particulière avec certains modules comme find (qui renvoient un truc bien précis à ce moment là), mais il faut savoir que *tous* les modules renvoient quelque chose. | |||
<syntaxhighlight lang='yaml'> | |||
- hosts: all | |||
tasks: | |||
- name: Ansible register with_items example | |||
shell: "find *.txt" | |||
args: | |||
chdir: "/Users/mdtutorials2/Documents/Ansible" | |||
register: with_output | |||
- shell: "cp {{ item }} {{item}}_bkp" | |||
with_items: | |||
- "{{ with_output.stdout_lines }}" | |||
#Ici, on s'en sert pour itérer sur la sortie de la commande shell envoyée. | |||
</syntaxhighlight> | |||
Chaque module fait son retour comme il veut; mais les retours sont en général des ensembles de valeurs auxquelles on peut accéder. Par exemple : | |||
<syntaxhighlight lang='yaml'> | |||
- name: shellcode | |||
shell: echo hi | |||
register: hello | |||
changed_when: false | |||
- name: debuggage | |||
debug: | |||
var: hello | |||
</syntaxhighlight> | |||
Renvoie ça : | |||
<syntaxhighlight lang="yaml"> | |||
ok: [localhost] => { | |||
"hello": { | |||
"changed": false, | |||
"cmd": "echo hi", | |||
"delta": "0:00:00.001968", | |||
"end": "2019-10-01 23:58:28.548570", | |||
"failed": false, | |||
"rc": 0, | |||
"start": "2019-10-01 23:58:28.546602", | |||
"stderr": "", | |||
"stderr_lines": [], | |||
"stdout": "hi", | |||
"stdout_lines": [ | |||
"hi" | |||
] | |||
} | |||
} | |||
</syntaxhighlight> | |||
Je peux accéder au return code avec hello.rc : | |||
<syntaxhighlight lang="yaml"> | |||
TASK [debug2] ********************************************************************************** | |||
ok: [localhost] => { | |||
"hello.rc": "0" | |||
} | |||
</syntaxhighlight> | |||
== Gestion de la réentrance (idempotence) == | |||
=== Args : Creates === | |||
Utile dans l'utilisation de modules comme command, ou shell. Ces modules peuvent prendre des arguments avec "args:"; l'argument "creates" sert à préciser ce qu'une commande créée sur la machine. Ça sert à garder l'idempotence : Si ma commande est sensée créer un fichier mais que ce fichier existe déjà, elle ne relancera pas la commande. | |||
Attention : ça ne semble pas fonctionner avec raw. Super. Raw ne prend quasiment pas d'arguments, à part le choix de shell; il faut donc bien les construire. | |||
<syntaxhighlight lang='yaml'> | |||
--- | |||
- hosts: all | |||
become: true | |||
tasks: | |||
- name: Création de fichier | |||
command: dnf install python -y | |||
args: | |||
creates: "/usr/bin/python" | |||
</syntaxhighlight> | |||
=== Args: changed_when / failed_when=== | |||
Les modules shell ou command ne sont pas géniaux pour gérer la réentrée. Cependant, on peut leur indiquer quand ce qu'ils font est un changement ou pas (afin d'afficher "changed" ou "ok". Pour ça, on a un autre argument : changed_when. On a aussi failed_when, qui fonctionne sur le même principe. Dans tous les cas, il faut faire un register sur le retour de module. | |||
Déjà, on peut annuler complètement les "changed" (si on sait ce qu'on fait) avec false: | |||
<syntaxhighlight lang="yaml"> | |||
tasks: | |||
- shell: /usr/bin/billybass --mode="take me to the river" | |||
register: bass_result | |||
changed_when: "bass_result.rc != 2" | |||
# this will never report 'changed' status | |||
- shell: wall 'beep' | |||
changed_when: False | |||
</syntaxhighlight> | |||
On peut aussi annuler le change à certains conditions, principalement du texte dans la sortie standard / d'erreur : | |||
<syntaxhighlight lang="yaml"> | |||
- name: Une commande | |||
shell: /usr/bin/something | |||
register: _ | |||
changed_when: '"truc" in _.stdout.lower()' | |||
- name: example of many failed_when conditions with OR | |||
shell: "./myBinary" | |||
register: ret | |||
failed_when: > | |||
("No such file or directory" in ret.stdout) or | |||
(ret.stderr != '') or | |||
(ret.rc == 10) | |||
</syntaxhighlight> | |||
== De longues variables == | |||
Le linter d'Ansible 'naime pas les lignes de plus de 120 caractères. Quand on a une longue variable, on peut utiliser diverses méthodes. | |||
[ Voir : https://adminswerk.de/multi-line-string-yaml-ansible-I/ ] | |||
<nowiki> | |||
> | " ' >- >+ |- |+ | |||
-------------------------|------|-----|-----|-----|------|------|------|------ | |||
Trailing spaces | Kept | Kept | | | | Kept | Kept | Kept | Kept | |||
Single newline => | _ | \n | _ | _ | _ | _ | _ | \n | \n | |||
Double newline => | \n | \n\n | \n | \n | \n | \n | \n | \n\n | \n\n | |||
Final newline => | \n | \n | | | | | \n | | \n | |||
Final dbl nl's => | | | | | | | Kept | | Kept | |||
In-line newlines | No | No | No | \n | No | No | No | No | No | |||
Spaceless newlines| No | No | No | \ | No | No | No | No | No | |||
Single quote | ' | ' | ' | ' | '' | ' | ' | ' | ' | |||
Double quote | " | " | " | \" | " | " | " | " | " | |||
Backslash | \ | \ | \ | \\ | \ | \ | \ | \ | \ | |||
" #", ": " | Ok | Ok | No | Ok | Ok | Ok | Ok | Ok | Ok | |||
Can start on same | No | No | Yes | Yes | Yes | No | No | No | No | |||
line as key | | |||
</nowiki> | |||
Et pour avoir une longue variable sur plusieurs lignes, sans espaces ni RIEN de rajoutés, il faut juste échapper l'espace et utiliser des doubles quotes: | |||
<syntaxhighlight lang="yaml"> | |||
variable: "abcdef\ | |||
ghijkl" | |||
</syntaxhighlight> | |||
== Boucler sur une liste + agir de façon conditionnelle (loop, when) == | |||
Voir aussi : https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html#loops-and-conditionals | |||
Ci-dessous, un exemple de boucle avec loop + une condition: | |||
<syntaxhighlight lang='yaml'> | |||
- name: Ouverture ports | |||
firewalld: | |||
port: "{{ item }}" | |||
permanent: yes | |||
state: enabled | |||
loop: "{{ fwports }}" | |||
when: fwports is defined | |||
</syntaxhighlight> | |||
Ici, fwports est une liste définie comme ceci dans mon inventaire : | |||
fwports='["80/tcp", "443/tcp"]' | |||
== Lookups == | |||
Les lookups permettent d'aller chercher des trucs. | |||
<syntaxhighlight lang="yaml"> | |||
- hosts: all | |||
vars: | |||
contents: "{{ lookup('file', '/etc/foo.txt') }}" | |||
tasks: | |||
- debug: msg="the value of foo.txt is {{ contents }}" | |||
</syntaxhighlight> | |||
= Rebond SSH = | |||
Dans une configuration réseau en mode Bastion, on peut avoir besoin de faire un rebond pour accéder à nos machines. Dans ce cas, cela demande un peu de configuration (mais rien de compliqué). Ici, les machines du groupe "safe" ne sont accessible que par la machine "gate", qui n'accepte les connexions SSH que sur son port 220 (le port 22 étant pris par, par exemple, un EndleSSH :D ). | |||
<source> | |||
[safe] | |||
foo.example.xyz | |||
bar.example.xyz | |||
baz.example.xyz | |||
[safe:vars] | |||
ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ProxyCommand="ssh -W %h:%p -q gate.example.xyz -p 220"' | |||
</source> | |||
= Rendre un argument optionnel avec default(omit) = | |||
Dans le cas suivant: | |||
<nowiki> | |||
- name: Start the container | |||
community.docker.docker_container: | |||
name: "{{ container_name }}" | |||
image: "{{ image_name }}:{{ image_tag | default(latest) }}" | |||
ports: "{{ container_ports | default(omit) }}" | |||
[...] | |||
</nowiki> | |||
...en ce qui concerne l'argument "ports", on veut que celui-ci ne soit présenté au module docker que si la variable "container_ports" existe. C'est ce que signifie default(omit) : soit ma variable existe et l'argument ports est présenté, soit elle n'existe pas et l'argument n'est pas présenté. C'est vraiment utile pour améliorer la modularité des playbooks ! | |||
= Un if/else = | |||
* https://www.redhat.com/sysadmin/ansible-coding-programming | |||
Apparement, Jinja permet de faire des if/else, mais j'ai l'impression que ça ne peut se faire que sur de l'attribuation de variables (grâce à Jinja). | |||
<nowiki> | |||
--- | |||
- name: Jinja2 IF | |||
hosts: localhost | |||
vars: | |||
change_provided: True | |||
job_name: death_star | |||
change_string: destroy | |||
current_date_time: 1977-01-01 | |||
tasks: | |||
- name: Set base schedule name | |||
ansible.builtin.set_fact: | |||
base_schedule_name: "{%- if (change_provided | bool) -%} | |||
{{ job_name }}_{{ change_string }} | |||
{%- else -%} | |||
{{ job_name }}_{{ current_date_time }} | |||
{%- endif -%}" | |||
- name: Show value | |||
ansible.builtin.debug: | |||
msg: "{{ base_schedule_name }}" | |||
</nowiki> | |||
Je remets l'explication issue de l'article: | |||
* The {% and %} are delimiters indicating a Jinja2 code. In this case, there are extra - marks to indicate to Jinja2 that I want to remove the space characters I have before the variables (the spaces are only for aesthetics). | |||
* If change_provided is true, I combine job_name with the underscore and change_string. Only this content is assigned, and any spaces before or after the variables are omitted because I previously used {%- and -%}. | |||
* The else statement is similar to what you might know from other languages. In this case, I combine job_name with an underscore and current_date_time. | |||
* Finally, the endif closes the if. |
Dernière version du 13 septembre 2022 à 12:14
Variables Utiles & Quirks divers
Ansible contient des variable globales assez utiles. Il contient également beaucoup de fonctions particulières et part un peu dans tous les sens; cependant, on trouve toujours réponse à ses problèmes.
Ne pas avoir à ajouter l'hôte au fichier known_hosts
Ajouter dans la partie [group:vars]:
ansible_ssh_common_args='-o StrictHostKeyChecking=no'
Sudo no password pose problème
Quand il est utilisé avec un user nopassword, ansible nous casse les pieds quand il faut faire du sudo. Il faut ajouter la conf suivante dans ansible.cfg:
[defaults] sudo_flags=-H -S
Des caractères spéciaux dans les mots de passe
En cas d'utilisation d'un fichier d'inventaire chiffré contenant des mots de passe, il faut que ceux-ci soient entre simples quotes afin d'éviter que les caractères spéciaux comme $ ne soient interprétés.
blocks
- name: Attempt and graceful roll back demo block: - debug: msg: 'I execute normally' - name: i force a failure command: /bin/false - debug: msg: 'I never execute, due to the above task failing, :-(' rescue: - debug: msg: 'I caught an error' - name: i force a failure in middle of recovery! >:-) command: /bin/false - debug: msg: 'I also never execute :-(' always: - debug: msg: "This always executes"
tags
Il est possible de taguer des tâches afin de "faire du tri". Le but est de pouvoir choisir de n'exécuter par exemple que certains tags (avec --tags), ou de les éviter (avec --skip-tags). Ajouter des tags sur des tâches individuelles est assez simple :
<syntaxhighlight lang='yaml'> tasks: - yum:
name: "Modèle:Item" state: present loop: - httpd - memcached tags: - packages
- template:
src: templates/src.j2 dest: /etc/foo.conf tags: - configuration
</syntaxhighlight>
Bien entendu, on peut appliquer le même tag à plusieurs tâches.
Héritage des tags
L'héritage de tags, c'est le fait d'ajouter à un play, des tâches importées, ou autre... des tags qui seront appliqués à toutes les tâches incluses. Cela se fait avec la syntaxe "tags: " :
<syntaxhighlight lang='yaml'> - hosts: all
tags: - bar tasks: ...
- hosts: all
tags: [ foo ] tasks: ...
</syntaxhighlight>
tag spécial
Il existe un tags spécial : always. Placer ce tag fait en sorte que l'élément associé sera toujours exécuté.
Accéder à la documentation
La documentation est intégrée ! Il suffit d'utiliser Ansible-doc :
<syntaxhighlight lang='bash'> [justine@argonaut filetree]$ ansible-doc --help Usage: ansible-doc [-l|-F|-s] [options] [-t <plugin type> ] [plugin]
plugin documentation tool
Options:
-h, --help show this help message and exit -j, --json **For internal testing only** Dump json metadata for all plugins. -l, --list List available plugins -F, --list_files Show plugin names and their source files without summaries (implies --list) -M MODULE_PATH, --module-path=MODULE_PATH prepend colon-separated path(s) to module library (def ault=~/.ansible/plugins/modules:/usr/share/ansible/plu gins/modules) -s, --snippet Show playbook snippet for specified plugin(s) -t TYPE, --type=TYPE Choose which plugin type (defaults to module). Available plugin types are : ('become', 'cache', 'callback', 'cliconf', 'connection', 'httpapi', 'inventory', 'lookup', 'shell', 'module', 'strategy', 'vars') -v, --verbose verbose mode (-vvv for more, -vvvv to enable connection debugging) --version show program's version number, config file location, configured module search path, module location, executable location and exit
See man pages for Ansible CLI options or website for tutorials https://docs.ansible.com </syntaxhighlight>
Le module find
Le module find est un peu casse-pieds. Il si je le register dans "fichiers", alors ma variable fichiers contiendra une liste appellée "files" (et d'autres : cf la doc), laquelle sera une liste de collection clefs-valeurs :
<syntaxhighlight lang="yaml">
[ { path: "/var/tmp/test1", mode: "0644", "...": "...", checksum: 16fac7be61a6e4591a33ef4b729c5c3302307523 }, { path: "/var/tmp/test2", "...": "..." }, ]
</syntaxhighlight>
Y accéder est un peu embêtant. Mettons que j'ai besoin d'accéder au path, je peux faire ça :
<syntaxhighlight lang='yaml'> --- - hosts: all
become: true tasks:
- name: Récupérer les fichiers find: patterns: "*log" paths: /var/log recurse: yes register: fichiers
- name: debuggage debug: msg: "Modèle:Item.path" with_items: "Modèle:Fichiers.files"
</syntaxhighlight>
Mais bon, ce n'est pas génial... Ici, on doit faire une itération sur la liste et extraire les paths à chaque fois.
On peut aussi utiliser un filtre Jinja2:
<syntaxhighlight lang='yaml'> --- - hosts: all
become: true tasks:
- name: Récupérer les fichiers find: patterns: "*log" paths: /var/log recurse: yes register: fichiers
- name: debuggage debug: msg: "{{ fichiers['files'] | map(attribute='path') | list }}"
</syntaxhighlight>
Cette fois-ci, on a une liste de tous les paths. Mais bon, ce n'est pas génial non plus. Si j'avais des listes dans des listes, je devrais utiliser with_nested.
Assigner des variables au milieu d'un playbook
Pour cela, il faut utiliser le module set_fact. En reprenant l'exemple juste avant :
<syntaxhighlight lang='yaml'> --- - hosts: all
become: true tasks:
- name: Récupérer les fichiers find: patterns: "*log" paths: /var/log recurse: yes register: fichiers
- name: Une nouvelle variable set_fact: chemins: "{{ fichiers['files'] | map(attribute='path') | list }}"
- name: debuggage debug: msg: "Modèle:Chemins"
</syntaxhighlight>
Register les sorties de tasks
On capturer les sorties de tâches avec register. Non seulement ça marche de façon particulière avec certains modules comme find (qui renvoient un truc bien précis à ce moment là), mais il faut savoir que *tous* les modules renvoient quelque chose.
<syntaxhighlight lang='yaml'> - hosts: all
tasks: - name: Ansible register with_items example shell: "find *.txt" args: chdir: "/Users/mdtutorials2/Documents/Ansible" register: with_output
- shell: "cp Modèle:Item Modèle:Item_bkp" with_items: - "Modèle:With output.stdout lines"
- Ici, on s'en sert pour itérer sur la sortie de la commande shell envoyée.
</syntaxhighlight>
Chaque module fait son retour comme il veut; mais les retours sont en général des ensembles de valeurs auxquelles on peut accéder. Par exemple :
<syntaxhighlight lang='yaml'>
- name: shellcode shell: echo hi register: hello changed_when: false
- name: debuggage debug: var: hello
</syntaxhighlight>
Renvoie ça :
<syntaxhighlight lang="yaml"> ok: [localhost] => {
"hello": { "changed": false, "cmd": "echo hi", "delta": "0:00:00.001968", "end": "2019-10-01 23:58:28.548570", "failed": false, "rc": 0, "start": "2019-10-01 23:58:28.546602", "stderr": "", "stderr_lines": [], "stdout": "hi", "stdout_lines": [ "hi" ] }
} </syntaxhighlight>
Je peux accéder au return code avec hello.rc :
<syntaxhighlight lang="yaml"> TASK [debug2] ********************************************************************************** ok: [localhost] => {
"hello.rc": "0"
} </syntaxhighlight>
Gestion de la réentrance (idempotence)
Args : Creates
Utile dans l'utilisation de modules comme command, ou shell. Ces modules peuvent prendre des arguments avec "args:"; l'argument "creates" sert à préciser ce qu'une commande créée sur la machine. Ça sert à garder l'idempotence : Si ma commande est sensée créer un fichier mais que ce fichier existe déjà, elle ne relancera pas la commande.
Attention : ça ne semble pas fonctionner avec raw. Super. Raw ne prend quasiment pas d'arguments, à part le choix de shell; il faut donc bien les construire.
<syntaxhighlight lang='yaml'> --- - hosts: all
become: true tasks:
- name: Création de fichier command: dnf install python -y args: creates: "/usr/bin/python"
</syntaxhighlight>
Args: changed_when / failed_when
Les modules shell ou command ne sont pas géniaux pour gérer la réentrée. Cependant, on peut leur indiquer quand ce qu'ils font est un changement ou pas (afin d'afficher "changed" ou "ok". Pour ça, on a un autre argument : changed_when. On a aussi failed_when, qui fonctionne sur le même principe. Dans tous les cas, il faut faire un register sur le retour de module. Déjà, on peut annuler complètement les "changed" (si on sait ce qu'on fait) avec false:
<syntaxhighlight lang="yaml"> tasks:
- shell: /usr/bin/billybass --mode="take me to the river" register: bass_result changed_when: "bass_result.rc != 2"
# this will never report 'changed' status - shell: wall 'beep' changed_when: False
</syntaxhighlight>
On peut aussi annuler le change à certains conditions, principalement du texte dans la sortie standard / d'erreur :
<syntaxhighlight lang="yaml"> - name: Une commande
shell: /usr/bin/something register: _ changed_when: '"truc" in _.stdout.lower()'
- name: example of many failed_when conditions with OR
shell: "./myBinary" register: ret failed_when: > ("No such file or directory" in ret.stdout) or (ret.stderr != ) or (ret.rc == 10)
</syntaxhighlight>
De longues variables
Le linter d'Ansible 'naime pas les lignes de plus de 120 caractères. Quand on a une longue variable, on peut utiliser diverses méthodes.
[ Voir : https://adminswerk.de/multi-line-string-yaml-ansible-I/ ]
> | " ' >- >+ |- |+ -------------------------|------|-----|-----|-----|------|------|------|------ Trailing spaces | Kept | Kept | | | | Kept | Kept | Kept | Kept Single newline => | _ | \n | _ | _ | _ | _ | _ | \n | \n Double newline => | \n | \n\n | \n | \n | \n | \n | \n | \n\n | \n\n Final newline => | \n | \n | | | | | \n | | \n Final dbl nl's => | | | | | | | Kept | | Kept In-line newlines | No | No | No | \n | No | No | No | No | No Spaceless newlines| No | No | No | \ | No | No | No | No | No Single quote | ' | ' | ' | ' | '' | ' | ' | ' | ' Double quote | " | " | " | \" | " | " | " | " | " Backslash | \ | \ | \ | \\ | \ | \ | \ | \ | \ " #", ": " | Ok | Ok | No | Ok | Ok | Ok | Ok | Ok | Ok Can start on same | No | No | Yes | Yes | Yes | No | No | No | No line as key |
Et pour avoir une longue variable sur plusieurs lignes, sans espaces ni RIEN de rajoutés, il faut juste échapper l'espace et utiliser des doubles quotes:
<syntaxhighlight lang="yaml"> variable: "abcdef\
ghijkl"
</syntaxhighlight>
Boucler sur une liste + agir de façon conditionnelle (loop, when)
Voir aussi : https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html#loops-and-conditionals
Ci-dessous, un exemple de boucle avec loop + une condition:
<syntaxhighlight lang='yaml'>
- name: Ouverture ports firewalld: port: "Modèle:Item" permanent: yes state: enabled loop: "Modèle:Fwports" when: fwports is defined
</syntaxhighlight>
Ici, fwports est une liste définie comme ceci dans mon inventaire :
fwports='["80/tcp", "443/tcp"]'
Lookups
Les lookups permettent d'aller chercher des trucs.
<syntaxhighlight lang="yaml"> - hosts: all
vars: contents: "Modèle:Lookup('file', '/etc/foo.txt')" tasks: - debug: msg="the value of foo.txt is Modèle:Contents"
</syntaxhighlight>
Rebond SSH
Dans une configuration réseau en mode Bastion, on peut avoir besoin de faire un rebond pour accéder à nos machines. Dans ce cas, cela demande un peu de configuration (mais rien de compliqué). Ici, les machines du groupe "safe" ne sont accessible que par la machine "gate", qui n'accepte les connexions SSH que sur son port 220 (le port 22 étant pris par, par exemple, un EndleSSH :D ).
<source> [safe] foo.example.xyz bar.example.xyz baz.example.xyz
[safe:vars] ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ProxyCommand="ssh -W %h:%p -q gate.example.xyz -p 220"' </source>
Rendre un argument optionnel avec default(omit)
Dans le cas suivant:
- name: Start the container community.docker.docker_container: name: "{{ container_name }}" image: "{{ image_name }}:{{ image_tag | default(latest) }}" ports: "{{ container_ports | default(omit) }}" [...]
...en ce qui concerne l'argument "ports", on veut que celui-ci ne soit présenté au module docker que si la variable "container_ports" existe. C'est ce que signifie default(omit) : soit ma variable existe et l'argument ports est présenté, soit elle n'existe pas et l'argument n'est pas présenté. C'est vraiment utile pour améliorer la modularité des playbooks !
Un if/else
Apparement, Jinja permet de faire des if/else, mais j'ai l'impression que ça ne peut se faire que sur de l'attribuation de variables (grâce à Jinja).
--- - name: Jinja2 IF hosts: localhost vars: change_provided: True job_name: death_star change_string: destroy current_date_time: 1977-01-01 tasks: - name: Set base schedule name ansible.builtin.set_fact: base_schedule_name: "{%- if (change_provided | bool) -%} {{ job_name }}_{{ change_string }} {%- else -%} {{ job_name }}_{{ current_date_time }} {%- endif -%}" - name: Show value ansible.builtin.debug: msg: "{{ base_schedule_name }}"
Je remets l'explication issue de l'article:
- The {% and %} are delimiters indicating a Jinja2 code. In this case, there are extra - marks to indicate to Jinja2 that I want to remove the space characters I have before the variables (the spaces are only for aesthetics).
- If change_provided is true, I combine job_name with the underscore and change_string. Only this content is assigned, and any spaces before or after the variables are omitted because I previously used {%- and -%}.
- The else statement is similar to what you might know from other languages. In this case, I combine job_name with an underscore and current_date_time.
- Finally, the endif closes the if.