--- # Collect timestamped journald logs and a support snapshot from one approved wave. - name: Collect support logs hosts: "{{ operation_wave | default('invalid-wave', true) }}" gather_facts: false become: true vars: approved_operation_waves: [lab, pilot_1, pilot_2, wave_1, wave_2, production] production_override: false collect_logs_dir: "{{ support_bundle_dir | default('/var/lib/blueforce/support-bundles') }}" collect_log_lines: "{{ log_lines | default(500) }}" fetch_logs: false pre_tasks: - name: Require confirmed approved operation wave scope ansible.builtin.assert: that: - operation_wave in approved_operation_waves - operation_confirmed | bool - operation_wave in groups - ansible_play_hosts_all | length > 0 - ansible_play_hosts_all | difference(groups[operation_wave]) | length == 0 fail_msg: "Set operation_wave to one inventory wave and operation_confirmed=true; full-fleet scope is refused." run_once: true - name: Require a safe support bundle directory ansible.builtin.assert: that: - collect_logs_dir is match('^/var/lib/blueforce/support-bundles(?:/[A-Za-z0-9][A-Za-z0-9._-]*)*\Z') fail_msg: "support_bundle_dir must be /var/lib/blueforce/support-bundles or an approved alphanumeric subpath; shell metacharacters are refused." run_once: true - name: Require separate production override ansible.builtin.assert: that: - operation_wave != 'production' or production_override | bool fail_msg: "Production operation requires production_override=true in addition to operation_confirmed=true." run_once: true tasks: - name: Generate unique bundle timestamp ansible.builtin.command: date -u +%Y%m%dT%H%M%SZ register: bundle_timestamp changed_when: false - name: Ensure bundle directory exists ansible.builtin.file: path: "{{ collect_logs_dir }}" state: directory owner: root group: root mode: "0750" - name: Export recent journal to timestamped bundle ansible.builtin.shell: >- journalctl -n {{ collect_log_lines | int }} --no-pager > {{ (collect_logs_dir ~ '/journal-' ~ inventory_hostname ~ '-' ~ bundle_timestamp.stdout ~ '.log') | quote }} changed_when: true - name: Record timestamped kernel and disk snapshot ansible.builtin.shell: >- { uname -a; printf '%s\\n' '---'; df -h; printf '%s\\n' '---'; uptime; } > {{ (collect_logs_dir ~ '/snapshot-' ~ inventory_hostname ~ '-' ~ bundle_timestamp.stdout ~ '.txt') | quote }} changed_when: true - name: Fetch timestamped journal bundle to controller ansible.builtin.fetch: src: "{{ collect_logs_dir }}/journal-{{ inventory_hostname }}-{{ bundle_timestamp.stdout }}.log" dest: "fetched-logs/{{ inventory_hostname }}/" flat: true when: fetch_logs | bool