![Logo Ansible](images/logo-ansible.svg) # Structures de contrôle ## _Facts_ * Variables délivrées par le système distant : - Adresses IP - Système d'exploitation - ... ## Facts - module setup * Liste des informations disponibles : module _setup_ ```none $ ansible my-host -i ./hosts -m setup my-host | SUCCESS => { "ansible_facts": { "ansible_all_ipv4_addresses": [ "10.6.214.74" ], "ansible_all_ipv6_addresses": [ "fe80::250:56ff:fe9d:1aaa" ], "ansible_architecture": "x86_64", ... ``` ### Facts pour la gestion multi-os * `ansible_pkg_mgr` : Le gestionnaire de paquets * `ansible_os_family` : La famille d'OS * `ansible_distribution` : Information détaillées sur la distribution ### Gestionnaire de paquets ```none $ ansible my-host -i ./hosts -m setup | grep ansible_pkg_mgr "ansible_pkg_mgr": "yum", ``` ### Famille d'OS ```none $ ansible my-host -i ./hosts -m setup | grep ansible_family "ansible_os_family": "RedHat", ``` ### Distribution ```none $ ansible my-host -i ./hosts -m setup | grep ansible_distribution "ansible_distribution": "CentOS", "ansible_distribution_file_parsed": true, "ansible_distribution_file_path": "/etc/redhat-release", "ansible_distribution_file_variety": "RedHat", "ansible_distribution_major_version": "7", "ansible_distribution_release": "Core", "ansible_distribution_version": "7.5.1804", ``` ### Exemple d'aiguillage multi-OS Arborescence du rôle ```none my-role ├── README.md ├── tasks │   ├── CentOS.yaml -> RedHat.yaml │   ├── Debian.yaml │   ├── main.yaml │   ├── RedHat.yaml │   └── Ubuntu.yaml -> Debian.yaml └── vars    ├── CentOS-6.yaml    ├── CentOS-7.yaml    ├── Debian-8.yaml    ├── Debian-9.yaml    ├── RedHat-6.yaml    ├── RedHat-7.yaml    └── Ubuntu-16.yaml ``` `my-role/tasks/main.yaml` ```yaml - name: Add the OS specific variables include_vars: '{{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yaml' - include_tasks: '{{ansible_distribution}}.yaml' ``` ## Utilisation des _conditionals_ * Action déclenchée de manière conditionnelle (en fonction du résultat d’une variable). * Utilisation de _when_. https://docs.ansible.com/ansible/playbooks_conditionals.html ### Exemple ```yaml - hosts: web tasks: - name: Install Apache for CentOS system yum: name: httpd state: present update_cache: yes when: - ansible_os_family == "RedHat" # sera joué sur RedHat et Centos - name: Install Apache for Ubuntu system apt: name: apache2 state: present update_cache: yes when: - ansible_os_family == "Debian" # sera joué sur Debian et Ubuntu ``` Chaque tâche cible une famille de système d'exploitation précise. ```none $ ansible-playbook playbook.yaml -i ./hosts PLAY [web] ******************************************************************* TASK [setup] ***************************************************************** ok: [centos-vm] ok: [ubuntu-vm] TASK [Install Apache for CentOS system] ************************************** ok: [centos-vm] skipping: [ubuntu-vm] TASK [Install Apache for Ubuntu system] ************************************** skipping: [centos-vm] ok: [ubuntu-vm] PLAY RECAP ******************************************************************* centos-vm : ok=2 changed=0 unreachable=0 failed=0 ubuntu-vm : ok=2 changed=0 unreachable=0 failed=0 ``` Les tâches sont exécutées ou non en fonction de la famille du système d'exploitation. ## Utilisation des _loops_ * Boucles pour la réalisation d'actions répétitives. * Permet de faire plusieurs actions dans une seule tâche. * Création d'utilisateurs, installation de paquets, ... * Utilisation de ~~with-x~~ _loop_ https://docs.ansible.com/ansible/playbooks_loops.html ### with-x Paramètre | Type | Example d'utilisation - | - | - `with_items` | Array | To create a group of users, directories, or to install a list of packages `with_nested` | Nested loops | To create a list of MySQL users and grant them access to a group of databases `with_dict` | Hashes | To parse a dictionary of key-value pairs and create virtual hosts `with_fileglobs` |Files with pattern match | To parse a path and copy only those files that match a certain pattern `with_together` | S ets | To join two arrays as a set and to loop over it `with_subelements` | Hash sub element | To walk over the list of SSH keys and distribute them to a user `with_sequence` | Integer sequence | To loop a sequence of numbers `with_random_choice` | Random choice | To pick up items from the array in a random order `with_indexed_items` | Array with index | Array with an index and is useful when an index for items is required ### Exemple avec with_items ```yaml - hosts: my-host tasks: - name: Add some users user: name: "{{ item }}" state: present with_items: - bob - alice - joe ``` Attention ! à partir d'Ansible 2.5 _with-x_ n'est plus la méthode recommandé pour effectué des boucles. ```none $ ansible-playbook playbook.yaml -i ./hosts PLAY [my-host] *************************************************************** TASK [setup] ***************************************************************** ok: [my-host] TASK [Add some users] ******************************************************** changed: [my-host] => (item=bob) changed: [my-host] => (item=alice) changed: [my-host] => (item=joe) PLAY RECAP ******************************************************************* my-host : ok=2 changed=1 unreachable=0 failed=0 ``` La boucle a bien itéré sur les 3 utilisateurs. ### Migration vers loop * A partir d'Ansible 2.5 _with-x_ n'est plus la méthode recommandée pour effectuer des boucles. * La documentation sur les boucles propose une section pour aider à la migration de _with-x_ vers _loop_. https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html ### Exemple avec loop ```yaml - hosts: my-host tasks: - name: Add some users user: name: "{{ item }}" state: present loop: - bob - alice - joe ``` On remplace simplement `with_items` par `loop`. ```none $ ansible-playbook -i inventories/formation/hosts playbook.yaml PLAY [my-host] *************************************************************** TASK [Gathering Facts] ******************************************************* ok: [my-host] TASK [Add some users] ******************************************************** changed: [my-host] => (item=bob) changed: [my-host] => (item=alice) changed: [my-host] => (item=joe) PLAY RECAP ******************************************************************* my-host : ok=2 changed=1 unreachable=0 failed=0 ``` Le résultat final est strictement identique. ```yaml - hosts: my-host tasks: - name: Add some users user: name: "{{ item.name }}" state: present groups: "{{ item.groups }}" loop: - { name: 'bob', groups: 'wheel' } - { name: 'alice', groups: 'root' } - { name: 'joe', groups: 'root' } ``` En plus des _strings_ , il est possible d'utiliser des _hashes_. ### Itérer sur l'inventaire ```yaml - hosts: centos7 tasks: - name: Iterate on hosts in the group all in the inventory debug: msg: "{{ item }}" loop: "{{ groups['all'] }}" # on itère sur les machines du groupe all ``` ```none $ ansible-playbook -i ./hosts playbook.yaml PLAY [centos7] ***************************************************************** TASK [Iterate on hosts in the group all in the inventory] ********************** ok: [ansible-1] => (item=ansible-3) => { "msg": "ansible-3" } ok: [ansible-1] => (item=ansible-1) => { "msg": "ansible-1" } ok: [ansible-1] => (item=ansible-2) => { "msg": "ansible-2" } ok: [ansible-2] => (item=ansible-3) => { "msg": "ansible-3" } ok: [ansible-2] => (item=ansible-1) => { "msg": "ansible-1" } ok: [ansible-2] => (item=ansible-2) => { "msg": "ansible-2" } ``` Chaque machine du Play (_centos7_) itère sur le groupe _all_. ### Itérer sur le Play ```yaml - hosts: centos7 tasks: - name: Iterate on all the hosts in the current play debug: msg: "{{ item }}" loop: "{{ ansible_play_batch }}" # variable qui contient les machines du Play ``` ```none $ ansible-playbook -i inventories/formation/hosts playbook.yaml PLAY [centos7] ***************************************************************** TASK [Iterate on all the hosts in the current play] **************************** ok: [ansible-1] => (item=ansible-1) => { "msg": "ansible-1" } ok: [ansible-1] => (item=ansible-2) => { "msg": "ansible-2" } ok: [ansible-2] => (item=ansible-1) => { "msg": "ansible-1" } ok: [ansible-2] => (item=ansible-2) => { "msg": "ansible-2" } ``` Chaque machine du Play (_centos7_) itère sur les machines du Play (_centos7_). ## Travaux pratiques ![Travaux pratiques](images/tp.gif) [TP Ansible : structures de contrôle](travaux-pratiques/tp-ansible-structures-de-controle.html)