Files
semaphore/playbooks/scan_inventory.yml

226 lines
9.0 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
- name: "Сканирование сети через SNMP (Community: public)"
hosts: localhost
connection: local
gather_facts: no
become: yes # Нужно для сканирования UDP (SNMP) и Nmap -O
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 (пароль для чтения)
snmp_community: "public"
tasks:
# ----------------------------------------------------------------
# ШАГ 1: Поиск живых хостов (Ping)
# ----------------------------------------------------------------
- name: Ping Sweep (быстрый поиск)
command: "nmap -sn -n --min-rate 1000 -T4 -oG - {{ subnets | join(' ') }}"
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 }}
loop: "{{ active_ips }}"
register: scan_results
changed_when: false
# ----------------------------------------------------------------
# ШАГ 3: Классификация на основе ответа SNMP
# ----------------------------------------------------------------
- name: Анализ устройств и классификация
set_fact:
classified_hosts: "{{ classified_hosts | default([]) + [ host_data ] }}"
vars:
out: "{{ item.stdout }}"
ip: "{{ item.item }}"
# Пытаемся вытащить строку sysDescr
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: Отправка в Semaphore (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: Отправка в Semaphore (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: Отправка в Semaphore (Принтеры)
# ----------------------------------------------------------------
- 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