Comment afficher la sortie des commandes shell dans les playbooks Ansible

AnsibleIntermediate
Pratiquer maintenant

Introduction

Ansible est un outil d'automatisation open-source puissant, largement utilisé par les administrateurs système et les professionnels DevOps. L'une de ses capacités clés est l'exécution de commandes shell sur des hôtes distants et le traitement de leur sortie. Dans ce tutoriel pratique, vous apprendrez comment capturer, afficher et traiter efficacement la sortie des commandes shell dans les playbooks Ansible. Cette compétence est essentielle pour créer des flux de travail d'automatisation robustes, capables de s'adapter à différentes conditions système et de fournir des retours d'information utiles.

Ceci est un Guided Lab, qui fournit des instructions étape par étape pour vous aider à apprendre et à pratiquer. Suivez attentivement les instructions pour compléter chaque étape et acquérir une expérience pratique. Les données historiques montrent que c'est un laboratoire de niveau intermédiaire avec un taux de réussite de 53%. Il a reçu un taux d'avis positifs de 100% de la part des apprenants.

Configuration de votre premier playbook Ansible avec des commandes Shell

Dans cette étape, nous allons configurer un playbook Ansible de base qui exécute des commandes shell et capture leur sortie. Cela fournira les bases pour des techniques plus avancées dans les étapes suivantes.

Installation d'Ansible

Tout d'abord, installons Ansible sur notre système :

sudo apt update
sudo apt install -y ansible

Maintenant, vérifiez qu'Ansible est correctement installé :

ansible --version

Vous devriez voir une sortie similaire à celle-ci :

ansible [core 2.12.x]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/labex/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  ansible collection location = /home/labex/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.10.x (default, Mar 15 2022, 12:22:08) [GCC 11.2.0]
  jinja version = 3.0.3
  libyaml = True

Création d'un fichier d'inventaire

Ansible utilise un fichier d'inventaire pour savoir quels hôtes gérer. Pour ce lab, nous allons créer un inventaire simple qui inclut uniquement la machine locale :

  1. Ouvrez votre WebIDE et créez un nouveau fichier appelé inventory.ini dans le répertoire /home/labex/project.
  2. Ajoutez le contenu suivant au fichier :
[local]
localhost ansible_connection=local

Cet inventaire définit un groupe appelé local qui contient uniquement localhost, et indique à Ansible de se connecter directement sans SSH.

Création de votre premier Playbook

Maintenant, créons un playbook simple qui exécute des commandes shell :

  1. Créez un nouveau fichier appelé first_playbook.yml dans le répertoire /home/labex/project.
  2. Ajoutez le contenu YAML suivant au fichier :
---
- name: Shell Command Example
  hosts: local
  gather_facts: no

  tasks:
    - name: Run a simple shell command
      shell: echo "Hello from Ansible shell command"
      register: hello_output

    - name: Display the output
      debug:
        msg: "{{ hello_output.stdout }}"

Ce playbook fait ce qui suit :

  • Cible le groupe local que nous avons défini dans notre inventaire
  • Ignore la collecte des faits (informations système) pour simplifier les choses
  • Exécute une commande shell qui affiche un message de salutation
  • Stocke la sortie dans une variable en utilisant le mot-clé register
  • Affiche la sortie en utilisant le module debug

Exécution de votre Playbook

Maintenant, exécutons le playbook :

ansible-playbook -i inventory.ini first_playbook.yml

Vous devriez voir une sortie similaire à celle-ci :

PLAY [Shell Command Example] **************************************************

TASK [Run a simple shell command] *********************************************
changed: [localhost]

TASK [Display the output] *****************************************************
ok: [localhost] => {
    "msg": "Hello from Ansible shell command"
}

PLAY RECAP ********************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

La sortie montre que notre playbook s'est exécuté avec succès, exécutant la commande shell et affichant sa sortie.

Concepts clés à comprendre

De cet exercice, notez ces concepts importants :

  1. Le module shell vous permet d'exécuter des commandes shell
  2. La directive register capture la sortie d'une tâche dans une variable
  3. Le module debug aide à afficher les valeurs des variables
  4. La sortie des commandes shell contient à la fois stdout (sortie standard) et stderr (sortie d'erreur)

Dans l'étape suivante, nous explorerons comment traiter et formater la sortie des commandes shell plus efficacement.

Travailler avec la sortie structurée des commandes Shell

Maintenant que vous comprenez les bases de l'exécution des commandes shell dans Ansible, explorons comment travailler avec la sortie structurée des commandes et l'afficher dans différents formats.

Traitement des informations système

Créons un playbook plus pratique qui collecte des informations système et les présente de manière structurée :

  1. Créez un nouveau fichier appelé system_info.yml dans le répertoire /home/labex/project.
  2. Ajoutez le contenu suivant :
---
- name: Gather and Display System Information
  hosts: local
  gather_facts: no

  tasks:
    - name: Gather system information
      shell: |
        echo "OS Information: $(cat /etc/os-release | grep PRETTY_NAME | cut -d= -f2)"
        echo "Kernel Version: $(uname -r)"
        echo "CPU Information: $(grep "model name" /proc/cpuinfo | head -1 | cut -d: -f2 | xargs)"
        echo "Memory Information: $(free -h | grep Mem | awk '{print $2}')"
      register: system_info

    - name: Display raw system information
      debug:
        msg: "{{ system_info.stdout }}"

    - name: Display information as a list
      debug:
        msg: "{{ system_info.stdout_lines }}"

Ce playbook :

  • Exécute un script shell multiligne qui collecte diverses informations système
  • Stocke la sortie dans la variable system_info
  • Affiche la sortie d'abord sous forme de chaîne brute, puis sous forme de liste de lignes

Exécutez le playbook :

ansible-playbook -i inventory.ini system_info.yml

Vous devriez voir une sortie qui ressemble à ceci :

PLAY [Gather and Display System Information] **********************************

TASK [Gather system information] **********************************************
changed: [localhost]

TASK [Display raw system information] *****************************************
ok: [localhost] => {
    "msg": "OS Information: \"Ubuntu 22.04.1 LTS\"\nKernel Version: 5.15.0-1023-azure\nCPU Information: Intel(R) Xeon(R) Platinum 8171M CPU @ 2.60GHz\nMemory Information: 4.0Gi"
}

TASK [Display information as a list] *****************************************
ok: [localhost] => {
    "msg": [
        "OS Information: \"Ubuntu 22.04.1 LTS\"",
        "Kernel Version: 5.15.0-1023-azure",
        "CPU Information: Intel(R) Xeon(R) Platinum 8171M CPU @ 2.60GHz",
        "Memory Information: 4.0Gi"
    ]
}

PLAY RECAP ********************************************************************
localhost                  : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Remarquez comment la deuxième tâche d'affichage montre la sortie sous forme de liste au lieu d'une chaîne avec des sauts de ligne. Ce format de liste facilite le travail avec une sortie multiligne.

Travailler avec les résultats de commandes et les codes de retour

Les commandes shell sous Linux renvoient des codes de sortie pour indiquer le succès (0) ou l'échec (non nul). Ansible les capture dans l'attribut rc (return code) de la variable enregistrée.

Créons un playbook qui démontre comment travailler avec les codes de retour :

  1. Créez un nouveau fichier appelé command_results.yml dans le répertoire /home/labex/project.
  2. Ajoutez le contenu suivant :
---
- name: Working with Command Results
  hosts: local
  gather_facts: no

  tasks:
    - name: Check if a file exists
      shell: test -f /etc/hosts
      register: file_check
      ignore_errors: yes

    - name: Show command result details
      debug:
        msg: |
          Return code: {{ file_check.rc }}
          Succeeded: {{ file_check.rc == 0 }}
          Failed: {{ file_check.rc != 0 }}

    - name: Check if a non-existent file exists
      shell: test -f /file/does/not/exist
      register: missing_file
      ignore_errors: yes

    - name: Show command result for missing file
      debug:
        msg: |
          Return code: {{ missing_file.rc }}
          Succeeded: {{ missing_file.rc == 0 }}
          Failed: {{ missing_file.rc != 0 }}

Ce playbook :

  • Exécute deux commandes de test pour vérifier si des fichiers existent
  • Utilise ignore_errors: yes pour empêcher le playbook de s'arrêter si une commande échoue
  • Affiche des informations détaillées sur les résultats de la commande, y compris le code de retour et l'état de réussite/échec

Exécutez le playbook :

ansible-playbook -i inventory.ini command_results.yml

Vous devriez voir une sortie similaire à ceci :

PLAY [Working with Command Results] *******************************************

TASK [Check if a file exists] *************************************************
changed: [localhost]

TASK [Show command result details] ********************************************
ok: [localhost] => {
    "msg": "Return code: 0\nSucceeded: True\nFailed: False\n"
}

TASK [Check if a non-existent file exists] ************************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": "test -f /file/does/not/exist", "delta": "0:00:00.003183", "end": "2023-07-14 15:24:33.931406", "msg": "non-zero return code", "rc": 1, "start": "2023-07-14 15:24:33.928223", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring

TASK [Show command result for missing file] ***********************************
ok: [localhost] => {
    "msg": "Return code: 1\nSucceeded: False\nFailed: True\n"
}

PLAY RECAP ********************************************************************
localhost                  : ok=4    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=1

Remarquez comment le code de retour est 0 pour le fichier existant et 1 pour le fichier inexistant. Cela démontre comment vous pouvez utiliser les codes de retour pour prendre des décisions dans vos playbooks.

Comprendre la structure de la variable enregistrée

La variable enregistrée à partir d'une commande shell contient plusieurs attributs utiles :

  • stdout: La sortie standard sous forme de chaîne unique
  • stdout_lines: La sortie standard divisée en une liste de lignes
  • stderr: La sortie d'erreur standard sous forme de chaîne unique
  • stderr_lines: La sortie d'erreur standard divisée en une liste de lignes
  • rc: Le code de retour (0 pour le succès, non nul pour l'échec)
  • cmd: La commande qui a été exécutée
  • start et end: Horodatages pour le début et la fin de la commande
  • delta: La durée de l'exécution de la commande

Comprendre cette structure est crucial pour travailler efficacement avec la sortie des commandes shell dans Ansible.

Exécution conditionnelle basée sur la sortie shell

L'une des capacités les plus puissantes d'Ansible est la possibilité de prendre des décisions basées sur la sortie des commandes shell. Dans cette étape, nous allons apprendre à utiliser des conditions et des filtres pour traiter la sortie des commandes shell et rendre les playbooks plus dynamiques.

Utilisation des conditions avec la sortie shell

Créons un playbook qui prend des décisions basées sur la sortie des commandes shell :

  1. Créez un nouveau fichier appelé conditional_playbook.yml dans le répertoire /home/labex/project.
  2. Ajoutez le contenu suivant :
---
- name: Conditional Tasks Based on Command Output
  hosts: local
  gather_facts: no

  tasks:
    - name: Check disk space
      shell: df -h / | grep -v Filesystem | awk '{print $5}' | sed 's/%//'
      register: disk_usage

    - name: Display disk usage
      debug:
        msg: "Current disk usage: {{ disk_usage.stdout }}%"

    - name: Disk usage warning
      debug:
        msg: "WARNING: Disk usage is high"
      when: disk_usage.stdout|int > 50

    - name: Disk usage normal
      debug:
        msg: "Disk usage is normal"
      when: disk_usage.stdout|int <= 50

Ce playbook :

  • Exécute une commande shell pour vérifier le pourcentage d'utilisation du disque sur le système de fichiers racine
  • Utilise la condition when basée sur la sortie de la commande
  • Utilise le filtre int pour convertir la sortie de la chaîne en un entier pour la comparaison

Exécutez le playbook :

ansible-playbook -i inventory.ini conditional_playbook.yml

La sortie variera en fonction de votre utilisation réelle du disque, mais ressemblera à ceci :

PLAY [Conditional Tasks Based on Command Output] ******************************

TASK [Check disk space] *******************************************************
changed: [localhost]

TASK [Display disk usage] *****************************************************
ok: [localhost] => {
    "msg": "Current disk usage: 38%"
}

TASK [Disk usage warning] *****************************************************
skipped: [localhost]

TASK [Disk usage normal] ******************************************************
ok: [localhost] => {
    "msg": "Disk usage is normal"
}

PLAY RECAP ********************************************************************
localhost                  : ok=3    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

Remarquez comment Ansible a exécuté une seule des tâches conditionnelles en fonction de la valeur réelle de l'utilisation du disque.

Gestion de la sortie JSON des commandes

De nombreux outils CLI modernes renvoient des données au format JSON. Ansible possède des capacités intégrées pour gérer la sortie JSON :

  1. Créez un nouveau fichier appelé json_output.yml dans le répertoire /home/labex/project.
  2. Ajoutez le contenu suivant :
---
- name: Handling JSON Output
  hosts: local
  gather_facts: no

  tasks:
    - name: Create a JSON file for testing
      copy:
        dest: /tmp/services.json
        content: |
          {
            "services": [
              {
                "name": "web",
                "status": "running",
                "port": 80
              },
              {
                "name": "database",
                "status": "stopped",
                "port": 5432
              },
              {
                "name": "cache",
                "status": "running",
                "port": 6379
              }
            ]
          }

    - name: Read JSON file with shell
      shell: cat /tmp/services.json
      register: json_output

    - name: Parse and display JSON content
      debug:
        msg: "{{ json_output.stdout | from_json }}"

    - name: Extract and display service information
      debug:
        msg: "Service: {{ item.name }}, Status: {{ item.status }}, Port: {{ item.port }}"
      loop: "{{ (json_output.stdout | from_json).services }}"

    - name: Show only running services
      debug:
        msg: "Running service: {{ item.name }} on port {{ item.port }}"
      loop: "{{ (json_output.stdout | from_json).services }}"
      when: item.status == "running"

Ce playbook :

  • Crée un exemple de fichier JSON pour la démonstration
  • Lit le fichier JSON avec une commande shell
  • Utilise le filtre from_json pour analyser la chaîne JSON en une structure de données
  • Parcourt la structure de données pour afficher les informations
  • Utilise une logique conditionnelle pour filtrer uniquement les services en cours d'exécution

Exécutez le playbook :

ansible-playbook -i inventory.ini json_output.yml

Vous devriez voir une sortie similaire à ceci :

PLAY [Handling JSON Output] ***************************************************

TASK [Create a JSON file for testing] *****************************************
changed: [localhost]

TASK [Read JSON file with shell] **********************************************
changed: [localhost]

TASK [Parse and display JSON content] *****************************************
ok: [localhost] => {
    "msg": {
        "services": [
            {
                "name": "web",
                "port": 80,
                "status": "running"
            },
            {
                "name": "database",
                "port": 5432,
                "status": "stopped"
            },
            {
                "name": "cache",
                "port": 6379,
                "status": "running"
            }
        ]
    }
}

TASK [Extract and display service information] ********************************
ok: [localhost] => (item={'name': 'web', 'status': 'running', 'port': 80}) => {
    "msg": "Service: web, Status: running, Port: 80"
}
ok: [localhost] => (item={'name': 'database', 'status': 'stopped', 'port': 5432}) => {
    "msg": "Service: database, Status: stopped, Port: 5432"
}
ok: [localhost] => (item={'name': 'cache', 'status': 'running', 'port': 6379}) => {
    "msg": "Service: cache, Status: running, Port: 6379"
}

TASK [Show only running services] *********************************************
ok: [localhost] => (item={'name': 'web', 'status': 'running', 'port': 80}) => {
    "msg": "Running service: web on port 80"
}
skipped: [localhost] => (item={'name': 'database', 'status': 'stopped', 'port': 5432})
ok: [localhost] => (item={'name': 'cache', 'status': 'running', 'port': 6379}) => {
    "msg": "Running service: cache on port 6379"
}

PLAY RECAP ********************************************************************
localhost                  : ok=5    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Remarquez comment le playbook analyse le JSON, extrait des informations spécifiques et filtre les données en fonction des conditions.

Gestion des erreurs avec les commandes shell

Lors de l'exécution de commandes shell, il est important de gérer les erreurs potentielles avec élégance :

  1. Créez un nouveau fichier appelé error_handling.yml dans le répertoire /home/labex/project.
  2. Ajoutez le contenu suivant :
---
- name: Error Handling with Shell Commands
  hosts: local
  gather_facts: no

  tasks:
    - name: Run a potentially failing command
      shell: grep "nonexistent_pattern" /etc/passwd
      register: command_result
      ignore_errors: yes

    - name: Display success or failure
      debug:
        msg: "Command {{ 'succeeded' if command_result.rc == 0 else 'failed with return code ' + command_result.rc|string }}"

    - name: Run a custom failing command
      shell: exit 3
      register: exit_command
      ignore_errors: yes

    - name: Display detailed error information
      debug:
        msg: |
          Return code: {{ exit_command.rc }}
          Error message: {{ exit_command.stderr if exit_command.stderr else 'No error message' }}

Ce playbook :

  • Exécute des commandes qui sont censées échouer
  • Utilise ignore_errors: yes pour continuer l'exécution du playbook même lorsque les commandes échouent
  • Montre différentes méthodes pour gérer et afficher les informations d'erreur

Exécutez le playbook :

ansible-playbook -i inventory.ini error_handling.yml

Vous devriez voir une sortie similaire à ceci :

PLAY [Error Handling with Shell Commands] *************************************

TASK [Run a potentially failing command] **************************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": "grep \"nonexistent_pattern\" /etc/passwd", "delta": "0:00:00.002916", "end": "2023-07-14 16:10:23.671519", "msg": "non-zero return code", "rc": 1, "start": "2023-07-14 16:10:23.668603", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring

TASK [Display success or failure] *********************************************
ok: [localhost] => {
    "msg": "Command failed with return code 1"
}

TASK [Run a custom failing command] *******************************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": "exit 3", "delta": "0:00:00.002447", "end": "2023-07-14 16:10:23.906121", "msg": "non-zero return code", "rc": 3, "start": "2023-07-14 16:10:23.903674", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring

TASK [Display detailed error information] *************************************
ok: [localhost] => {
    "msg": "Return code: 3\nError message: No error message\n"
}

PLAY RECAP ********************************************************************
localhost                  : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=2

Cela démontre comment capturer et répondre à différentes conditions d'erreur lors de l'exécution de commandes shell.

Création d'un outil pratique de traitement de la sortie shell

Dans cette dernière étape, nous allons rassembler tout ce que nous avons appris pour créer un playbook Ansible pratique qui collecte des informations système, les traite et génère un rapport. Cela représente un scénario réel où les capacités de traitement des commandes shell d'Ansible peuvent être extrêmement utiles.

Construction d'un outil de rapport d'informations système

Créons un outil complet de collecte d'informations système :

  1. Créez un nouveau fichier appelé system_report.yml dans le répertoire /home/labex/project.
  2. Ajoutez le contenu suivant :
---
- name: Comprehensive System Report
  hosts: local
  gather_facts: no

  vars:
    report_file: /tmp/system_report.txt

  tasks:
    - name: Collect basic system information
      shell: |
        echo "SYSTEM REPORT" > {{ report_file }}
        echo "=============" >> {{ report_file }}
        echo "" >> {{ report_file }}

        echo "HOSTNAME: $(hostname)" >> {{ report_file }}
        echo "TIMESTAMP: $(date)" >> {{ report_file }}
        echo "" >> {{ report_file }}

        echo "SYSTEM INFORMATION" >> {{ report_file }}
        echo "------------------" >> {{ report_file }}
        echo "OS: $(cat /etc/os-release | grep PRETTY_NAME | cut -d= -f2)" >> {{ report_file }}
        echo "KERNEL: $(uname -r)" >> {{ report_file }}
        echo "UPTIME: $(uptime -p)" >> {{ report_file }}
        echo "" >> {{ report_file }}

        echo "RESOURCE UTILIZATION" >> {{ report_file }}
        echo "-------------------" >> {{ report_file }}
        echo "CPU LOAD: $(uptime | awk -F'load average:' '{print $2}')" >> {{ report_file }}
        echo "MEMORY USAGE:" >> {{ report_file }}
        free -h >> {{ report_file }}
        echo "" >> {{ report_file }}
        echo "DISK USAGE:" >> {{ report_file }}
        df -h >> {{ report_file }}
        echo "" >> {{ report_file }}

        echo "NETWORK INFORMATION" >> {{ report_file }}
        echo "-------------------" >> {{ report_file }}
        echo "IP ADDRESSES:" >> {{ report_file }}
        ip addr | grep "inet " | awk '{print $2}' >> {{ report_file }}
        echo "" >> {{ report_file }}

        echo "PROCESS INFORMATION" >> {{ report_file }}
        echo "-------------------" >> {{ report_file }}
        echo "TOP 5 CPU CONSUMING PROCESSES:" >> {{ report_file }}
        ps aux --sort=-%cpu | head -6 >> {{ report_file }}
        echo "" >> {{ report_file }}
        echo "TOP 5 MEMORY CONSUMING PROCESSES:" >> {{ report_file }}
        ps aux --sort=-%mem | head -6 >> {{ report_file }}
      register: report_generation

    - name: Check if report was generated successfully
      stat:
        path: "{{ report_file }}"
      register: report_stat

    - name: Display report generation status
      debug:
        msg: "Report generated successfully at {{ report_file }}"
      when: report_stat.stat.exists

    - name: Display report content
      shell: cat {{ report_file }}
      register: report_content
      when: report_stat.stat.exists

    - name: Show report content
      debug:
        msg: "{{ report_content.stdout_lines }}"
      when: report_stat.stat.exists

    - name: Analyze disk usage
      shell: df -h / | grep -v Filesystem | awk '{print $5}' | sed 's/%//'
      register: disk_usage
      when: report_stat.stat.exists

    - name: Generate disk usage alert if needed
      debug:
        msg: "ALERT: Disk usage on / is {{ disk_usage.stdout }}% which exceeds the 80% threshold!"
      when:
        - report_stat.stat.exists
        - disk_usage.stdout|int > 80

    - name: Generate disk usage warning if needed
      debug:
        msg: "WARNING: Disk usage on / is {{ disk_usage.stdout }}% which exceeds the 60% threshold."
      when:
        - report_stat.stat.exists
        - disk_usage.stdout|int > 60
        - disk_usage.stdout|int <= 80

    - name: Confirm normal disk usage
      debug:
        msg: "Disk usage on / is normal at {{ disk_usage.stdout }}%."
      when:
        - report_stat.stat.exists
        - disk_usage.stdout|int <= 60

Ce playbook :

  • Collecte des informations système complètes à l'aide d'une série de commandes shell
  • Écrit les informations dans un fichier de rapport
  • Vérifie que le rapport a été créé avec succès
  • Affiche le contenu du rapport
  • Analyse les données d'utilisation du disque
  • Génère des alertes appropriées en fonction de l'analyse

Exécutez le playbook :

ansible-playbook -i inventory.ini system_report.yml

Vous verrez une sortie complète montrant l'exécution du playbook et le rapport système complet. La sortie est assez longue, voici donc juste un exemple de ce que vous pourriez voir :

PLAY [Comprehensive System Report] ********************************************

TASK [Collect basic system information] ***************************************
changed: [localhost]

TASK [Check if report was generated successfully] *****************************
ok: [localhost]

TASK [Display report generation status] ***************************************
ok: [localhost] => {
    "msg": "Report generated successfully at /tmp/system_report.txt"
}

TASK [Display report content] *************************************************
changed: [localhost]

TASK [Show report content] ****************************************************
ok: [localhost] => {
    "msg": [
        "SYSTEM REPORT",
        "=============",
        "",
        "HOSTNAME: ubuntu-vm",
        "TIMESTAMP: Fri Jul 14 16:35:42 UTC 2023",
        "",
        "SYSTEM INFORMATION",
        "------------------",
        "OS: \"Ubuntu 22.04.1 LTS\"",
        "KERNEL: 5.15.0-1023-azure",
        "UPTIME: up 3 hours, 25 minutes",
        ...

Examen du rapport

Examinons le rapport système que nous avons généré :

cat /tmp/system_report.txt

Cela affichera le rapport complet qui a été généré par notre playbook.

Création d'un script shell personnalisé et appel depuis Ansible

Pour les opérations plus complexes, il est parfois plus facile de créer un script shell dédié et de l'appeler depuis Ansible :

  1. Créez un nouveau fichier appelé disk_analyzer.sh dans le répertoire /home/labex/project.
  2. Ajoutez le contenu suivant :
#!/bin/bash

## disk_analyzer.sh - A simple script to analyze disk usage

echo "DISK USAGE ANALYSIS"
echo "------------------"

## Get overall disk usage
ROOT_USAGE=$(df -h / | grep -v Filesystem | awk '{print $5}' | sed 's/%//')
echo "Root filesystem usage: ${ROOT_USAGE}%"

## Categorize the usage
if [ $ROOT_USAGE -gt 80 ]; then
  echo "STATUS: CRITICAL - Immediate action required"
elif [ $ROOT_USAGE -gt 60 ]; then
  echo "STATUS: WARNING - Consider cleaning up disk space"
else
  echo "STATUS: OK - Disk usage is within normal parameters"
fi

echo ""

## Find largest directories
echo "Top 5 largest directories in /var:"
du -h /var --max-depth=1 2> /dev/null | sort -hr | head -5

echo ""

## Find largest files
echo "Top 5 largest files in /var/log:"
find /var/log -type f -exec du -h {} \; 2> /dev/null | sort -hr | head -5

exit 0
  1. Rendez le script exécutable :
chmod +x /home/labex/project/disk_analyzer.sh
  1. Créez un nouveau playbook pour appeler ce script :
touch /home/labex/project/call_script.yml
  1. Ajoutez le contenu suivant au playbook :
---
- name: Call Custom Shell Script
  hosts: local
  gather_facts: no

  tasks:
    - name: Run disk analyzer script
      shell: /home/labex/project/disk_analyzer.sh
      register: script_output

    - name: Display script output
      debug:
        msg: "{{ script_output.stdout_lines }}"

    - name: Check for critical status
      debug:
        msg: "CRITICAL DISK USAGE DETECTED! Immediate action required."
      when: script_output.stdout is search("STATUS: CRITICAL")
  1. Exécutez le playbook :
ansible-playbook -i inventory.ini call_script.yml

Vous devriez voir une sortie similaire à ceci :

PLAY [Call Custom Shell Script] ***********************************************

TASK [Run disk analyzer script] ***********************************************
changed: [localhost]

TASK [Display script output] **************************************************
ok: [localhost] => {
    "msg": [
        "DISK USAGE ANALYSIS",
        "------------------",
        "Root filesystem usage: 38%",
        "STATUS: OK - Disk usage is within normal parameters",
        "",
        "Top 5 largest directories in /var:",
        "60M\t/var/lib",
        "60M\t/var/cache",
        "12M\t/var/log",
        "4.0K\t/var/tmp",
        "4.0K\t/var/mail",
        "",
        "Top 5 largest files in /var/log:",
        "4.0M\t/var/log/journal/c75af53674ce472fb9654a1d5cf8cc37/system.journal",
        "2.3M\t/var/log/auth.log",
        "1.3M\t/var/log/syslog",
        "724K\t/var/log/kern.log",
        "428K\t/var/log/cloud-init.log"
    ]
}

TASK [Check for critical status] **********************************************
skipped: [localhost]

PLAY RECAP ********************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

Cette approche combine la puissance des scripts shell avec les capacités d'automatisation d'Ansible. Le script shell gère la logique complexe pour l'analyse du disque, tandis qu'Ansible gère l'exécution et le traitement ultérieur des résultats.

Principaux points à retenir

Grâce à ce laboratoire, vous avez appris plusieurs techniques importantes pour travailler avec la sortie des commandes shell dans Ansible :

  1. Comment exécuter des commandes shell et capturer leur sortie
  2. Comment traiter et formater la sortie des commandes pour l'affichage
  3. Comment utiliser l'exécution conditionnelle basée sur les résultats des commandes
  4. Comment gérer la sortie JSON et les conditions d'erreur
  5. Comment créer des outils pratiques qui combinent les commandes shell avec les capacités d'automatisation d'Ansible

Ces compétences seront inestimables lorsque vous construirez des solutions d'automatisation plus complexes avec Ansible.

Résumé

Dans ce laboratoire, vous avez appris à travailler efficacement avec la sortie des commandes shell dans les playbooks Ansible. En commençant par les bases de l'exécution des commandes shell et de la capture de leur sortie, vous avez progressé vers des techniques plus avancées telles que l'exécution conditionnelle, la gestion des erreurs et le traitement des formats de données structurées comme JSON.

Vous avez maîtrisé plusieurs compétences clés :

  • Exécution de commandes shell dans les playbooks Ansible à l'aide du module shell
  • Capture de la sortie des commandes avec la directive register
  • Affichage de la sortie à l'aide du module debug
  • Traitement de la sortie avec les filtres et les conditions Jinja2
  • Création d'outils d'automatisation pratiques qui combinent Ansible avec des scripts shell

Ces techniques vous permettent de créer des flux de travail d'automatisation plus dynamiques et réactifs, capables de s'adapter à différentes conditions système et de fournir des commentaires utiles sur les opérations en cours.

Au fur et à mesure que vous poursuivez votre parcours Ansible, n'oubliez pas que, bien que les commandes shell offrent une grande flexibilité, les modules intégrés d'Ansible sont souvent une solution plus robuste et portable pour les tâches courantes. Utilisez les commandes shell lorsque vous devez exploiter des scripts shell existants ou effectuer des opérations complexes qui ne sont pas facilement gérées par les modules Ansible.