Files
semaphore/playbooks/scan_inventory.yml

280 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: "Сканирование сети (Jinja2 Logic Fix)"
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: Классификация (Jinja2 Block - Исправленная логика)
# Мы обрабатываем весь список результатов сразу, а не в цикле задач.
# ----------------------------------------------------------------
- name: Обработка результатов сканирования
set_fact:
classified_hosts: >-
[
{% for res in scan_results.results %}
{% set out = res.stdout %}
{% set ip = res.item %}
{# Поиск имени #}
{% set smb_found = out | regex_search('Computer name: ([\\w-]+)', '\\1') %}
{% set smb_name = smb_found[0] if smb_found else '' %}
{# Определение типа (Ищем 'порт/tcp' и 'open' с любыми пробелами) #}
{% set type = 'other' %}
{% if out | regex_search('445/tcp\s+open') %}
{% set type = 'windows' %}
{% elif out | regex_search('8291/tcp\s+open') %}
{% set type = 'mikrotik' %}
{% elif out | regex_search('9100/tcp\s+open') %}
{% set type = 'printer' %}
{% elif out | regex_search('22/tcp\s+open') %}
{% set type = 'linux' %}
{% endif %}
{# Формирование имени #}
{% if type == 'windows' and smb_name != '' %}
{% set final_name = smb_name | lower %}
{% else %}
{% set final_name = type + '_' + ip | replace('.', '_') %}
{% endif %}
{
"ip": "{{ ip }}",
"type": "{{ type }}",
"name": "{{ final_name }}"
},
{% endfor %}
]
# ----------------------------------------------------------------
# ШАГ 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:
- "Windows: {{ list_win | length }}"
- "MikroTik: {{ list_tik | length }}"
- "Linux: {{ list_lin | length }}"
- "Printers: {{ list_prn | length }}"
- "Other: {{ classified_hosts | length - (list_win|length + list_lin|length + list_tik|length + 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