diff --git a/playbooks/inventory_generator.yml b/playbooks/inventory_generator.yml index 26bebe6..b726f4e 100644 --- a/playbooks/inventory_generator.yml +++ b/playbooks/inventory_generator.yml @@ -1,13 +1,11 @@ --- -- name: Генерация инвентаря Windows PC по DNS +- name: Максимально быстрая генерация инвентаря hosts: localhost connection: local gather_facts: yes vars: domain: "zag.lan" - dns_servers: - - "192.168.1.250" - - "192.168.1.254" + dns_server: "192.168.1.250" inventory_file: "/tmp/windows_inventory.yml" subnets: - "192.168.0.0/24" @@ -24,105 +22,69 @@ - "172.19.58.0/23" tasks: - - name: Генерация списка всех IP + - name: Быстрый поиск активных хостов (nmap) + command: "nmap -sn -T5 {{ subnets | join(' ') }} --min-parallelism 100" + register: nmap_result + changed_when: false + + - name: Извлечение активных IP + set_fact: + active_ips: "{{ nmap_result.stdout | regex_findall('Nmap scan report for ([0-9.]+)') }}" + + - name: DNS резолв только для активных хостов shell: | python3 << 'EOF' - import ipaddress - subnets = {{ subnets | to_json }} - for subnet in subnets: - network = ipaddress.ip_network(subnet) - for ip in network.hosts(): - print(ip) + import subprocess + import concurrent.futures + + DNS = "{{ dns_server }}" + IPS = {{ active_ips | to_json }} + + def resolve(ip): + try: + r = subprocess.run(['nslookup', ip, DNS], capture_output=True, text=True, timeout=2) + for line in r.stdout.split('\n'): + if 'name =' in line: + host = line.split('=')[-1].strip().rstrip('.') + if host.lower().startswith('pc'): + return f"{ip}|{host}" + except: pass + return None + + with concurrent.futures.ThreadPoolExecutor(max_workers=50) as ex: + for r in filter(None, ex.map(resolve, IPS)): + print(r) EOF - register: all_ips + register: dns_result changed_when: false + when: active_ips | length > 0 - - name: Парсинг IP адресов + - name: Формирование списка PC set_fact: - ip_list: "{{ all_ips.stdout_lines }}" - - - name: Информация о сканировании - debug: - msg: "Будет проверено {{ ip_list | length }} IP адресов" - - - name: DNS резолв для всех IP - shell: | - result=$(nslookup {{ item }} {{ dns_servers[0] }} 2>/dev/null | grep 'name =' | awk '{print $NF}' | sed 's/\.$//') - - if [ -z "$result" ]; then - result=$(nslookup {{ item }} {{ dns_servers[1] }} 2>/dev/null | grep 'name =' | awk '{print $NF}' | sed 's/\.$//') - fi - - if [ -z "$result" ]; then - echo "NO_DNS" - else - echo "$result" - fi - loop: "{{ ip_list }}" - register: dns_results - changed_when: false - # Выполнение параллельно для ускорения - async: 30 - poll: 0 - - - name: Ожидание завершения DNS запросов - async_status: - jid: "{{ item.ansible_job_id }}" - register: dns_jobs - until: dns_jobs.finished - retries: 60 - delay: 1 - loop: "{{ dns_results.results }}" - - - name: Фильтрация PC хостов - set_fact: - pc_hosts: "{{ pc_hosts | default([]) + [{'hostname': item.stdout | trim, 'ip': item.item}] }}" - loop: "{{ dns_jobs.results }}" + pc_hosts: "{{ pc_hosts | default([]) + [{'ip': item.split('|')[0], 'hostname': item.split('|')[1]}] }}" + loop: "{{ dns_result.stdout_lines }}" when: - - item.stdout is defined - - item.stdout != "NO_DNS" - - item.stdout | trim | lower is match('^pc\\d+.*') + - dns_result.stdout_lines is defined + - dns_result.stdout_lines | length > 0 - - name: Создание инвентаря YAML + - name: Создание инвентаря copy: content: | - # ========================================== - # Инвентарь Windows PC - # Сгенерирован: {{ ansible_date_time.iso8601 }} - # DNS серверы: {{ dns_servers | join(', ') }} - # Подсети: {{ subnets | join(', ') }} - # Всего IP проверено: {{ ip_list | length }} - # PC хостов найдено: {{ pc_hosts | default([]) | length }} - # ========================================== - all: children: windows_pcs: hosts: - {% for host in pc_hosts | default([]) | sort(attribute='hostname') %} - {{ host.hostname | regex_replace('\\.' + domain + '$', '') | regex_replace('\\..*$', '') }}: - ansible_host: {{ host.ip }} + {% for h in pc_hosts | default([]) | sort(attribute='hostname') %} + {{ h.hostname.split('.')[0] }}: + ansible_host: {{ h.ip }} {% endfor %} vars: ansible_connection: winrm ansible_winrm_transport: ntlm ansible_winrm_server_cert_validation: ignore ansible_port: 5985 - ansible_winrm_scheme: http dest: "{{ inventory_file }}" - - name: Итоговая статистика + - name: Результат debug: - msg: - - "==========================================" - - "Просканировано подсетей: {{ subnets | length }}" - - "Проверено IP адресов: {{ ip_list | length }}" - - "Найдено PC хостов: {{ pc_hosts | default([]) | length }}" - - "Файл инвентаря: {{ inventory_file }}" - - "==========================================" - - - name: Список найденных PC - debug: - msg: "{{ item.hostname }} ({{ item.ip }})" - loop: "{{ pc_hosts | default([]) | sort(attribute='hostname') }}" - when: pc_hosts is defined \ No newline at end of file + msg: "Найдено {{ pc_hosts | default([]) | length }} PC хостов → {{ inventory_file }}" \ No newline at end of file