![Logo Ansible](images/logo-ansible.svg) # Templates ## Syntaxe jinja2 * Documentation - Jinja language : http://jinja.pocoo.org/docs/ - Template formatting : http://jinja.pocoo.org/docs/templates/ ## Principe * On créé les fichiers dans le dossier `templates` du Role. * On indique l'emplacement des zones variables à l'aide de la syntaxe `{{ ma_variable }}`. `templates/httpd.conf.j2` ```none ... Listen {{ apache_port }} DocumentRoot {{ apache_document_root }} ServerName {{ apache_server_name }} ServerAdmin {{ apache_server_admin }} ... ``` On utilise le module _template_ ```yaml - hosts: web vars: apache_port: 80 apache_document_root: /var/www/html apache_server_name: my-server apache_server_admin: admin@localhost tasks: - name: Deploy Apache configuration template: src: templates/httpd.conf.j2 dest: /etc/http/httpd.conf owner: apache group: apache mode: 0600 ``` Les variables sont automatiquement injectées dans le fichier sur la cible. ## Exemple pour une configuration du service NTP `./group_vars/all` ```none ntp_servers: - 0.pool.ntp.org - 1.pool.ntp.org - 2.pool.ntp.org - 3.pool.ntp.org ``` `./roles/ntp/templates/ntp.conf.j2` ```none ... {% for server in ntp_servers %} server {{ server }} {% endfor %} ... ``` `./roles/ntp/tasks/main.yaml` ```yaml - name: Install NTP package apt: name: "ntp" - name: Configure NTP template: src: ntp.conf.j2 dest: "/etc/ntp.conf" owner: "root" group: "root" mode: 0644 notify: Restart ntp service ``` ## Contrôle conditionnel ```none {% if condition %} do_some_thing {% elif condition2 %} do_another_thing {% else %} do_something_else {% endif %} ``` ## Filtres Les variables peuvent être modifiées par des filtres. https://docs.ansible.com/ansible/playbooks_filters.html ### Filtres Jinja2 * Les filtres Ansible reposent sur Jinja2. * Ils sont utilisés pour transformer des données. * Les filtres peuvent être chaînés. * Il est possible de créer des filtres personnalisés. ### Fixer une valeur par défaut aux variables non-définies ```none {{ variable | default(5) }} ``` ### Formater des données ```none {{ variable | to_json }} {{ variable | to_yaml }} ``` ```none {{ variable | from_json }} {{ variable | from_yaml }} ``` ### Filtres de listes Récupérer les valeurs minimales ou maximales ```none {{ ma_liste | min }} {{ [3, 4, 2] | max }} ``` Eliminer les doublons ```none {{ list1 | unique }} ``` Combiner deux listes ```none {{ list1 | union(list2) }} ``` Obtenir la différence entre deux listes (éléments dans list1 qui n'existent pas dans list2) ```none {{ list1 | difference(list2) }} ``` ### Filtres de nombres aléatoires Obtenir un élément au hasard parmi une liste ```none "{{ ['a','b','c'] | random }}" # => 'c' ``` Obtenir un nombre au hasard entre 0 et une valeur spécifiée ```none "{{ 60 | random}} * * * * root /script/from/cron“ # => '21 * * * * root /script/from/cron' ``` Obtenir un nombre au hasard entre 0 et 100 par pas de 10 ```none {{ 101 | random(step=10) }} # => 70 ``` ### Tester des adresses IP Tester si une chaîne est une adresse IP valide ```none {{ myvar | ipaddr }} ``` Même chose en forçant la version du protocole IP ```none {{ myvar | ipv4 }} {{ myvar | ipv6 }} ``` ### Filtres sur la notation CIDR ```none {{ '192.0.2.1/24' | ipaddr('address') }} '192.0.2.1/24' ``` ```none {{ '192.0.2.1/24' | ipaddr('prefix') }} '24' ``` https://docs.ansible.com/ansible/playbooks_filters_ipaddr.html ### Fonctions de hashage Obtenir l'empreinte sha1 ou md5 d'une chaîne ```none {{ 'test1' | hash('sha1') }} 'dba7673010f19a94af4345453005933fd511bea9' {{ 'test1' | hash('md5') }} '3e7705498e8be60520841409ebc69bc1' ``` https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#hashing-filters Obtenir un hashage de mot de passe sha512 ```none {{ 'passwordsaresecret' | password_hash('sha512') }} ``` Obtenir un hashage de mot de passe sha256 avec salage ```none {{ 'secretpassword' | password_hash('sha256', 'mysecretsalt') }} ``` Exemple d'utilisation dans un fichier de variables ```none user_password: "{{ 'Mon super password' | password_hash('sha256') }}" ``` ### Filtres de commentaires Il permettent de "décorer" un texte avec un style de commentaire. Exemple : ```none {{ "Hello" | comment }} ``` produit : ```none # # Hello # ``` Il est possible d'appliquer différents types de commentaires : ```none {{ "C style" | comment('c') }} '// C style' ``` ```none {{ "C block style" | comment('cblock') }} '/* C block style */' ``` ```none {{ "XML style" | comment('xml') }} '' ``` ### Filtres d'URL Obtenir une sous-partie d'une URL. ```none {{ "http://bob:1234@www.test.com:81/dir/index.html?query=term#fragment" | urlsplit('scheme') }} # => 'http' ``` Filtre | Résultat - | - urlsplit('scheme') | 'http' urlsplit('username') | 'bob' urlsplit('password') | '1234' urlsplit('hostname') | 'www.test.com' urlsplit('port') | '81' urlsplit('path') | '/dir/index.html' urlsplit('query') | 'query=term' urlsplit('fragment') | 'fragment' ### Autres filtres utiles Ajouter des guillemets pour protéger des variables (usage shell) ```none - shell: echo {{ string_value | quote }} ``` Retourner une valeur si un test est vrai et une autre si il est faux ```none {{ (name == "John") | ternary('Mr','Mme') }} ``` Concatener une liste en chaîne ```none {{ list | join(" ") }} ``` ```none {{ list | join(",") }} ``` Obtenir le dernier élément d'un chemin ```none {{ '/etc/foo/bar.txt' | basename }} 'bar.txt' ``` Obtenir le début d'un chemin ```none {{ '/etc/foo/bar.txt' | dirname }} '/etc/foo' ``` Obtenir le chemin réel d'un lien ```none {{ path | realpath }} ``` Expanser un chemin contenant un tilde (~) ```none {{ path | expanduser }} ``` Expanser un chemin contenant des variables d'environnement ```none {{ path | expandvars }} ``` Découper un nom de fichier ```none {{ path | splitext }} ``` Avec `path` == `nginx.conf` le retour sera `('nginx', '.conf')` ## Tests `variable` is `test expression` https://docs.ansible.com/ansible/playbooks_tests.html ### Tester des chaînes de caractères ```yaml vars: url: "http://example.com/users/foo/resources/bar" tasks: - debug: msg: "matched pattern 1" when: url is match("http://example.com/users/.*/resources/.*") - debug: msg: "matched pattern 2" when: url is search("/users/.*/resources/.*") - debug: msg: "matched pattern 3" when: url is search("/groups/") ``` ```none TASK [debug] ***************************************************************** ok: [my-host] => { "msg": "matched pattern 1" } TASK [debug] ***************************************************************** ok: [my-host] => { "msg": "matched pattern 2" } TASK [debug] ***************************************************************** skipping: [my-host] ``` ### Tester des numéros de version Si `ansible_facts['distribution_version']` est supérieur ou égal à 16.04, le test retourne `True`, sinon il retourne `False`. ```none {{ ansible_facts['distribution_version'] is version('16.04', '>=') }} ``` Opérateurs acceptés : `<`, `lt`, `<=`, `le`, `>`, `gt`, `>=`, `ge`, `==`, `=`, `eq`, `!=`, `<>`, `ne` ### Tester des chemins ```yaml - debug: msg: "path is a directory" when: mypath is directory - debug: msg: "path is a file" when: mypath is file - debug: msg: "path is a symlink" when: mypath is link - debug: msg: "path already exists" when: mypath is exists ``` Chaque tâche est effectuée ou abandonnée en fonction du résultat du test. ### Tester le résultat final d'une tâche ```yaml - shell: /usr/bin/foo register: result ignore_errors: True - debug: msg: "it failed" when: result is failed - debug: msg: "it succeeded" when: result is succeeded ``` ## Sortir prématurément en fonction de conditions * Le module _fail_ permet de stopper l'exécution d'un playbook si un condition n'est pas remplie. * Dans l'exemple suivant, l'exécution s'arrête car la variable `param2` n'est pas définie. ```yaml --- - hosts: ansible-1 vars: - param1: "test" tasks: - name: 'exit if param1 or param2 are null or invalid' fail: msg="Please enter correct Params" when: param1 is not defined or param2 is not defined - debug: msg: "other tasks..." ``` ## Travaux pratiques ![Travaux pratiques](images/tp.gif) [TP Ansible : templates](travaux-pratiques/tp-ansible-templates.html)