Files
homelab-optimized/ansible/automation/playbooks/disk_usage_report.yml
Gitea Mirror Bot 32abef4132
Some checks failed
Documentation / Build Docusaurus (push) Failing after 5m4s
Documentation / Deploy to GitHub Pages (push) Has been skipped
Sanitized mirror from private repository - 2026-04-19 15:28:05 UTC
2026-04-19 15:28:05 +00:00

312 lines
12 KiB
YAML

---
# 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