Add Ansible-based maintenance scripts for infrastructure operations: - CVE scanner using NIST NVD database - Package update checker with OpenAI risk assessment - Docker cleanup playbook - Log archiver for rotated logs - Disk space analyzer Supports Ubuntu 20.04/22.04/24.04, Debian 11/12/13, and Alpine Linux
177 lines
7.2 KiB
YAML
177 lines
7.2 KiB
YAML
---
|
|
- name: Archive and Send Rotated Logs
|
|
hosts: all
|
|
gather_facts: true
|
|
vars:
|
|
log_directory: "/var/log"
|
|
archive_pattern: "*.gz"
|
|
remote_storage_path: "{{ lookup('env', 'REMOTE_STORAGE_PATH') | default('/mnt/log-archive', true) }}"
|
|
temp_archive_dir: "/tmp/log_archive_{{ ansible_date_time.iso8601_basic_short }}"
|
|
local_temp_dir: "/tmp/received_logs_{{ ansible_date_time.iso8601_basic_short }}"
|
|
retention_days: 30
|
|
archive_filename: "logs_{{ ansible_hostname }}_{{ ansible_default_ipv4.address | replace('.', '-') }}_{{ ansible_date_time.date }}.tar.gz"
|
|
output_file: "/tmp/log_archive_report_{{ ansible_date_time.iso8601_basic_short }}.json"
|
|
|
|
tasks:
|
|
- name: Create temporary local directory for logs
|
|
file:
|
|
path: "{{ local_temp_dir }}"
|
|
state: directory
|
|
mode: '0700'
|
|
delegate_to: localhost
|
|
run_once: true
|
|
|
|
- name: Find rotated log files (gzipped)
|
|
find:
|
|
paths: "{{ log_directory }}"
|
|
patterns: "{{ archive_pattern }}"
|
|
recurse: true
|
|
register: rotated_logs
|
|
failed_when: false
|
|
|
|
- name: Check if rotated logs exist
|
|
fail:
|
|
msg: "No rotated log files found matching {{ archive_pattern }} in {{ log_directory }}"
|
|
when: rotated_logs.matched == 0
|
|
|
|
- name: Display found log files
|
|
debug:
|
|
msg: "Found {{ rotated_logs.matched }} rotated log files to archive"
|
|
|
|
- name: Create temporary archive directory
|
|
file:
|
|
path: "{{ temp_archive_dir }}"
|
|
state: directory
|
|
mode: '0700'
|
|
|
|
- name: Organize logs in temporary directory with metadata
|
|
shell: >-
|
|
mkdir -p "{{ temp_archive_dir }}/{{ ansible_hostname }}/{{ ansible_date_time.date }}/{{ ansible_default_ipv4.address | replace('.', '-') }}/{{ item.path | dirname | replace(log_directory, '') }}" &&
|
|
cp -p {{ item.path }} "{{ temp_archive_dir }}/{{ ansible_hostname }}/{{ ansible_date_time.date }}/{{ ansible_default_ipv4.address | replace('.', '-') }}/{{ item.path | dirname | replace(log_directory, '') }}/"
|
|
loop: "{{ rotated_logs.files }}"
|
|
loop_control:
|
|
loop_var: item
|
|
|
|
- name: Create metadata file for archive
|
|
copy:
|
|
dest: "{{ temp_archive_dir }}/metadata.json"
|
|
content: >-
|
|
{
|
|
"hostname": "{{ ansible_hostname }}",
|
|
"ip_address": "{{ ansible_default_ipv4.address }}",
|
|
"fqdn": "{{ ansible_fqdn }}",
|
|
"os": "{{ ansible_distribution }} {{ ansible_distribution_version }}",
|
|
"kernel": "{{ ansible_kernel }}",
|
|
"architecture": "{{ ansible_architecture }}",
|
|
"collection_date": "{{ ansible_date_time.iso8601 }}",
|
|
"log_files_count": {{ rotated_logs.matched }},
|
|
"source_directory": "{{ log_directory }}",
|
|
"archive_pattern": "{{ archive_pattern }}"
|
|
}
|
|
mode: '0644'
|
|
|
|
- name: Create tar archive of organized logs
|
|
archive:
|
|
path: "{{ temp_archive_dir }}/*"
|
|
dest: "/tmp/{{ archive_filename }}"
|
|
format: gz
|
|
mode: '0600'
|
|
|
|
- name: Calculate archive size
|
|
stat:
|
|
path: "/tmp/{{ archive_filename }}"
|
|
register: archive_stat
|
|
|
|
- name: Create remote storage directory structure
|
|
file:
|
|
path: "{{ remote_storage_path }}/{{ ansible_date_time.year }}/{{ ansible_date_time.month }}/{{ ansible_date_time.day }}"
|
|
state: directory
|
|
mode: '0755'
|
|
delegate_to: localhost
|
|
run_once: true
|
|
|
|
- name: Fetch archive to localhost
|
|
fetch:
|
|
src: "/tmp/{{ archive_filename }}"
|
|
dest: "{{ local_temp_dir }}/{{ archive_filename }}"
|
|
flat: true
|
|
|
|
- name: Copy archive to remote storage location
|
|
copy:
|
|
src: "{{ local_temp_dir }}/{{ archive_filename }}"
|
|
dest: "{{ remote_storage_path }}/{{ ansible_date_time.year }}/{{ ansible_date_time.month }}/{{ ansible_date_time.day }}/{{ archive_filename }}"
|
|
mode: '0644'
|
|
delegate_to: localhost
|
|
run_once: true
|
|
|
|
- name: Verify archive was transferred successfully
|
|
stat:
|
|
path: "{{ remote_storage_path }}/{{ ansible_date_time.year }}/{{ ansible_date_time.month }}/{{ ansible_date_time.day }}/{{ archive_filename }}"
|
|
register: remote_archive_stat
|
|
delegate_to: localhost
|
|
run_once: true
|
|
|
|
- name: Remove original rotated log files after successful transfer
|
|
file:
|
|
path: "{{ item.path }}"
|
|
state: absent
|
|
loop: "{{ rotated_logs.files }}"
|
|
loop_control:
|
|
loop_var: item
|
|
when: remote_archive_stat.stat.exists
|
|
|
|
- name: Clean up temporary directories
|
|
file:
|
|
path: "{{ item }}"
|
|
state: absent
|
|
loop:
|
|
- "{{ temp_archive_dir }}"
|
|
- "/tmp/{{ archive_filename }}"
|
|
failed_when: false
|
|
|
|
- name: Generate archive report
|
|
copy:
|
|
dest: "{{ output_file }}"
|
|
content: >-
|
|
{
|
|
"hostname": "{{ ansible_hostname }}",
|
|
"ip_address": "{{ ansible_default_ipv4.address }}",
|
|
"os": "{{ ansible_distribution }} {{ ansible_distribution_version }}",
|
|
"archive_date": "{{ ansible_date_time.iso8601 }}",
|
|
"log_directory": "{{ log_directory }}",
|
|
"archive_pattern": "{{ archive_pattern }}",
|
|
"logs_archived": {{ rotated_logs.matched }},
|
|
"archive_filename": "{{ archive_filename }}",
|
|
"archive_size_bytes": {{ archive_stat.stat.size | default(0) }},
|
|
"archive_size_human": "{{ archive_stat.stat.size | default(0) | human_readable }}",
|
|
"remote_storage_path": "{{ remote_storage_path }}/{{ ansible_date_time.year }}/{{ ansible_date_time.month }}/{{ ansible_date_time.day }}/{{ archive_filename }}",
|
|
"transfer_successful": {{ remote_archive_stat.stat.exists | default(false) }},
|
|
"original_logs_deleted": {{ remote_archive_stat.stat.exists | default(false) }}
|
|
}
|
|
mode: '0600'
|
|
|
|
- name: Display archive summary
|
|
debug:
|
|
msg:
|
|
- "Log archive completed on {{ ansible_hostname }}"
|
|
- "Files archived: {{ rotated_logs.matched }}"
|
|
- "Archive size: {{ archive_stat.stat.size | default(0) | human_readable }}"
|
|
- "Remote location: {{ remote_storage_path }}/{{ ansible_date_time.year }}/{{ ansible_date_time.month }}/{{ ansible_date_time.day }}/{{ archive_filename }}"
|
|
- "Transfer successful: {{ remote_archive_stat.stat.exists | default(false) }}"
|
|
- "Original logs deleted: {{ remote_archive_stat.stat.exists | default(false) }}"
|
|
- "Report saved to: {{ output_file }}"
|
|
|
|
- name: Return archive findings
|
|
set_fact:
|
|
log_archive_report:
|
|
hostname: ansible_hostname
|
|
ip_address: ansible_default_ipv4.address
|
|
os: ansible_distribution + ' ' + ansible_distribution_version
|
|
logs_archived: rotated_logs.matched
|
|
archive_filename: archive_filename
|
|
archive_size_bytes: archive_stat.stat.size | default(0)
|
|
remote_storage_path: "{{ remote_storage_path }}/{{ ansible_date_time.year }}/{{ ansible_date_time.month }}/{{ ansible_date_time.day }}/{{ archive_filename }}"
|
|
transfer_successful: remote_archive_stat.stat.exists | default(false)
|
|
archive_date: ansible_date_time.iso8601
|
|
report_file: output_file
|