--- # Disk Usage Report Playbook # Monitor storage usage across all hosts and generate comprehensive reports # Usage: ansible-playbook playbooks/disk_usage_report.yml # Usage: ansible-playbook playbooks/disk_usage_report.yml -e "alert_threshold=80" # Usage: ansible-playbook playbooks/disk_usage_report.yml -e "detailed_analysis=true" - name: Generate Comprehensive Disk Usage Report hosts: "{{ host_target | default('all') }}" gather_facts: yes vars: alert_threshold: "{{ alert_threshold | default(85) }}" warning_threshold: "{{ warning_threshold | default(75) }}" detailed_analysis: "{{ detailed_analysis | default(false) }}" report_dir: "/tmp/disk_reports" include_docker_analysis: "{{ include_docker_analysis | default(true) }}" top_directories_count: "{{ top_directories_count | default(10) }}" tasks: - name: Create report directory file: path: "{{ report_dir }}/{{ ansible_date_time.date }}" state: directory mode: '0755' delegate_to: localhost - name: Get basic disk usage shell: df -h register: disk_usage_basic changed_when: false - name: Get disk usage percentages shell: df --output=source,pcent,avail,target | grep -v "Filesystem" register: disk_usage_percent changed_when: false - name: Identify high usage filesystems shell: | df --output=source,pcent,target | awk 'NR>1 {gsub(/%/, "", $2); if ($2 >= {{ alert_threshold }}) print $0}' register: high_usage_filesystems changed_when: false - name: Get inode usage shell: df -i register: inode_usage changed_when: false - name: Analyze Docker storage usage shell: | echo "=== DOCKER STORAGE ANALYSIS ===" if command -v docker &> /dev/null; then echo "Docker System Usage:" docker system df 2>/dev/null || echo "Cannot access Docker" echo "" echo "Container Sizes:" docker ps --format "table {{.Names}}\t{{.Size}}" 2>/dev/null || echo "Cannot access Docker containers" echo "" echo "Image Sizes:" docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" 2>/dev/null | head -20 || echo "Cannot access Docker images" echo "" echo "Volume Usage:" docker volume ls -q | xargs -I {} sh -c 'echo "Volume: {}"; docker volume inspect {} --format "{{.Mountpoint}}" | xargs du -sh 2>/dev/null || echo "Cannot access volume"' 2>/dev/null || echo "Cannot access Docker volumes" else echo "Docker not available" fi register: docker_storage_analysis when: include_docker_analysis | bool changed_when: false - name: Find largest directories shell: | echo "=== TOP {{ top_directories_count }} LARGEST DIRECTORIES ===" # Find largest directories in common locations for path in / /var /opt /home /volume1 /volume2; do if [ -d "$path" ]; then echo "=== $path ===" du -h "$path"/* 2>/dev/null | sort -hr | head -{{ top_directories_count }} || echo "Cannot analyze $path" echo "" fi done register: largest_directories when: detailed_analysis | bool changed_when: false - name: Analyze log file sizes shell: | echo "=== LOG FILE ANALYSIS ===" # System logs echo "System Logs:" find /var/log -type f -name "*.log" -exec du -h {} \; 2>/dev/null | sort -hr | head -10 || echo "Cannot access system logs" echo "" # Docker logs echo "Docker Container Logs:" if [ -d "/var/lib/docker/containers" ]; then find /var/lib/docker/containers -name "*-json.log" -exec du -h {} \; 2>/dev/null | sort -hr | head -10 || echo "Cannot access Docker logs" fi echo "" # Application logs echo "Application Logs:" find /volume1 /opt -name "*.log" -type f -exec du -h {} \; 2>/dev/null | sort -hr | head -10 || echo "No application logs found" register: log_analysis when: detailed_analysis | bool changed_when: false - name: Check for large files shell: | echo "=== LARGE FILES (>1GB) ===" find / -type f -size +1G -exec du -h {} \; 2>/dev/null | sort -hr | head -20 || echo "No large files found or permission denied" register: large_files when: detailed_analysis | bool changed_when: false - name: Analyze temporary files shell: | echo "=== TEMPORARY FILES ANALYSIS ===" for temp_dir in /tmp /var/tmp /volume1/tmp; do if [ -d "$temp_dir" ]; then echo "=== $temp_dir ===" du -sh "$temp_dir" 2>/dev/null || echo "Cannot access $temp_dir" echo "File count: $(find "$temp_dir" -type f 2>/dev/null | wc -l)" echo "Oldest file: $(find "$temp_dir" -type f -printf '%T+ %p\n' 2>/dev/null | sort | head -1 | cut -d' ' -f2- || echo 'None')" echo "" fi done register: temp_files_analysis changed_when: false - name: Generate disk usage alerts set_fact: disk_alerts: [] disk_warnings: [] - name: Process disk usage alerts set_fact: disk_alerts: "{{ disk_alerts + [item] }}" loop: "{{ disk_usage_percent.stdout_lines }}" when: - item.split()[1] | regex_replace('%', '') | int >= alert_threshold | int vars: usage_percent: "{{ item.split()[1] | regex_replace('%', '') | int }}" - name: Process disk usage warnings set_fact: disk_warnings: "{{ disk_warnings + [item] }}" loop: "{{ disk_usage_percent.stdout_lines }}" when: - item.split()[1] | regex_replace('%', '') | int >= warning_threshold | int - item.split()[1] | regex_replace('%', '') | int < alert_threshold | int - name: Create comprehensive report copy: content: | ๐Ÿ“Š DISK USAGE REPORT - {{ inventory_hostname }} ============================================= ๐Ÿ“… Generated: {{ ansible_date_time.iso8601 }} ๐Ÿ–ฅ๏ธ Host: {{ inventory_hostname }} ๐Ÿ’ฟ OS: {{ ansible_distribution }} {{ ansible_distribution_version }} โš ๏ธ Alert Threshold: {{ alert_threshold }}% โšก Warning Threshold: {{ warning_threshold }}% ๐Ÿšจ CRITICAL ALERTS (>={{ alert_threshold }}%): {% if disk_alerts | length > 0 %} {% for alert in disk_alerts %} โŒ {{ alert }} {% endfor %} {% else %} โœ… No critical disk usage alerts {% endif %} โš ๏ธ WARNINGS (>={{ warning_threshold }}%): {% if disk_warnings | length > 0 %} {% for warning in disk_warnings %} ๐ŸŸก {{ warning }} {% endfor %} {% else %} โœ… No disk usage warnings {% endif %} ๐Ÿ’พ FILESYSTEM USAGE: {{ disk_usage_basic.stdout }} ๐Ÿ“ INODE USAGE: {{ inode_usage.stdout }} ๐Ÿงน TEMPORARY FILES: {{ temp_files_analysis.stdout }} {% if include_docker_analysis and docker_storage_analysis.stdout is defined %} ๐Ÿณ DOCKER STORAGE: {{ docker_storage_analysis.stdout }} {% endif %} {% if detailed_analysis %} {% if largest_directories.stdout is defined %} ๐Ÿ“‚ LARGEST DIRECTORIES: {{ largest_directories.stdout }} {% endif %} {% if log_analysis.stdout is defined %} ๐Ÿ“ LOG FILES: {{ log_analysis.stdout }} {% endif %} {% if large_files.stdout is defined %} ๐Ÿ“ฆ LARGE FILES: {{ large_files.stdout }} {% endif %} {% endif %} ๐Ÿ’ก RECOMMENDATIONS: {% if disk_alerts | length > 0 %} - ๐Ÿšจ IMMEDIATE ACTION REQUIRED: Clean up filesystems above {{ alert_threshold }}% {% endif %} {% if disk_warnings | length > 0 %} - โš ๏ธ Monitor filesystems above {{ warning_threshold }}% {% endif %} - ๐Ÿงน Run cleanup playbook: ansible-playbook playbooks/cleanup_old_backups.yml - ๐Ÿณ Prune Docker: ansible-playbook playbooks/prune_containers.yml - ๐Ÿ“ Rotate logs: ansible-playbook playbooks/log_rotation.yml - ๐Ÿ—‘๏ธ Clean temp files: find /tmp -type f -mtime +7 -delete ๐Ÿ“Š SUMMARY: - Total Filesystems: {{ disk_usage_percent.stdout_lines | length }} - Critical Alerts: {{ disk_alerts | length }} - Warnings: {{ disk_warnings | length }} - Docker Analysis: {{ 'Included' if include_docker_analysis else 'Skipped' }} - Detailed Analysis: {{ 'Included' if detailed_analysis else 'Skipped' }} dest: "{{ report_dir }}/{{ ansible_date_time.date }}/{{ inventory_hostname }}_disk_report.txt" delegate_to: localhost - name: Create JSON report for automation copy: content: | { "timestamp": "{{ ansible_date_time.iso8601 }}", "hostname": "{{ inventory_hostname }}", "thresholds": { "alert": {{ alert_threshold }}, "warning": {{ warning_threshold }} }, "alerts": {{ disk_alerts | to_json }}, "warnings": {{ disk_warnings | to_json }}, "filesystems": {{ disk_usage_percent.stdout_lines | to_json }}, "summary": { "total_filesystems": {{ disk_usage_percent.stdout_lines | length }}, "critical_count": {{ disk_alerts | length }}, "warning_count": {{ disk_warnings | length }}, "status": "{% if disk_alerts | length > 0 %}CRITICAL{% elif disk_warnings | length > 0 %}WARNING{% else %}OK{% endif %}" } } dest: "{{ report_dir }}/{{ ansible_date_time.date }}/{{ inventory_hostname }}_disk_report.json" delegate_to: localhost - name: Display summary debug: msg: | ๐Ÿ“Š DISK USAGE REPORT COMPLETE - {{ inventory_hostname }} ================================================ {% if disk_alerts | length > 0 %} ๐Ÿšจ CRITICAL ALERTS: {{ disk_alerts | length }} {% for alert in disk_alerts %} โŒ {{ alert }} {% endfor %} {% endif %} {% if disk_warnings | length > 0 %} โš ๏ธ WARNINGS: {{ disk_warnings | length }} {% for warning in disk_warnings %} ๐ŸŸก {{ warning }} {% endfor %} {% endif %} {% if disk_alerts | length == 0 and disk_warnings | length == 0 %} โœ… All filesystems within normal usage levels {% endif %} ๐Ÿ“„ Reports saved to: - {{ report_dir }}/{{ ansible_date_time.date }}/{{ inventory_hostname }}_disk_report.txt - {{ report_dir }}/{{ ansible_date_time.date }}/{{ inventory_hostname }}_disk_report.json ๐Ÿ” Next Steps: {% if disk_alerts | length > 0 %} - Run cleanup: ansible-playbook playbooks/cleanup_old_backups.yml - Prune Docker: ansible-playbook playbooks/prune_containers.yml {% endif %} - Schedule regular monitoring via cron ================================================ - name: Send alert if critical usage detected debug: msg: | ๐Ÿšจ CRITICAL DISK USAGE ALERT ๐Ÿšจ Host: {{ inventory_hostname }} Critical filesystems: {{ disk_alerts | length }} Immediate action required! when: - disk_alerts | length > 0 - send_alerts | default(false) | bool