# Playbook Un playbook Ansible è un file testuale, scritto in formato YAML, che definisce una sequenza di operazioni (`task`) da eseguire su uno o più nodi. Un playbook può contenere uno o più *Play*. Ogni Play è composto da una serie di *task*, che a loro volta possono richiamare uno o più moduli. ## Struttura di un playbook Di seguito è riportato un esempio di playbook: ```yaml --- - name: install and start httpd hosts: databases tasks: - name: install httpd apt: name: httpd state: latest become: true - name: start httpd service: name: httpd state: started become: true ``` - `name`: specifica il nome del play, che descrive l'azione da eseguire - `hosts`: indica i nodi sui quali il play sarà eseguito - `tasks`: contiene un elenco di operazioni da eseguire In questo esempio: - il playbook contiene un unico play - il play ha il compito di installare e avviare il servizio httpd su un gruppo di host denominato *databases* - sono definiti due task: il primo installa il pacchetto httpd tramite il *modulo apt*, mentre il secondo avvia il servizio httpd utilizzando il *modulo service* - l’opzione `become: true` indica che i task devono essere eseguite con privilegi elevati, tipicamente utilizzando sudo Un esempio di playbook con due play: ```yaml --- - name: install and start apache hosts: webservers tasks: - name: install apache apt: name: apache2 state: latest become: true - name: start apache service: name: apache2 state: started become: true - name: install and start mysql hosts: databases tasks: - name: install mysql apt: name: mysql-server state: latest become: true - name: start mysql service: name: mysql state: started become: true ``` ## Esecuzione di un playbook Per eseguire un playbook, è necessario utilizzare il comando `ansible-playbook`, specificando: - l’inventory file, se custom, con l'opzione `-i` - il percorso del playbook - eventuali opzioni aggiuntive, come `-ask-vault-pass`, che richiede la password per decifrare i file crittografati con `ansible-vault` ```bash ansible-playbook -i inventory playbook/my-playbook.yml -K --ask-vault-pass ``` ## Conditionals Le istruzioni condizionali consentono di modificare il comportamento di un playbook in base a specifiche condizioni. L'istruzione condizionale più semplice si applica a un singolo task, utilizzando la parola chiave `when`. In questo caso, il task verrà eseguito solo sui nodi in cui la condizione specificata è soddisfatta. ### Tipologie di condizioni Le condizioni possono basarsi su diversi tipi di dati: - `ansible_facts`: attributi specifici di ogni host, messi a disposizione da Ansible. Questi fanno riferimento a caratteristiche del nodo, come il tipo sistema operativo, le caratteristiche hardware e altre proprietà rilevanti. Sono utili per adattare il comportamento del playbook in base alle caratteristiche del nodo target - `registered variables`: variabili che contengono il risultato di task precedenti. È possibile condizionare in questo modo l’esecuzione di un task in base all’esito di un task già eseguito - `variabili` definite nel playbook o nell'inventory Un semplice esempio di condizione `when`: ```yaml --- - name: playbooks with conditions hosts: db become: true tasks: - name: install postgres yum: name: postgresql state: latest when: ansible_distribution == 'Ubuntu' ``` Un esempio di `registered variables`: ```yaml --- - name: Install and Start HTTPD Service hosts: webservers become: true tasks: - name: Install the httpd package yum: name: httpd state: present register: httpd_installation - name: Start the httpd service service: name: httpd state: started when: httpd_installation.changed == true ``` Questo task utilizza il modulo yum per installare il pacchetto httpd. Durante l'esecuzione, il risultato dell'installazione viene registrato nella variabile `httpd_installation`. Avvia infine il servizio httpd, ma solo se l'installazione del pacchetto è stata completata con successo. ## Loops I loop in Ansible consentono di ripetere un task più volte all'interno di un playbook, evitando la necessità di riscrivere blocchi di codice che eseguono la stessa operazione. I tre tipi principali di loop sono: - `Liste` - `Liste di hash` - `Dizionari` ### Liste Per i loop di liste, si utilizza la parola chiave `loop`, seguita da una lista di stringhe. Il task verrà eseguito tante volte quante sono le stringhe nella lista, e `{{ item }}`, nel task, assumerà il valore dell'elemento iesimo. ```yaml --- - name: playbook with loop hosts: db become: true tasks: - name: add users user: name: "{{ item }}" loop: - userOne - userTwo ``` ### Liste di hash Per i loop di liste di hash, si utilizza la medesima parola chiave loop, ma la lista contiene elementi `chiavi: valore`. In questo caso, si può accedere ai valori usando la sintassi `{{ item.key }}`. ```yaml --- - name: Playbook con loop su lista di hash hosts: db become: true tasks: - name: add users user: name: "{{ item.name }}" uid: "{{ item.uid }}" shell: "{{ item.shell }}" loop: - { name: 'userOne', uid: 1001, shell: '/bin/bash' } - { name: 'userTwo', uid: 1002, shell: '/bin/zsh' } ``` ## Blocks I blocchi in Ansible vengono impiegati per due finalità principali: - *raggruppare task* correlati tra loro, in modo da applicare direttive comuni a un insieme di operazioni - *gestire gli errori* che possono verificarsi durante l’esecuzione dei task, consentendo di definire azioni specifiche in caso di fallimento o di successo Tutte le direttive associate a un blocco vengono automaticamente ereditate da tutti i task contenuti al suo interno. I blocchi offrono due sezioni dedicate alla gestione degli errori: - `rescue`: contiene i task che vengono eseguiti immediatamente nel caso in cui almeno uno dei task all'interno del blocco generi un errore - `always`: contiene i task che vengono eseguiti indipendentemente dall’esito dei task nel blocco, sia in caso di successo che di fallimento Un esempio di **raggruppamento**: ```yaml --- - name: block hosts: db tasks: - block: - name: list user command: ls -l /usr/ - name: list root command: ls -l /root/ - name: list bin command: ls -l /bin/ - name: list home command: ls -l ~/ become: yes - name: list home command: "ls -l ~/" ``` La direttiva `become: yes` è associata al blocco e viene applicata a tutti i task al suo interno, semplificando la gestione delle operazioni correlate. Un esempio di **gestione di errori**: ```yaml --- - name: Error handling example hosts: db tasks: - block: - name: Execute a command that fail command: /bin/false rescue: - name: Handle the error debug: msg: "The command failed, executing an alternative action." always: - name: Always execute this command debug: msg: "This action is executed regardless of the block's result." ``` In questo caso, il task nella sezione `rescue` viene eseguito solo se il comando /bin/false fallisce, mentre il task nella sezione `always` viene eseguito in ogni circostanza.