--- - name: Disk usage before maintenance ansible.builtin.shell: df -hT / | tail -1 register: disk_before changed_when: false - name: Show disk before ansible.builtin.debug: msg: "{{ inventory_hostname }} before: {{ disk_before.stdout }}" - name: Vacuum systemd journal ansible.builtin.command: "journalctl --vacuum-size={{ journal_max_size }}" register: journal_vacuum changed_when: "'Vacuuming done' in journal_vacuum.stdout" failed_when: false - name: Clean apt cache ansible.builtin.apt: autoclean: true autoremove: true clean: true when: apt_clean | bool - name: Check if docker is available ansible.builtin.command: docker info register: docker_info changed_when: false failed_when: false tags: [always, docker] - name: Truncate oversized Docker container logs ansible.builtin.shell: | set -o pipefail find /var/lib/docker/containers -name '*-json.log' -size +{{ docker_log_truncate_threshold }} \ -exec truncate -s {{ docker_log_truncate_target }} {} \; echo done args: executable: /bin/bash register: log_truncate changed_when: log_truncate.stdout is search('done') when: docker_info is defined and docker_info.rc == 0 - name: Prune stopped containers ansible.builtin.command: >- docker container prune -f --filter until={{ docker_prune_stopped_containers_older_than }} register: container_prune changed_when: "'Total reclaimed space' in container_prune.stdout and '0B' not in container_prune.stdout.split('Total reclaimed space')[1].split('\n')[0]" when: docker_info is defined and docker_info.rc == 0 - name: Prune dangling images ansible.builtin.command: docker image prune -f register: image_prune_dangling changed_when: "'Total reclaimed space' in image_prune_dangling.stdout and '0B' not in image_prune_dangling.stdout.split('Total reclaimed space')[1].split('\n')[0]" when: - docker_info is defined - docker_info.rc == 0 - docker_prune_dangling_images | bool - name: Prune unused images older than threshold ansible.builtin.command: >- docker image prune -af --filter until={{ docker_prune_unused_images_older_than }} register: image_prune_old changed_when: "'Total reclaimed space' in image_prune_old.stdout and '0B' not in image_prune_old.stdout.split('Total reclaimed space')[1].split('\n')[0]" when: - docker_info is defined - docker_info.rc == 0 - docker_prune_unused_images_older_than | length > 0 tags: - aggressive - name: Prune docker build cache ansible.builtin.command: >- docker builder prune -af --filter until={{ docker_prune_build_cache_older_than }} register: builder_prune changed_when: "'Total:' in builder_prune.stdout" failed_when: false when: docker_info is defined and docker_info.rc == 0 - name: Prune dangling docker volumes ansible.builtin.command: docker volume prune -f register: volume_prune changed_when: "'Total reclaimed space' in volume_prune.stdout and '0B' not in volume_prune.stdout.split('Total reclaimed space')[1].split('\n')[0]" when: - docker_info is defined - docker_info.rc == 0 - docker_prune_dangling_volumes | bool - name: Check for existing Docker daemon.json ansible.builtin.stat: path: /etc/docker/daemon.json register: docker_daemon_json when: docker_info is defined and docker_info.rc == 0 - name: Ensure Docker log rotation defaults ansible.builtin.copy: dest: /etc/docker/daemon.json owner: root group: root mode: "0644" force: false content: | { "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } } notify: Restart docker when: - docker_info is defined - docker_info.rc == 0 - not docker_daemon_json.stat.exists - name: Remove old Frigate recording day folders ansible.builtin.shell: | set -euo pipefail retain={{ frigate_recordings_retain_days }} cutoff=$(date -d "-${retain} days" +%Y-%m-%d) removed=0 for d in "{{ frigate_recordings_path }}"/20??-??-??; do [ -d "$d" ] || continue day=$(basename "$d") if [[ "$day" < "$cutoff" ]]; then rm -rf "$d" echo "removed $day" removed=1 fi done [ "$removed" -eq 0 ] || true args: executable: /bin/bash register: frigate_recording_cleanup changed_when: frigate_recording_cleanup.stdout | length > 0 when: - frigate_recordings_path is defined - frigate_recordings_path | length > 0 tags: - frigate - name: Remove old Frigate clip previews ansible.builtin.find: paths: "{{ frigate_clips_path | default('') }}/previews" age: "{{ frigate_clips_retain_days }}d" file_type: any recurse: true register: old_frigate_clips when: - frigate_clips_path is defined - frigate_clips_path | length > 0 - name: Delete old Frigate clip files ansible.builtin.file: path: "{{ item.path }}" state: absent loop: "{{ old_frigate_clips.files | default([]) }}" when: - frigate_clips_path is defined - frigate_clips_path | length > 0 loop_control: label: "{{ item.path }}" tags: - frigate - name: Clean stale Jellyfin cache files ansible.builtin.find: paths: "{{ jellyfin_cache_path | default('') }}" age: "{{ jellyfin_cache_max_age_days }}d" file_type: file recurse: true register: old_jellyfin_cache when: - jellyfin_cache_path is defined - jellyfin_cache_path | length > 0 - name: Delete stale Jellyfin cache ansible.builtin.file: path: "{{ item.path }}" state: absent loop: "{{ old_jellyfin_cache.files | default([]) }}" when: - jellyfin_cache_path is defined - jellyfin_cache_path | length > 0 loop_control: label: "{{ item.path }}" tags: - jellyfin - name: Clean npm cache on dev hosts ansible.builtin.command: npm cache clean --force when: - dev_tooling_cleanup | default(false) | bool - npm_cache_clean | bool changed_when: true failed_when: false tags: - dev-tooling - name: Run fstrim on root filesystem ansible.builtin.command: fstrim -v / register: fstrim_result changed_when: "'trimmed' in fstrim_result.stdout and '0 B' not in fstrim_result.stdout" when: fstrim_enabled | bool - name: Docker disk summary ansible.builtin.command: docker system df register: docker_df changed_when: false failed_when: false when: docker_info is defined and docker_info.rc == 0 - name: Disk usage after maintenance ansible.builtin.shell: df -hT / | tail -1 register: disk_after changed_when: false - name: Maintenance summary ansible.builtin.debug: msg: | {{ inventory_hostname }}: before: {{ disk_before.stdout }} after: {{ disk_after.stdout }} fstrim: {{ fstrim_result.stdout | default('skipped') }} docker: {{ docker_df.stdout | default('n/a') }}