Обновить playbooks/inventory.yml
This commit is contained in:
@@ -1,107 +1,86 @@
|
|||||||
---
|
---
|
||||||
- name: Сбор инвентаря и создание его в Semaphore UI
|
- name: Сбор инвентаря и создание (Метод через файл)
|
||||||
hosts: localhost
|
hosts: localhost
|
||||||
connection: local
|
connection: local
|
||||||
gather_facts: no
|
gather_facts: no
|
||||||
vars:
|
vars:
|
||||||
# --- НАСТРОЙКИ SEMAPHORE ---
|
# --- НАСТРОЙКИ ---
|
||||||
semaphore_url: "http://192.168.0.198:9999" # Укажите ваш URL (или http://localhost:3000)
|
semaphore_url: "http://192.168.0.198:9999"
|
||||||
semaphore_project_id: 1
|
semaphore_project_id: 1
|
||||||
# ID ключа, который будет использоваться для подключения к новым хостам
|
|
||||||
semaphore_key_id: 7
|
semaphore_key_id: 7
|
||||||
# Токен API (лучше хранить в Secret, но для теста можно тут)
|
|
||||||
semaphore_api_token: "9ojexqiwt1xkemig7j1bd1pe-frh7hkre4reryk2occ="
|
semaphore_api_token: "9ojexqiwt1xkemig7j1bd1pe-frh7hkre4reryk2occ="
|
||||||
inventory_name: "Auto Scanned Network"
|
inventory_name: "Auto Scanned Network"
|
||||||
|
|
||||||
# --- НАСТРОЙКИ СЕТИ ---
|
# --- СЕТИ ---
|
||||||
subnets:
|
subnets:
|
||||||
- "192.168.0.0/24"
|
- "192.168.0.0/23"
|
||||||
- "192.168.1.0/24"
|
- "192.168.1.0/23"
|
||||||
- "192.168.2.0/24"
|
- "192.168.2.0/24"
|
||||||
- "192.168.3.0/24"
|
- "192.168.3.0/24"
|
||||||
- "172.19.8.0/23"
|
- "172.19.8.0/24"
|
||||||
- "172.19.9.0/23"
|
- "172.19.9.0/24"
|
||||||
- "172.19.10.0/23"
|
- "172.19.10.0/24"
|
||||||
- "172.19.24.0/23"
|
- "172.19.24.0/24"
|
||||||
- "172.19.26.0/23"
|
- "172.19.26.0/24"
|
||||||
- "172.19.40.0/23"
|
- "172.19.40.0/24"
|
||||||
- "172.19.42.0/23"
|
- "172.19.42.0/24"
|
||||||
- "172.19.56.0/23"
|
- "172.19.56.0/24"
|
||||||
- "172.19.58.0/23"
|
- "172.19.58.0/24"
|
||||||
- "172.19.90.0/23"
|
- "172.19.90.0/24"
|
||||||
# - "192.168.1.0/24" # Добавьте нужные подсети
|
# добавьте остальные ваши подсети сюда...
|
||||||
scan_ports: [5985, 22, 445]
|
scan_ports: [5985, 22, 445]
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
# ---------------------------------------------------------
|
# 1. Сканирование (Ваш код)
|
||||||
# ШАГ 1: Сканирование (Nmap)
|
- name: Сканирование сети
|
||||||
# ---------------------------------------------------------
|
|
||||||
- name: Сканирование сети (поиск живых IP)
|
|
||||||
command: >
|
command: >
|
||||||
nmap -p {{ scan_ports | join(',') }}
|
nmap -p {{ scan_ports | join(',') }}
|
||||||
-Pn -n --open --min-rate 1000 -T4 -oG -
|
-Pn -n --open --min-rate 1000 -T4 -oG -
|
||||||
{{ subnets | join(' ') }}
|
{{ subnets | join(' ') }}
|
||||||
register: nmap_result
|
register: nmap_result
|
||||||
changed_when: false
|
changed_when: false
|
||||||
ignore_errors: yes # Чтобы не падало, если ничего не нашлось
|
ignore_errors: yes
|
||||||
|
|
||||||
- name: Извлечение IP адресов
|
- name: Извлечение IP
|
||||||
set_fact:
|
set_fact:
|
||||||
active_ips: "{{ nmap_result.stdout | regex_findall('Host: ([0-9.]+).*Ports:.*(?:' + scan_ports | join('|') + ')/open') | unique | list }}"
|
active_ips: "{{ nmap_result.stdout | regex_findall('Host: ([0-9.]+).*Ports:.*(?:' + scan_ports | join('|') + ')/open') | unique | list }}"
|
||||||
|
|
||||||
- name: Проверка, найдены ли IP
|
- name: Проверка IP
|
||||||
fail:
|
fail:
|
||||||
msg: "Не найдено ни одного активного IP. Проверьте настройки сети или Nmap."
|
msg: "IP не найдены!"
|
||||||
when: active_ips | length == 0
|
when: active_ips | length == 0
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
# 2. Имена (Ваш код)
|
||||||
# ШАГ 2: Определение имен
|
- name: Определение имен
|
||||||
# ---------------------------------------------------------
|
|
||||||
- name: Определение имен хостов (SMB Discovery + DNS)
|
|
||||||
shell: |
|
shell: |
|
||||||
IP="{{ item }}"
|
IP="{{ item }}"
|
||||||
SMB_NAME=$(nmap -p 445 --script smb-os-discovery $IP -Pn -n | grep "Computer name:" | awk -F': ' '{print $2}')
|
SMB_NAME=$(nmap -p 445 --script smb-os-discovery $IP -Pn -n | grep "Computer name:" | awk -F': ' '{print $2}')
|
||||||
if [ ! -z "$SMB_NAME" ]; then
|
if [ ! -z "$SMB_NAME" ]; then echo "$SMB_NAME" | tr '[:upper:]' '[:lower:]'; else
|
||||||
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)
|
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
|
if [ ! -z "$DNS_NAME" ]; then echo "$DNS_NAME" | tr '[:upper:]' '[:lower:]'; else echo "UNKNOWN"; fi
|
||||||
echo "$DNS_NAME" | tr '[:upper:]' '[:lower:]'
|
|
||||||
else
|
|
||||||
echo "UNKNOWN"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
loop: "{{ active_ips }}"
|
loop: "{{ active_ips }}"
|
||||||
register: host_names
|
register: host_names
|
||||||
changed_when: false
|
changed_when: false
|
||||||
no_log: true
|
no_log: true
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
# 3. Сортировка (Ваш код)
|
||||||
# ШАГ 3: Сортировка и генерация текста
|
- name: Сортировка
|
||||||
# ---------------------------------------------------------
|
|
||||||
- name: Сортировка хостов
|
|
||||||
set_fact:
|
set_fact:
|
||||||
pc_list: >-
|
pc_list: >-
|
||||||
{{ host_names.results | selectattr('stdout', 'search', 'pc')
|
{{ host_names.results | selectattr('stdout', 'search', 'pc') | map(attribute='item') | list | zip(host_names.results | selectattr('stdout', 'search', 'pc') | map(attribute='stdout') | list) | list }}
|
||||||
| map(attribute='item') | list
|
|
||||||
| zip(host_names.results | selectattr('stdout', 'search', 'pc') | map(attribute='stdout') | list)
|
|
||||||
| list }}
|
|
||||||
other_list: >-
|
other_list: >-
|
||||||
{{ host_names.results | rejectattr('stdout', 'search', 'pc')
|
{{ host_names.results | rejectattr('stdout', 'search', 'pc') | map(attribute='item') | list | zip(host_names.results | rejectattr('stdout', 'search', 'pc') | map(attribute='stdout') | list) | list }}
|
||||||
| map(attribute='item') | list
|
|
||||||
| zip(host_names.results | rejectattr('stdout', 'search', 'pc') | map(attribute='stdout') | list)
|
|
||||||
| list }}
|
|
||||||
|
|
||||||
- name: Генерация текста инвентаря
|
# 4. Текст инвентаря
|
||||||
|
- name: Генерация текста
|
||||||
set_fact:
|
set_fact:
|
||||||
inventory_content: |
|
inventory_content: |
|
||||||
# === Найденные PC ===
|
|
||||||
[windows_pcs]
|
[windows_pcs]
|
||||||
{% for ip, name in pc_list %}
|
{% for ip, name in pc_list %}
|
||||||
{{ name }} ansible_host={{ ip }}
|
{{ name }} ansible_host={{ ip }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
# === Остальные устройства ===
|
|
||||||
[windows_other]
|
[windows_other]
|
||||||
{% for ip, name in other_list %}
|
{% for ip, name in other_list %}
|
||||||
{% if name == "UNKNOWN" %}
|
{% if name == "UNKNOWN" %}
|
||||||
@@ -121,54 +100,43 @@
|
|||||||
ansible_shell_type=powershell
|
ansible_shell_type=powershell
|
||||||
ansible_user=o.grechko
|
ansible_user=o.grechko
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
# ==========================================================
|
||||||
# ШАГ 4: Отладка (проверка данных перед отправкой)
|
# ИЗМЕНЕННАЯ ЧАСТЬ: СОЗДАНИЕ ЧЕРЕЗ ФАЙЛ
|
||||||
# ---------------------------------------------------------
|
# ==========================================================
|
||||||
- name: Debug Payload (Проверка данных)
|
|
||||||
|
- name: Сохранение JSON-пейлоада в файл (для надежности)
|
||||||
|
copy:
|
||||||
|
content: |
|
||||||
|
{
|
||||||
|
"name": "{{ inventory_name }} {{ 1000 | random }}",
|
||||||
|
"project_id": {{ semaphore_project_id | int }},
|
||||||
|
"type": "static",
|
||||||
|
"ssh_key_id": {{ semaphore_key_id | int }},
|
||||||
|
"become_key_id": null,
|
||||||
|
"repository_id": null,
|
||||||
|
"inventory": {{ inventory_content | to_json }}
|
||||||
|
}
|
||||||
|
dest: /tmp/semaphore_payload.json
|
||||||
|
|
||||||
|
- name: Отправка через CURL (чтение из файла)
|
||||||
|
command: >
|
||||||
|
curl -v -X POST "{{ semaphore_url }}/api/project/{{ semaphore_project_id }}/inventory"
|
||||||
|
-H "Authorization: Bearer {{ semaphore_api_token }}"
|
||||||
|
-H "Content-Type: application/json"
|
||||||
|
-H "Accept: application/json"
|
||||||
|
-d @/tmp/semaphore_payload.json
|
||||||
|
register: curl_result
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Показать полный ответ CURL
|
||||||
debug:
|
debug:
|
||||||
msg:
|
var: curl_result.stderr_lines
|
||||||
- "URL: {{ semaphore_url }}/api/project/{{ semaphore_project_id }}/inventory"
|
|
||||||
- "SSH Key ID: {{ semaphore_key_id }}"
|
|
||||||
- "Количество символов в инвентаре: {{ inventory_content | length }}"
|
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
- name: Показать ответ сервера (body)
|
||||||
# ШАГ 5: Отправка в API (ИСПРАВЛЕНО ssh_key_id)
|
|
||||||
# ---------------------------------------------------------
|
|
||||||
- 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 }} {{ 10000 | random }}"
|
|
||||||
project_id: "{{ semaphore_project_id | int }}"
|
|
||||||
type: "static"
|
|
||||||
ssh_key_id: "{{ semaphore_key_id | int }}"
|
|
||||||
become_key_id: null
|
|
||||||
# !!! ВОТ ЭТО ПОЛЕ ОБЯЗАТЕЛЬНО !!!
|
|
||||||
repository_id: null
|
|
||||||
inventory: "{{ inventory_content }}"
|
|
||||||
status_code: [201, 200]
|
|
||||||
register: api_response
|
|
||||||
ignore_errors: yes # Чтобы увидеть вывод ошибки, если она случится
|
|
||||||
|
|
||||||
# Эта задача покажет, ПОЧЕМУ именно сервер ругается (текст ошибки)
|
|
||||||
- name: ОТЛАДКА - Ответ сервера (если ошибка)
|
|
||||||
debug:
|
debug:
|
||||||
msg: "Server response: {{ api_response.json | default(api_response.content) }}"
|
var: curl_result.stdout_lines
|
||||||
when: api_response.failed is defined and api_response.failed
|
|
||||||
|
|
||||||
- name: Остановка сценария при ошибке
|
- name: Удалить временный файл
|
||||||
fail:
|
file:
|
||||||
msg: "Не удалось создать инвентарь. См. причину выше."
|
path: /tmp/semaphore_payload.json
|
||||||
when: api_response.failed is defined and api_response.failed
|
state: absent
|
||||||
|
|
||||||
- name: Успех
|
|
||||||
debug:
|
|
||||||
msg: "Инвентарь создан! ID: {{ api_response.json.id }}"
|
|
||||||
when: api_response.status == 201 or api_response.status == 200
|
|
||||||
Reference in New Issue
Block a user