--- - name: "Сканирование сети через SNMP (Community: public)" hosts: localhost connection: local gather_facts: no # become: yes <--- УБРАЛИ ОТСЮДА (Глобальный sudo вызывает ошибку прав) vars: # --- SEMAPHORE API --- semaphore_url: "http://192.168.0.198:9999" semaphore_project_id: 1 semaphore_api_token: "9ojexqiwt1xkemig7j1bd1pe-frh7hkre4reryk2occ=" # --- ID КЛЮЧЕЙ --- key_windows: 7 key_linux: 8 key_mikrotik: 9 key_printers: 7 # --- СЕТИ --- subnets: - "192.168.0.0/24" - "192.168.0.0/23" - "192.168.2.0/24" - "192.168.3.0/24" - "172.19.8.0/24" - "172.19.9.0/24" - "172.19.10.0/24" - "172.19.24.0/24" - "172.19.26.0/24" - "172.19.40.0/24" - "172.19.42.0/24" - "172.19.56.0/24" - "172.19.58.0/24" - "172.19.90.0/24" snmp_community: "public" tasks: # ---------------------------------------------------------------- # ШАГ 1: Поиск живых хостов # ---------------------------------------------------------------- - name: Ping Sweep (быстрый поиск) command: "nmap -sn -n --min-rate 1000 -T4 -oG - {{ subnets | join(' ') }}" become: yes # <--- ДОБАВИЛИ СЮДА (Точечно) register: ping_scan changed_when: false - name: Формирование списка активных IP set_fact: active_ips: "{{ ping_scan.stdout | regex_findall('Host: ([0-9.]+)') | unique | list }}" - name: Проверка наличия хостов fail: msg: "Сеть пуста, активных хостов не найдено." when: active_ips | length == 0 # ---------------------------------------------------------------- # ШАГ 2: Опрос через SNMP # ---------------------------------------------------------------- - name: SNMP Discovery shell: | nmap -sU -sS -p U:161,T:22,T:445,T:8291,T:9100 \ --script snmp-sysdescr \ --script-args snmpcommunity={{ snmp_community }} \ -Pn -n -T4 {{ item }} become: yes # <--- ДОБАВИЛИ СЮДА (Точечно, т.к. UDP скан требует root) loop: "{{ active_ips }}" register: scan_results changed_when: false # ---------------------------------------------------------------- # ШАГ 3: Классификация # ---------------------------------------------------------------- - name: Анализ устройств и классификация set_fact: classified_hosts: "{{ classified_hosts | default([]) + [ host_data ] }}" vars: out: "{{ item.stdout }}" ip: "{{ item.item }}" snmp_desc: "{{ out | regex_search('sysDescr\\.0: ([^\\n]+)', '\\1') | first | default('') }}" detected_type: >- {% if 'Windows' in snmp_desc or '445/tcp open' in out %}windows {% elif 'RouterOS' in snmp_desc or 'MikroTik' in snmp_desc or '8291/tcp open' in out %}mikrotik {% elif 'Linux' in snmp_desc or 'Ubuntu' in snmp_desc or '22/tcp open' in out %}linux {% elif 'JetDirect' in snmp_desc or 'LaserJet' in snmp_desc or 'Samsung' in snmp_desc or 'Kyocera' in snmp_desc or '9100/tcp open' in out %}printer {% else %}other{% endif %} host_data: ip: "{{ ip }}" type: "{{ detected_type }}" desc: "{{ snmp_desc | replace('\"', '') | default('No SNMP info') }}" name: "{{ detected_type }}_{{ ip | replace('.', '_') }}" loop: "{{ scan_results.results }}" no_log: true # ---------------------------------------------------------------- # ШАГ 4: Группировка # ---------------------------------------------------------------- - name: Группировка хостов set_fact: list_win: "{{ classified_hosts | selectattr('type', 'equalto', 'windows') | list }}" list_lin: "{{ classified_hosts | selectattr('type', 'equalto', 'linux') | list }}" list_tik: "{{ classified_hosts | selectattr('type', 'equalto', 'mikrotik') | list }}" list_prn: "{{ classified_hosts | selectattr('type', 'equalto', 'printer') | list }}" # ---------------------------------------------------------------- # ШАГ 5: Отправка Windows # ---------------------------------------------------------------- - block: - name: Генерация текста инвентаря Windows set_fact: content_win: | [windows] {% for h in list_win %} {{ h.name }} ansible_host={{ h.ip }} # SNMP: {{ h.desc }} {% endfor %} [windows:vars] ansible_connection=ssh ansible_shell_type=powershell ansible_port=22 - name: Сохранение JSON для Windows copy: content: | { "name": "SNMP Windows {{ 1000 | random }}", "project_id": {{ semaphore_project_id }}, "type": "static", "ssh_key_id": {{ key_windows }}, "become_key_id": null, "repository_id": null, "inventory": {{ content_win | to_json }} } dest: /tmp/p_win.json - name: Отправка Windows API command: > curl -X POST "{{ semaphore_url }}/api/project/{{ semaphore_project_id }}/inventory" -H "Authorization: Bearer {{ semaphore_api_token }}" -H "Content-Type: application/json" -d @/tmp/p_win.json ignore_errors: yes when: list_win | length > 0 # ---------------------------------------------------------------- # ШАГ 6: Отправка MikroTik # ---------------------------------------------------------------- - block: - name: Генерация текста инвентаря MikroTik set_fact: content_tik: | [routers] {% for h in list_tik %} {{ h.name }} ansible_host={{ h.ip }} # {{ h.desc }} {% endfor %} [routers:vars] ansible_connection=network_cli ansible_network_os=routeros - name: Сохранение JSON для MikroTik copy: content: | { "name": "SNMP MikroTik {{ 1000 | random }}", "project_id": {{ semaphore_project_id }}, "type": "static", "ssh_key_id": {{ key_mikrotik }}, "become_key_id": null, "repository_id": null, "inventory": {{ content_tik | to_json }} } dest: /tmp/p_tik.json - name: Отправка MikroTik API command: > curl -X POST "{{ semaphore_url }}/api/project/{{ semaphore_project_id }}/inventory" -H "Authorization: Bearer {{ semaphore_api_token }}" -H "Content-Type: application/json" -d @/tmp/p_tik.json ignore_errors: yes when: list_tik | length > 0 # ---------------------------------------------------------------- # ШАГ 7: Отправка Принтеров # ---------------------------------------------------------------- - block: - name: Генерация текста инвентаря Принтеров set_fact: content_prn: | [printers] {% for h in list_prn %} {{ h.name }} ansible_host={{ h.ip }} # {{ h.desc }} {% endfor %} [printers:vars] ansible_connection=local - name: Сохранение JSON для Принтеров copy: content: | { "name": "SNMP Printers {{ 1000 | random }}", "project_id": {{ semaphore_project_id }}, "type": "static", "ssh_key_id": {{ key_printers }}, "become_key_id": null, "repository_id": null, "inventory": {{ content_prn | to_json }} } dest: /tmp/p_prn.json - name: Отправка Принтеров API command: > curl -X POST "{{ semaphore_url }}/api/project/{{ semaphore_project_id }}/inventory" -H "Authorization: Bearer {{ semaphore_api_token }}" -H "Content-Type: application/json" -d @/tmp/p_prn.json ignore_errors: yes when: list_prn | length > 0 - name: Очистка временных файлов shell: rm -f /tmp/p_*.json