Files
semaphore/playbooks/scan_inventory.yml

220 lines
8.6 KiB
YAML

---
- 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