commit 4b0559579e14a551d096665938f8dab6ae826046
parent f79470f43b47ee9727e2f18a4d584aa1517f9b2d
Author: Chris Roberts <chris.roberts@learningunix.net>
Date: Thu, 13 Aug 2026 06:05:43 -0500
added role to fetch server logs and view them
Diffstat:
8 files changed, 118 insertions(+), 0 deletions(-)
diff --git a/roles/log-sync/defaults/main.yml b/roles/log-sync/defaults/main.yml
@@ -0,0 +1,8 @@
+---
+log_sync_remote_host: learningunix.net
+log_sync_remote_user: cjr
+log_sync_ssh_key: "{{ ansible_facts['user_dir'] }}/.ssh/id_ed25519_logsync"
+log_sync_remote_paths:
+ - /var/log/nginx/
+log_sync_local_dest: "{{ ansible_facts['user_dir'] }}/learningunix-logs"
+log_sync_interval: daily
diff --git a/roles/log-sync/meta/main.yml b/roles/log-sync/meta/main.yml
@@ -0,0 +1,6 @@
+---
+galaxy_info:
+ author: cjr
+ description: Periodically pull learningunix.net server logs to this workstation
+ license: BSD-3-Clause
+ min_ansible_version: "2.1"
diff --git a/roles/log-sync/tasks/main.yml b/roles/log-sync/tasks/main.yml
@@ -0,0 +1,57 @@
+---
+- name: Load OS-specific package names
+ ansible.builtin.include_vars: "{{ ansible_facts['os_family'] }}.yml"
+
+- name: Install rsync and an SSH client
+ ansible.builtin.package:
+ name: "{{ log_sync_packages }}"
+ state: present
+ become: true
+
+- name: Ensure local bin directory exists
+ ansible.builtin.file:
+ path: "{{ ansible_facts['user_dir'] }}/.local/bin"
+ state: directory
+ mode: "0755"
+
+- name: Ensure log destination directory exists
+ ansible.builtin.file:
+ path: "{{ log_sync_local_dest }}"
+ state: directory
+ mode: "0700"
+
+- name: Deploy log pull script
+ ansible.builtin.template:
+ src: pull-logs.sh.j2
+ dest: "{{ ansible_facts['user_dir'] }}/.local/bin/pull-learningunix-logs.sh"
+ mode: "0755"
+
+- name: Ensure systemd user directory exists
+ ansible.builtin.file:
+ path: "{{ ansible_facts['user_dir'] }}/.config/systemd/user"
+ state: directory
+ mode: "0755"
+
+- name: Deploy systemd user service
+ ansible.builtin.template:
+ src: log-sync.service.j2
+ dest: "{{ ansible_facts['user_dir'] }}/.config/systemd/user/log-sync.service"
+ mode: "0644"
+
+- name: Deploy systemd user timer
+ ansible.builtin.template:
+ src: log-sync.timer.j2
+ dest: "{{ ansible_facts['user_dir'] }}/.config/systemd/user/log-sync.timer"
+ mode: "0644"
+
+- name: Reload systemd user units
+ ansible.builtin.systemd:
+ scope: user
+ daemon_reload: true
+
+- name: Enable and start the log-sync timer
+ ansible.builtin.systemd:
+ scope: user
+ name: log-sync.timer
+ enabled: true
+ state: started
diff --git a/roles/log-sync/templates/log-sync.service.j2 b/roles/log-sync/templates/log-sync.service.j2
@@ -0,0 +1,6 @@
+[Unit]
+Description=Pull learningunix.net server logs
+
+[Service]
+Type=oneshot
+ExecStart=%h/.local/bin/pull-learningunix-logs.sh
diff --git a/roles/log-sync/templates/log-sync.timer.j2 b/roles/log-sync/templates/log-sync.timer.j2
@@ -0,0 +1,9 @@
+[Unit]
+Description=Run learningunix.net log pull ({{ log_sync_interval }})
+
+[Timer]
+OnCalendar={{ log_sync_interval }}
+Persistent=true
+
+[Install]
+WantedBy=timers.target
diff --git a/roles/log-sync/templates/pull-logs.sh.j2 b/roles/log-sync/templates/pull-logs.sh.j2
@@ -0,0 +1,24 @@
+#!/bin/sh
+# Pulls learningunix.net server logs down to this workstation.
+# This machine is the rsync destination only — never writes back to the server.
+set -e
+
+mkdir -p "{{ log_sync_local_dest }}"
+
+{% for path in log_sync_remote_paths %}
+rsync -az -e "ssh -i {{ log_sync_ssh_key }} -o StrictHostKeyChecking=accept-new" \
+ "{{ log_sync_remote_user }}@{{ log_sync_remote_host }}:{{ path }}" \
+ "{{ log_sync_local_dest }}/"
+{% endfor %}
+
+# Regenerate the goaccess report from all available nginx access logs (current + rotated).
+# Normalized through zcat -f first: this goaccess build doesn't decompress .gz itself,
+# and zcat -f transparently handles both compressed and plain files.
+if command -v goaccess >/dev/null 2>&1; then
+ zcat -f {{ log_sync_local_dest }}/access.log* > {{ log_sync_local_dest }}/.combined-access.log 2>/dev/null
+ goaccess {{ log_sync_local_dest }}/.combined-access.log \
+ --log-format=COMBINED \
+ -o {{ log_sync_local_dest }}/report.html \
+ 2>/dev/null || true
+ rm -f {{ log_sync_local_dest }}/.combined-access.log
+fi
diff --git a/roles/log-sync/vars/Archlinux.yml b/roles/log-sync/vars/Archlinux.yml
@@ -0,0 +1,4 @@
+---
+log_sync_packages:
+ - rsync
+ - openssh
diff --git a/roles/log-sync/vars/Debian.yml b/roles/log-sync/vars/Debian.yml
@@ -0,0 +1,4 @@
+---
+log_sync_packages:
+ - rsync
+ - openssh-client