--- - 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 | default(ansible_ssh_host | default('127.0.0.1'))) | 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 debug: msg: "No rotated log files found matching {{ archive_pattern }} in {{ log_directory }}" when: rotated_logs.matched == 0 - name: Generate empty report when no logs found copy: dest: "{{ output_file }}" content: >- { "hostname": "{{ ansible_hostname }}", "ip_address": "{{ ansible_default_ipv4.address | default(ansible_ssh_host | default('unknown')) }}", "os": "{{ ansible_distribution }} {{ ansible_distribution_version }}", "archive_date": "{{ ansible_date_time.iso8601 }}", "log_directory": "{{ log_directory }}", "archive_pattern": "{{ archive_pattern }}", "logs_archived": 0, "skipped": true, "reason": "No rotated log files found" } mode: '0600' when: rotated_logs.matched == 0 - meta: end_play 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 | default(ansible_ssh_host | default('127.0.0.1'))) | replace('.', '-') }}/{{ item.path | dirname | replace(log_directory, '') }}" && cp -p {{ item.path }} "{{ temp_archive_dir }}/{{ ansible_hostname }}/{{ ansible_date_time.date }}/{{ (ansible_default_ipv4.address | default(ansible_ssh_host | default('127.0.0.1'))) | 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 | default(ansible_ssh_host | default('unknown')) }}", "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 | default(ansible_ssh_host | default('unknown')) }}", "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 | default(ansible_ssh_host | default('unknown')) 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