Outils pour utilisateurs

Outils du site


tech:notes_ansible_jinja2

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
tech:notes_ansible_jinja2 [2025/09/22 09:57] Jean-Baptistetech:notes_ansible_jinja2 [2025/09/22 22:52] (Version actuelle) Jean-Baptiste
Ligne 1: Ligne 1:
 +<!DOCTYPE markdown>
 +{{tag>Ansible YAML Jinja}}
 +
 +# Notes Ansible Jinja2
 +
 +
 +Voir :
 +  * https://jinja.palletsprojects.com/en/3.1.x/templates/#list-of-control-structures
 +  * https://ansible-arista-howto.readthedocs.io/en/latest/JINJA_YAML_STRUCTURES.html
 +  * https://tedboy.github.io/jinja2/templ14.html
 +  * https://docs.saltproject.io/en/latest/topics/jinja/index.html
 +  * https://blog.stephane-robert.info/post/ansible-template-jinja/
 +  * j2cli
 +  * [Mastering loops with Jinja templates in Ansible](https://www.redhat.com/en/blog/ansible-jinja)
 +  * https://blog.stephane-robert.info/docs/developper/programmation/python/jinja/
 +
 +
 +
 +
 +A la place du module **template** il est possible d'utiliser le module **copy** :
 +Ansible M(template) M(copy)
 +~~~yaml
 +     - name: Generate new resolv.conf
 +       ansible.builtin.copy:
 +         mode: "{{ stat_resolv_conf.stat.mode }}"
 +         content: |
 +           {% for nameserver in nameservers %}
 +           nameserver {{ nameserver }}
 +           {% endfor %}
 +         dest: resolv.conf.test
 +~~~
 +
 +### Ansible jinja version
 +
 +~~~
 +$ ansible --version |grep jinja
 +  jinja version = 3.1.6
 +~~~
 +
 +
 +### Jinja2 en ligne de commande j2cli j2
 +
 +#### Install
 +
 +~~~bash
 +apt-get install j2cli
 +~~~
 +
 +ou
 +~~~bash
 +pip3 install jinja2-cli[yaml,toml,xml,hjson,json5]==0.8.2 # --break-system-packages
 +~~~
 +
 +#### Exemples
 +
 +Exemple 1
 +
 +''nginx.conf.j2''
 +~~~nginx
 +server {
 +  listen 80;
 +  server_name {{ nginx.hostname }};
 +
 +  root {{ nginx.webroot }};
 +  index index.htm;
 +}
 +~~~
 +
 +''nginx.yaml''
 +~~~yaml
 +---
 +
 +nginx:
 +  hostname: localhost
 +  webroot: "/var/html/projet1"
 +
 +~~~
 +
 +~~~bash
 +# j2 -f json nginx.conf.j2 nginx.json > nginx.conf
 +j2 nginx.conf.j2 nginx.yaml > nginx.conf
 +~~~
 +
 +Exemple 2
 +
 +''timezone.j2''
 +~~~
 +{{ TIMEZONE }}
 +~~~
 +
 +''ENV''
 +~~~bash
 +TIMEZONE=Europe/Paris
 +~~~
 +
 +~~~bash
 +j2 -f env timezone.j2 ENV > timezone
 +~~~
 +
 +
 +
 +### Regex
 +
 +~~~
 +{{ requete_conteneur.stdout | regex_replace('\\s', '') }}
 +~~~
 +
 +Exclure un élément d'une liste / enlever un élément d'une liste.
 +
 +~~~yaml
 +    - name: DEBUG
 +      debug: msg='{{ item }}'
 +      with_items: '{{ ansible_interfaces |difference(["lo"]) }}'
 +~~~
 +
 +### Condition IF
 +
 +''/etc/yum.repos.d/plop.repo''
 +~~~
 +{% if ansible_distribution_version == '7.2' %}
 +[mirorlinux-rh7.2-x86_64]
 +name=Plop RH 7.2
 +baseurl=http://172.16.12.42/redhat/rh7.2/x86_64/
 +gpgcheck=0
 +enabled=1
 +{% endif %}
 +~~~
 +
 +~~~
 +{% for user in users if not user.hidden %}
 +    <li>{{ user.username|e }}</li>
 +{% endfor %}
 +~~~
 +
 +
 +### Valeur par défaut - variable undef
 +
 +Erreur
 +~~~
 +fatal: [vmware-local]: FAILED! => {"failed": true, "msg": "'servers' is undefined"}
 +~~~
 +
 +Code Ansible
 +~~~yaml
 +- name: conf /etc/chrony.conf - add servers
 +  lineinfile: dest=/etc/chrony.conf line='server {{ item }} iburst'
 +  with_items:
 +    - "{{ servers }}"
 +    - 172.18.32.3
 +~~~
 +
 +Code Ansible corrigé 
 +~~~yaml
 +- name: conf /etc/chrony.conf - add servers
 +  lineinfile: dest=/etc/chrony.conf line='server {{ item }} iburst'
 +  with_items:
 +    #- "{{ servers |default('') }}"
 +    - "{{ servers |default([]) }}"
 +    - 172.18.32.3
 +~~~
 +
 +Liste vide avec item undef - with_item undef / empty : 
 +~~~
 +{{ item |default([]) }}''
 +~~~
 +
 +
 +### Affichage - Alignement
 +
 +Avec la méthode ''ljust'' ou ''rjust''
 +
 +~~~jinja
 +{% for HOST in hosts %}
 +define host {
 +{% for k, v in HOST.items() %}
 +        {{ k.ljust(20) }}                       {{ v }}
 +{% endfor %}
 +}
 +
 +{% endfor %}
 +~~~
 +
 +
 +### Lever une exeption
 +
 +
 +Source https://stackoverflow.com/questions/21778252/how-to-raise-an-exception-in-a-jinja2-macro
 +
 +Avec Ansibe 
 +~~~
 +{{ ('OK text' if condition_ok) | mandatory('Text of error message') }}
 +
 +{{ ('' if false) | mandatory('ERROR: KIND must be A, B or C') }}
 +~~~
 +
 +Ou sinon plus simple :
 +~~~
 +{{ 0/0 }}
 +~~~
 +
 +
 +
 +
 +## Linter
 +
 +Voir :
 +  * https://pypi.org/project/djlint/
 +
 +~~~bash
 +sudo apt-get install python3-pip
 +~~~
 +
 +~~~bash
 +python3 -m venv djlint
 +source bin/activate
 +pip install djlint
 +~~~
 +
 +~~~
 +$ ./bin/djlint ~/code/template-dockerfile/ --extension=j2 --lint
 +
 +Linting 1/1 files ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 00:00
 +
 +
 +Dockerfile.j2
 +──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 +H025 19:9 Tag seems to be an orphan. <EOF >
 +H014 132:27 Found extra blank lines. e/pcc/logs
 +
 +Linted 1 file, found 2 errors.
 +~~~
 +
 +~~~bash
 +djlint . --extension=html.j2 --lint
 +
 +djlint . --extension=html.j2 --check
 +
 +djlint . --extension=html.j2 --reformat
 +~~~
 +
 +## Exemples
 +
 +### Variables - Whitespace Control - Exemple de contrôles de sauts de ligne et d'espaces
 +
 +Voir : https://jinja.palletsprojects.com/en/stable/templates/#variables
 +
 +
 +#### Méthode 1 
 +
 +* Utilisation de ''+'' dans la boucle
 +* Utilisation de ''-'' dans les conditions à l'interieur de la boucle
 +* A la fin de la dernière condition (''endif'') utiliser un ''+'' à la place d'un ''-''
 +
 +~~~
 +{%+ for KEY in CONF.SYS_GROUPS +%}
 +    {%- if CONF.SYS_GROUPS[KEY].GID is defined -%}
 +        RUN groupadd -g {{ CONF.SYS_GROUPS[KEY].GID }} {{ KEY }}
 +    {%- else -%}
 +        RUN groupadd {{ KEY }}
 +    {%- endif +%}
 +{%+ endfor +%}
 +~~~
 +
 +
 +
 +#### Méthode 2
 +
 +* Mettre des ''-'' systématiquement sauf aux extrémités de la boucle
 +* A chaque fin de ligne utiliser : 
 +~~~
 +{{ '\n' }}
 +~~~ 
 +
 +~~~
 +{% for KEY in CONF.SYS_GROUPS -%}
 +    {%- if CONF.SYS_GROUPS[KEY].GID is defined -%}
 +        RUN groupadd -g {{ CONF.SYS_GROUPS[KEY].GID }} {{ KEY + '\n' }}
 +    {%- else -%}
 +        RUN groupadd {{ KEY + '\n' }}
 +    {%- endif -%}
 +{%- endfor %}
 +~~~
 +
 +
 +## Ansible Templating all j2 files
 +
 +~~~yaml
 +- name: Templating all j2 files with config.yaml
 +  gather_facts: false
 +  hosts: localhost
 +
 +  tasks:
 +    - name: Include vars of config.yaml
 +      no_log: true
 +      ansible.builtin.include_vars:
 +        file: config.yaml
 +        name: CONF
 +
 +    - name: Find all j2 templates files
 +      register: reg_find_j2tpls
 +      ansible.builtin.find:
 +        paths: "."
 +        patterns: "*.j2"
 +        hidden: false
 +        file_type: file
 +        recurse: true
 +        excludes:
 +          - .git
 +
 +    - name: Templating j2 files
 +      ansible.builtin.template:
 +        src: "{{ item }}"
 +        dest: "{{ dest }}"
 +        mode: "0600"
 +      loop: "{{ reg_find_j2tpls.files | map(attribute='path') }}"
 +      vars:
 +        dest: "{{ item | regex_replace('\\.j2$', '') }}"
 +~~~
 +
 +
 +
 +
 +## Pb
 +
 +### Err template error while templating string: no filter named 'split'
 +
 +~~~
 +fatal: [localhost]: FAILED! => {"msg": "template error while templating string: no filter named 'split'. String: {{ fic_resolv.content | b64decode | split('\n') | select('match', '^nameserver\\\\s' ) | replace('\\\\t', ' ') | regex_replace('nameserver\\\\s+') }}"}
 +~~~
 +
 +La version d'Ansible est trop ancienne
 +
 +A la place du filtre ''split'' il est possible d'utiliser la méthode ''split'' ou ''splitlines''
 +
 +~~~yaml
 +- name: Set facts - get values - resolv.conf
 +  ansible.builtin.set_fact:
 +    # resolv_lines_domains: "{{ fic_slurp_resolv.content | b64decode | split('\n') | select('match', '^domain\\s' )     | replace('\\t', ' ') | regex_replace('domain\\s+'    }}"
 +    resolv_lines_domains: "{{ (fic_slurp_resolv.content | b64decode).split('\n') | select('match', '^domain\\s' ) | list | replace('\\t', ' ') | regex_replace('domain\\s+') }}"
 +~~~
 +
 +
 +
 +
 +
  

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki