diff --git a/ansible/roles/podman/defaults/main.yml b/ansible/roles/podman/defaults/main.yml index 9d195ea..b1919fd 100644 --- a/ansible/roles/podman/defaults/main.yml +++ b/ansible/roles/podman/defaults/main.yml @@ -83,6 +83,13 @@ zomboid_mods_excluded: mod_id: IconsInventory reason: Sophie recommends removing Icon Inventory +# How long to keep PZ's own log archive under data/Logs. +# +# PZ rolls logs into dated directories and never prunes them; logrotate cannot +# bound that, because the growth is in the number of files rather than the size +# of any one of them. See containers/home/zomboid.yml. +zomboid_log_retention_days: 14 + # Mod IDs the Sophie preset's `Mods=` line gets wrong for a 42.20.3 server. # # Every workshop item below is in the preset's own WorkshopItems= list and diff --git a/ansible/roles/podman/tasks/containers/home/zomboid.yml b/ansible/roles/podman/tasks/containers/home/zomboid.yml index 6f4dc79..b6dbc2e 100644 --- a/ansible/roles/podman/tasks/containers/home/zomboid.yml +++ b/ansible/roles/podman/tasks/containers/home/zomboid.yml @@ -174,6 +174,38 @@ notify: restorecon podman tags: zomboid-conf +- name: deploy zomboid log prune script + become: true + ansible.builtin.template: + src: zomboid/zomboid-log-prune.sh.j2 + dest: "{{ podman_home }}/bin/zomboid-log-prune.sh" + owner: "{{ podman_user }}" + group: "{{ podman_user }}" + mode: '0755' + +- name: deploy zomboid log prune units + become: true + ansible.builtin.template: + src: "zomboid/zomboid-log-prune.{{ item }}.j2" + dest: "{{ podman_home }}/.config/systemd/user/zomboid-log-prune.{{ item }}" + owner: "{{ podman_user }}" + group: "{{ podman_user }}" + mode: '0644' + loop: + - service + - timer + notify: reload zomboid systemd + +- name: enable zomboid log prune timer + become: true + become_user: "{{ podman_user }}" + ansible.builtin.systemd: + name: zomboid-log-prune.timer + scope: user + enabled: true + state: started + daemon_reload: true + # The server's own logs, not the container's. PZ holds these fds open for the # life of the process, so copytruncate is mandatory -- a rename would leave it # writing into an unlinked inode and the file would appear to stop growing. diff --git a/ansible/roles/podman/tasks/main.yml b/ansible/roles/podman/tasks/main.yml index 9d80831..370812f 100644 --- a/ansible/roles/podman/tasks/main.yml +++ b/ansible/roles/podman/tasks/main.yml @@ -123,7 +123,7 @@ - import_tasks: containers/home/gregtime.yml vars: - image: localhost/greg-time-bot:3.14.1 + image: localhost/greg-time-bot:3.15.0 tags: gregtime # Gated on zomboid_enabled (roles/podman/defaults/main.yml) so it can be taken diff --git a/ansible/roles/podman/templates/zomboid/logrotate.j2 b/ansible/roles/podman/templates/zomboid/logrotate.j2 index e62cacf..b3fd2d0 100644 --- a/ansible/roles/podman/templates/zomboid/logrotate.j2 +++ b/ansible/roles/podman/templates/zomboid/logrotate.j2 @@ -1,7 +1,13 @@ # {{ ansible_managed }} # -# Project Zomboid's own log files. These are separate from the container's -# stdout, which podman rotates itself via the k8s-file driver's max_size. +# Project Zomboid's server console, which is a single ever-growing file. This is +# separate from the container's stdout, which podman rotates itself via the +# k8s-file driver's max_size. +# +# Scope is deliberately just this file. PZ's other logs live in dated +# directories under Logs/ that grow in file *count*, not file size, so nothing +# there ever crosses a rotation threshold -- those are pruned by age instead, +# via zomboid-log-prune.timer. # # copytruncate is mandatory here: the server holds these fds open for the whole # life of the process, so a rename would leave it writing into an unlinked @@ -10,7 +16,6 @@ # The Discord bot tails server-console.txt from a byte offset and resets that # offset when the file shrinks, so a truncate under it is safe. {{ zomboid_path }}/data/server-console.txt -{{ zomboid_path }}/data/Logs/*.txt { # size, not a time directive: logrotate's daily timer is when this is # *checked*, 100M is when it actually rotates. Specifying both makes diff --git a/ansible/roles/podman/templates/zomboid/zomboid-log-prune.service.j2 b/ansible/roles/podman/templates/zomboid/zomboid-log-prune.service.j2 new file mode 100644 index 0000000..1777550 --- /dev/null +++ b/ansible/roles/podman/templates/zomboid/zomboid-log-prune.service.j2 @@ -0,0 +1,6 @@ +[Unit] +Description=Prune Zomboid log archive older than {{ zomboid_log_retention_days }} days + +[Service] +Type=oneshot +ExecStart={{ podman_home }}/bin/zomboid-log-prune.sh diff --git a/ansible/roles/podman/templates/zomboid/zomboid-log-prune.sh.j2 b/ansible/roles/podman/templates/zomboid/zomboid-log-prune.sh.j2 new file mode 100644 index 0000000..1cb15b1 --- /dev/null +++ b/ansible/roles/podman/templates/zomboid/zomboid-log-prune.sh.j2 @@ -0,0 +1,24 @@ +#!/bin/bash +# Prune Project Zomboid's own log archive. +# +# PZ rolls its logs into dated directories under Logs/ (logs_YYYY-MM-DD/, plus +# loose YYYY-MM-DD_HH-MM_*.txt at the top) and never removes them. That is not +# something logrotate can bound: it rotates by size, and no individual file here +# ever reaches a sensible threshold -- the growth is in the *number* of files. +# 112 directories and 146k files had accumulated to 18 GB before this existed. +# +# Files are owned by the container's UID, so this runs under podman unshare. +set -euo pipefail + +LOGS="{{ zomboid_path }}/data/Logs" +DAYS={{ zomboid_log_retention_days }} + +[[ -d "$LOGS" ]] || exit 0 + +before=$(podman unshare du -sh "$LOGS" 2>/dev/null | cut -f1) +podman unshare find "$LOGS" -type f -mtime +"$DAYS" -delete 2>/dev/null || true +# Second pass: the dated directories are empty once their files are gone. +podman unshare find "$LOGS" -mindepth 1 -type d -empty -delete 2>/dev/null || true +after=$(podman unshare du -sh "$LOGS" 2>/dev/null | cut -f1) + +echo "zomboid log prune: keeping ${DAYS}d, ${before} -> ${after}" diff --git a/ansible/roles/podman/templates/zomboid/zomboid-log-prune.timer.j2 b/ansible/roles/podman/templates/zomboid/zomboid-log-prune.timer.j2 new file mode 100644 index 0000000..0412ade --- /dev/null +++ b/ansible/roles/podman/templates/zomboid/zomboid-log-prune.timer.j2 @@ -0,0 +1,10 @@ +[Unit] +Description=Prune the Zomboid log archive daily + +[Timer] +OnCalendar=daily +Persistent=true +RandomizedDelaySec=30m + +[Install] +WantedBy=timers.target