--- - name: Comprehensive Linux System Audit and Inventory hosts: all become: no gather_facts: yes strategy: free vars: audit_script_name: "comprehensive_discovery.sh" audit_script_path: "migration_scripts/discovery/comprehensive_discovery.sh" local_results_dir: "./audit_results" remote_script_path: "/tmp/{{ audit_script_name }}" ansible_ssh_retries: 5 ansible_timeout: 60 audit_timeout: 1800 # 30 minutes for audit execution audit_poll_interval: 60 # Check every 60 seconds pre_tasks: - name: Validate host connectivity ansible.builtin.ping: register: ping_result retries: 3 delay: 5 until: ping_result is success - name: Check available disk space ansible.builtin.command: df -h /tmp register: disk_space changed_when: false - name: Display disk space information ansible.builtin.debug: msg: "Available disk space on {{ inventory_hostname }}: {{ disk_space.stdout }}" tasks: - name: Create local results directory delegate_to: localhost become: no run_once: true ansible.builtin.file: path: "{{ local_results_dir }}" state: directory mode: '0755' - name: Install required packages with retry logic become: yes ansible.builtin.package: name: - net-tools - lsof - nmap - curl - wget - tree - ethtool - jq state: present register: package_install retries: 5 delay: 20 until: package_install is success ignore_errors: yes # Continue if some packages fail (e.g., not in repos) - name: Display package installation results ansible.builtin.debug: msg: "Package installation {{ 'succeeded' if package_install is success else 'had issues' }} on {{ inventory_hostname }}" - name: Ensure /tmp has correct permissions become: yes ansible.builtin.file: path: /tmp mode: '1777' state: directory - name: Copy audit script to remote host become: yes ansible.builtin.copy: src: "{{ audit_script_path }}" dest: "{{ remote_script_path }}" mode: '0755' backup: yes register: script_copy - name: Verify script copy ansible.builtin.stat: path: "{{ remote_script_path }}" register: script_stat - name: Display script information ansible.builtin.debug: msg: "Audit script copied to {{ inventory_hostname }}: {{ script_stat.stat.size }} bytes" - name: Run system audit script with enhanced timeout become: yes ansible.builtin.command: "bash {{ remote_script_path }}" args: chdir: /tmp register: audit_output async: "{{ audit_timeout }}" poll: "{{ audit_poll_interval }}" retries: 2 delay: 30 until: audit_output is success - name: Display audit execution status ansible.builtin.debug: msg: "Audit execution on {{ inventory_hostname }}: {{ 'completed' if audit_output is success else 'failed or timed out' }}" - name: Find the audit results archive ansible.builtin.find: paths: /tmp patterns: "system_audit_*.tar.gz" file_type: file register: audit_archives changed_when: false retries: 5 delay: 30 until: audit_archives.files | length > 0 - name: Set audit archive fact ansible.builtin.set_fact: audit_archive_path: "{{ (audit_archives.files | sort(attribute='mtime', reverse=true) | first).path }}" when: audit_archives.files | length > 0 - name: Create local host directory delegate_to: localhost become: no ansible.builtin.file: path: "{{ local_results_dir }}/{{ inventory_hostname }}" state: directory mode: '0755' when: audit_archive_path is defined - name: Fetch audit results archive with retry ansible.builtin.fetch: src: "{{ audit_archive_path }}" dest: "{{ local_results_dir }}/{{ inventory_hostname }}/" flat: yes when: audit_archive_path is defined register: fetch_result retries: 5 delay: 30 until: fetch_result is success failed_when: "fetch_result is failed and 'did not find' not in (fetch_result.msg | default(''))" - name: Extract compressed results locally delegate_to: localhost become: no ansible.builtin.unarchive: src: "{{ fetch_result.dest }}" dest: "{{ local_results_dir }}/{{ inventory_hostname }}/" remote_src: yes when: fetch_result.changed - name: Clean up remote audit files become: yes ansible.builtin.file: path: "{{ item }}" state: absent loop: - "{{ remote_script_path }}" - "{{ audit_archive_path }}" - "{{ audit_archive_path | regex_replace('.tar.gz$') }}" when: - cleanup_remote | default(false) - audit_archive_path is defined ignore_errors: yes # Don't fail if cleanup fails post_tasks: - name: Generate audit completion summary delegate_to: localhost become: no run_once: true ansible.builtin.debug: msg: | ======================================== COMPREHENSIVE DISCOVERY COMPLETE ======================================== Total hosts processed: {{ ansible_play_hosts_all | length }} Results are extracted in: {{ local_results_dir }}// Review the detailed logs and discovery files there. ========================================