---
# Сбор системных фактов со всех управляемых хостов и сохранение в JSON-файлы.
# Результаты публикуются как GitLab Pages через scripts/generate_report.py.
#
# Запуск:
#   ansible-playbook -i inventory/prod playbooks/gather_facts.yml
- name: Gather and save host facts
  hosts: all
  gather_facts: true
  ignore_unreachable: true

  vars:
    facts_output_dir: "{{ playbook_dir }}/../host_facts"

  tasks:
    - name: Собрать информацию об установленных пакетах
      ansible.builtin.package_facts:
        manager: auto
      failed_when: false

    - name: Собрать информацию о системных службах
      ansible.builtin.service_facts:
      failed_when: false

    - name: Получить открытые TCP/UDP порты
      ansible.builtin.command: ss -tlnup
      register: _ports_raw
      changed_when: false
      failed_when: false
      become: true

    - name: Получить правила firewalld (CentOS)
      ansible.builtin.command: firewall-cmd --list-all-zones
      register: _firewalld_raw
      changed_when: false
      failed_when: false
      become: true
      when: ansible_facts['distribution'] | default('') == 'CentOS'

    - name: Получить правила ufw (Debian)
      ansible.builtin.command: ufw status verbose
      register: _ufw_raw
      changed_when: false
      failed_when: false
      become: true
      when: ansible_facts['distribution'] | default('') == 'Debian'

    - name: Подготовить данные о портах и фаерволе
      ansible.builtin.set_fact:
        _network_security:
          ports_raw: "{{ _ports_raw.stdout | default('') }}"
          firewall_raw: >-
            {{
              _firewalld_raw.stdout | default('')
              if ansible_facts.get('distribution', '') == 'CentOS'
              else _ufw_raw.stdout | default('')
            }}

    - name: Инициализировать данные о Docker-контейнерах
      ansible.builtin.set_fact:
        _docker_info:
          containers: []

    - name: Проверить наличие Docker и получить ID запущенных контейнеров
      ansible.builtin.command: docker ps -q
      register: _docker_ids
      changed_when: false
      failed_when: false
      become: true

    - name: Получить детали запущенных Docker-контейнеров
      ansible.builtin.command: docker inspect {{ _docker_ids.stdout_lines | join(' ') }}
      register: _docker_inspect_raw
      changed_when: false
      failed_when: false
      become: true
      when:
        - _docker_ids.rc == 0
        - _docker_ids.stdout | trim | length > 0

    - name: Обновить данные о Docker-контейнерах
      ansible.builtin.set_fact:
        _docker_info:
          containers: "{{ _docker_inspect_raw.stdout | from_json }}"
      when:
        - _docker_inspect_raw is defined
        - _docker_inspect_raw is not skipped
        - _docker_inspect_raw.rc == 0
        - _docker_inspect_raw.stdout | default('') | trim | length > 0

    - name: Получить активные TCP-соединения к внешним хостам
      ansible.builtin.command: ss -tnp state established
      register: _connections_raw
      changed_when: false
      failed_when: false
      become: true

    - name: Получить список процессов с аргументами
      ansible.builtin.command: ps -eo pid,args --no-headers
      register: _ps_raw
      changed_when: false
      failed_when: false
      become: true

    - name: Подготовить данные об активных TCP-соединениях
      ansible.builtin.set_fact:
        _connections_info:
          connections_raw: "{{ _connections_raw.stdout | default('') }}"
          ps_raw: "{{ _ps_raw.stdout | default('') }}"

    - name: Получить таблицу conntrack (TCP и UDP)
      ansible.builtin.command: conntrack -L 2>/dev/null
      register: _conntrack_raw
      changed_when: false
      failed_when: false
      become: true

    - name: Подготовить данные conntrack
      ansible.builtin.set_fact:
        _conntrack_info:
          conntrack_raw: "{{ _conntrack_raw.stdout | default('') }}"

    - name: Создать локальную директорию для хранения фактов
      ansible.builtin.file:
        path: "{{ facts_output_dir }}"
        state: directory
        mode: "0755"
      delegate_to: localhost
      run_once: true
      become: false

    - name: Сохранить факты хоста в JSON
      ansible.builtin.copy:
        content: >-
          {{
            ansible_facts
            | combine({'inventory_hostname': inventory_hostname})
            | combine(_network_security)
            | combine(_docker_info)
            | combine(_connections_info)
            | combine(_conntrack_info)
            | to_nice_json
          }}
        dest: "{{ facts_output_dir }}/{{ inventory_hostname }}.json"
        mode: "0644"
      delegate_to: localhost
      become: false
