From f1fcda4b2389cce142dce4be956d179c6d0ddc2e Mon Sep 17 00:00:00 2001 From: ogrechko Date: Wed, 10 Dec 2025 09:01:12 +0000 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8=D1=82?= =?UTF-8?q?=D1=8C=20playbooks/inventory.yml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- playbooks/inventory.yml | 182 ++++++++++++++++++++++++++-------------- 1 file changed, 118 insertions(+), 64 deletions(-) diff --git a/playbooks/inventory.yml b/playbooks/inventory.yml index 5b91683..ad8070a 100644 --- a/playbooks/inventory.yml +++ b/playbooks/inventory.yml @@ -1,78 +1,132 @@ --- -# ------------------------------------------------------------------------- -# ПЛЕЙ 1: Подключение к Docker-серверу, чтение файла и создание инвентаря -# ------------------------------------------------------------------------- -- name: Extract IPs from Docker and create Inventory - hosts: docker_servers # Группа в Semaphore, где лежит ваш Docker-сервер - become: true # Нужно для выполнения команд docker +- name: Сбор инвентаря и создание его в Semaphore UI + hosts: localhost + connection: local + gather_facts: no vars: - # НАСТРОЙКИ - container_name: "semaphore-semaphore-1" # Имя контейнера - file_path_in_container: "/app/hosts.txt" # Путь к файлу внутри контейнера - inventory_save_path: "/tmp/extracted_inventory.ini" # Куда сохранить результат на сервере + # --- НАСТРОЙКИ SEMAPHORE --- + semaphore_url: "http://192.168.0.198:9999" # Адрес вашего Semaphore + semaphore_project_id: 1 # ID проекта + semaphore_key_id: 5 # ID ключа (Store Key) для подключения к хостам + semaphore_api_token: "9ojexqiwt1xkemig7j1bd1pe-frh7hkre4reryk2occ=" # Вставьте токен или передайте через Extra Vars + inventory_name: "Auto Scanned Network" # Как назвать инвентарь в Semaphore + + # --- НАСТРОЙКИ СЕТИ (из вашего примера) --- + subnets: + - "192.168.0.0/24" + - "192.168.1.0/24" + - "192.168.2.0/24" + - "192.168.3.0/24" + - "172.19.8.0/23" + - "172.19.9.0/23" + - "172.19.10.0/23" + - "172.19.24.0/23" + - "172.19.26.0/23" + - "172.19.40.0/23" + - "172.19.42.0/23" + - "172.19.56.0/23" + - "172.19.58.0/23" + # ... добавьте остальные подсети ... + scan_ports: [5985, 22, 445] tasks: - # 1. Проверяем, жив ли контейнер - - name: Check if container is running - shell: "docker ps -q -f name={{ container_name }}" - register: container_check - - - name: Fail if container is not running - fail: - msg: "Контейнер {{ container_name }} не найден или остановлен!" - when: container_check.stdout == "" - - # 2. Читаем файл (формат: просто список IP, каждый с новой строки) - - name: Read file content from container - command: "docker exec {{ container_name }} cat {{ file_path_in_container }}" - register: file_content + # 1. Сканирование (Ваш код) + - name: Сканирование сети (поиск живых IP) + command: > + nmap -p {{ scan_ports | join(',') }} + -Pn -n --open --min-rate 1000 -T4 -oG - + {{ subnets | join(' ') }} + register: nmap_result changed_when: false - # 3. Добавляем хосты в оперативную память (для текущего запуска Ansible) - - name: Add hosts to memory (dynamic inventory) - add_host: - name: "{{ item }}" - groups: extracted_dockers_hosts - ansible_user: "Administrator" # Можно задать пользователя по умолчанию для новых хостов - ansible_connection: "winrm" # Или ssh, в зависимости от того, что за хосты в списке - # Фильтр select проверяет, что строка не пустая - loop: "{{ file_content.stdout_lines | select('match', '^.+$') | list }}" + - name: Извлечение IP адресов + set_fact: + active_ips: "{{ nmap_result.stdout | regex_findall('Host: ([0-9.]+).*Ports:.*(?:' + scan_ports | join('|') + ')/open') | unique | list }}" - # 4. (Опционально) Сохраняем физический файл инвентаря, как в вашем старом скрипте - - name: Save inventory to file (INI format) - copy: - content: | - # === Инвентарь, полученный из Docker: {{ container_name }} === - - [extracted_hosts] - {% for ip in file_content.stdout_lines | select('match', '^.+$') %} - host_{{ ip | replace('.', '_') }} ansible_host={{ ip }} + # 2. Определение имен (Ваш код) + - name: Определение имен хостов (SMB Discovery + DNS) + shell: | + IP="{{ item }}" + SMB_NAME=$(nmap -p 445 --script smb-os-discovery $IP -Pn -n | grep "Computer name:" | awk -F': ' '{print $2}') + if [ ! -z "$SMB_NAME" ]; then + echo "$SMB_NAME" | tr '[:upper:]' '[:lower:]' + else + DNS_NAME=$(nslookup -timeout=1 $IP 192.168.1.250 2>/dev/null | grep 'name =' | awk '{print $NF}' | sed 's/\.$//' | head -n 1) + if [ ! -z "$DNS_NAME" ]; then + echo "$DNS_NAME" | tr '[:upper:]' '[:lower:]' + else + echo "UNKNOWN" + fi + fi + loop: "{{ active_ips }}" + register: host_names + changed_when: false + no_log: true + + # 3. Сортировка (Ваш код) + - name: Сортировка хостов + set_fact: + pc_list: >- + {{ host_names.results | selectattr('stdout', 'search', 'pc') + | map(attribute='item') | list + | zip(host_names.results | selectattr('stdout', 'search', 'pc') | map(attribute='stdout') | list) + | list }} + other_list: >- + {{ host_names.results | rejectattr('stdout', 'search', 'pc') + | map(attribute='item') | list + | zip(host_names.results | rejectattr('stdout', 'search', 'pc') | map(attribute='stdout') | list) + | list }} + + # 4. Формирование текста инвентаря в переменную + - name: Генерация текста инвентаря + set_fact: + inventory_content: | + # === Найденные PC === + [windows_pcs] + {% for ip, name in pc_list %} + {{ name }} ansible_host={{ ip }} {% endfor %} - - [extracted_hosts:vars] - # Пример переменных (настройте под ваши задачи) + + # === Остальные устройства === + [windows_other] + {% for ip, name in other_list %} + {% if name == "UNKNOWN" %} + unknown_{{ ip | replace('.', '_') }} ansible_host={{ ip }} + {% else %} + {{ name }} ansible_host={{ ip }} + {% endif %} + {% endfor %} + + [windows:children] + windows_pcs + windows_other + + [windows:vars] ansible_connection=winrm - ansible_port=5985 ansible_winrm_transport=ntlm ansible_winrm_server_cert_validation=ignore - dest: "{{ inventory_save_path }}" - delegate_to: localhost # Сохранить файл на сервере Semaphore (или уберите, чтобы сохранить на Docker-сервере) + ansible_port=5985 + ansible_user=Administrator - - name: Show extracted IPs - debug: - msg: "Найден IP: {{ item }}" - loop: "{{ file_content.stdout_lines | select('match', '^.+$') | list }}" + # 5. ОТПРАВКА В SEMAPHORE API + - name: Создание/Обновление инвентаря в Semaphore через API + uri: + url: "{{ semaphore_url }}/api/project/{{ semaphore_project_id }}/inventory" + method: POST + headers: + Authorization: "Bearer {{ semaphore_api_token }}" + Content-Type: "application/json" + Accept: "application/json" + body_format: json + body: + name: "{{ inventory_name }}" + project_id: "{{ semaphore_project_id | int }}" + type: "static" + key_id: "{{ semaphore_key_id | int }}" + inventory: "{{ inventory_content }}" + status_code: [201, 204, 200] + register: api_response -# ------------------------------------------------------------------------- -# ПЛЕЙ 2: (Пример) Проверка связи с новыми хостами -# ------------------------------------------------------------------------- -- name: Verify connection to new hosts - hosts: extracted_dockers_hosts - gather_facts: false # Отключаем сбор фактов для скорости (или если нет доступа) - - tasks: - - name: Ping host - # Используем win_ping для Windows или ping для Linux - # win_ping: + - name: Результат API debug: - msg: "Успешное подключение к {{ inventory_hostname }} (IP: {{ ansible_host | default(inventory_hostname) }})" \ No newline at end of file + msg: "Инвентарь успешно создан! ID: {{ api_response.json.id | default('неизвестен') }}" \ No newline at end of file