Files
semaphore/playbooks/scan_inventory.yml

272 lines
10 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: "Сканирование сети (Final Fix - Regex)"
hosts: localhost
connection: local
gather_facts: no
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"
tasks:
# ----------------------------------------------------------------
# ШАГ 1: Поиск живых хостов
# ----------------------------------------------------------------
- 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: Сканирование портов (TCP Connect)
# ----------------------------------------------------------------
- name: TCP Port Scan & Name Discovery
shell: |
nmap -sT -p 22,445,8291,9100 \
--script smb-os-discovery \
-Pn -n -T4 {{ item }}
loop: "{{ active_ips }}"
register: scan_results
changed_when: false
# ----------------------------------------------------------------
# ШАГ 3: Классификация (ИСПРАВЛЕНО НА REGEX)
# ----------------------------------------------------------------
- name: Анализ результатов
set_fact:
classified_hosts: "{{ classified_hosts | default([]) + [ host_data ] }}"
vars:
out: "{{ item.stdout }}"
ip: "{{ item.item }}"
# Поиск имени (безопасный метод)
smb_matches: "{{ out | regex_findall('Computer name: ([\\w-]+)') }}"
smb_name: "{{ smb_matches | first | default('') }}"
# ЛОГИКА ОПРЕДЕЛЕНИЯ ТИПА (Используем regex_search для игнорирования лишних пробелов)
# \s+ означает "один или больше пробелов"
detected_type: >-
{% if out | regex_search('445/tcp\s+open') %}windows
{% elif out | regex_search('8291/tcp\s+open') %}mikrotik
{% elif out | regex_search('9100/tcp\s+open') %}printer
{% elif out | regex_search('22/tcp\s+open') %}linux
{% else %}other{% endif %}
# Формируем имя
final_name: >-
{% if detected_type == 'windows' and smb_name != '' %}{{ smb_name | lower }}
{% else %}{{ detected_type }}_{{ ip | replace('.', '_') }}{% endif %}
host_data:
ip: "{{ ip }}"
type: "{{ detected_type }}"
name: "{{ final_name }}"
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 }}"
- name: СТАТИСТИКА (Что нашли)
debug:
msg:
- "Всего живых IP: {{ active_ips | length }}"
- "Windows: {{ list_win | length }}"
- "MikroTik: {{ list_tik | length }}"
- "Linux: {{ list_lin | length }}"
- "Printers: {{ list_prn | length }}"
# ----------------------------------------------------------------
# ШАГ 5: Отправка Windows
# ----------------------------------------------------------------
- block:
- name: Генерация инвентаря Windows
set_fact:
content_win: |
[windows]
{% for h in list_win %}
{{ h.name }} ansible_host={{ h.ip }}
{% endfor %}
[windows:vars]
ansible_connection=ssh
ansible_shell_type=powershell
ansible_port=22
- name: Сохранение JSON (Windows)
copy:
content: |
{
"name": "Auto 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: Отправка API (Windows)
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 }}
{% endfor %}
[routers:vars]
ansible_connection=network_cli
ansible_network_os=routeros
- name: Сохранение JSON (MikroTik)
copy:
content: |
{
"name": "Auto 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: Отправка API (MikroTik)
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 }}
{% endfor %}
[printers:vars]
ansible_connection=local
- name: Сохранение JSON (Принтеры)
copy:
content: |
{
"name": "Auto 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
# ----------------------------------------------------------------
# ШАГ 8: Отправка Linux
# ----------------------------------------------------------------
- block:
- name: Генерация инвентаря Linux
set_fact:
content_lin: |
[linux]
{% for h in list_lin %}
{{ h.name }} ansible_host={{ h.ip }}
{% endfor %}
[linux:vars]
ansible_connection=ssh
ansible_user=root
- name: Сохранение JSON (Linux)
copy:
content: |
{
"name": "Auto Linux {{ 1000 | random }}",
"project_id": {{ semaphore_project_id }},
"type": "static",
"ssh_key_id": {{ key_linux }},
"become_key_id": null,
"repository_id": null,
"inventory": {{ content_lin | to_json }}
}
dest: /tmp/p_lin.json
- name: Отправка API (Linux)
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_lin.json
ignore_errors: yes
when: list_lin | length > 0
- name: Очистка
shell: rm -f /tmp/p_*.json