diff --git a/.gitignore b/.gitignore index 23e80b0..5a8222a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ keys/ +vars/wifi.yml *.retry diff --git a/README.md b/README.md index e8063fa..150794e 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,93 @@ # fleet -Идемпотентный провижнинг парка приёмников пеленгации (Raspberry Pi + HackRF). -Один прогон приводит новую или старую малинку в рабочее состояние: обновление -системы, зависимости сборки, общий deploy-ключ до Gitea, клон и сборка -`hackrf-scanner`. - -Гоняется дома, пока узлы в сети с интернетом. После переноса в изолированную -сеть (коммутатор, статические IP) на карте уже есть всё; правки кода дальше -идут `rsync` + сборка на месте. Статические IP playbook не трогает. +Плейбуки ansible, которые приводят любую малинку парка (Raspberry Pi + +HackRF) в рабочее состояние и управляют ею дальше: домашний Wi-Fi ради +интернета, пакеты, код `hackrf-scanner` со сборкой на месте, паспорт узла, +запуск и остановка сканера, перезагрузка и выключение. +Управление идёт по проводной сети 11.0.0.0/24 (`ansible_host` в инвентаре), +Wi-Fi нужен только на время установки пакетов и перед работой выключается, +потому что адаптер сидит в 2,4 ГГц рядом с приёмником. ## Требования -- на управляющей машине: `ansible` (Arch: `pacman -S ansible`), доступ по ssh - к узлам под `pi` по ключу; -- на узлах: Raspberry Pi OS (Debian 13), `pi` с sudo без пароля, интернет. +- управляющая машина: `ansible` с коллекциями `community.general` и + `ansible.posix`, `rsync`, `sshpass` (только для `bootstrap.yml`), + рядом лежит каталог `../hackrf-scanner` (переменная `scanner_src`); + Alt Linux p11 и Sisyphus: `apt-get install ansible + python3-module-ansible-collections-ansible-posix sshpass rsync openssh-clients`; + на p10 пакет `ansible` 2.9 не подходит, нужны `ansible-core + python3-module-packaging glibc-locales` и `ansible-galaxy collection install + community.general ansible.posix`; +- узлы: Raspberry Pi OS Lite (Debian 13, NetworkManager), пользователь `pi` + с sudo без пароля, статический адрес 11.0.0.x на eth0; на полном образе + с рабочим столом первый `full-upgrade` по Wi-Fi идёт больше часа; +- `vars/wifi.yml` (в `.gitignore`) по образцу `vars/wifi.yml.example`. -## Первый запуск +## Новый узел - scripts/gen-key.sh # пара keys/gitea_deploy (в .gitignore) - # добавить keys/gitea_deploy.pub как deploy key (read-only) - # в Gitea: IU9/hackrf-scanner - ansible-playbook playbook.yml # весь парк +```bash +nmap -sn 11.0.0.0/24 # какие узлы в сети +ansible-playbook bootstrap.yml -l node107 # ключ по паролю pi/raspberry +ansible-playbook wifi-on.yml # Wi-Fi и проверка интернета +ansible-playbook playbook.yml # пакеты, права, имя +ansible-playbook wifi-off.yml # Wi-Fi выключен до следующего раза +ansible-playbook deploy.yml # код с этой машины, сборка на узле +ansible-playbook env.yml # паспорт ~/node.env из инвентаря +``` -## Теги +## Работа - base apt upgrade, зависимости, pi в plugdev - hostname имя узла из инвентаря - key deploy-ключ, ssh config, known_hosts - repo clone/pull ветки scanner_branch (stash локальных правок) - build cmake configure + build +```bash +# 1. расстановка: x, y узлов и server_ip в inventory/hosts.yml +ansible-playbook env.yml --diff # 2. паспорта на узлы +# 3. частота и усиления: inventory/group_vars/all/scanner.yml +ansible-playbook scanner-start.yml # 4. peleng на всех узлах +ansible-playbook scanner-start.yml -e scanner_args="--freq 2437" # разово поверх +ansible-playbook scanner-stop.yml # HackRF свободен (scan, калибровка) +``` - ansible-playbook playbook.yml -l node106 --tags repo,build +`scanner-start.yml` на каждом узле зовёт `node.py start <профиль> <флаги>`: +останавливает прежний peleng и любой процесс, держащий HackRF, переинициализирует +USB и запускает peleng в фоне с логом `/tmp/peleng.log`. Профиль и флаги лежат в +`inventory/group_vars/all/scanner.yml` (`scanner_profile`, `scanner_args`); узлу +можно задать своё значение в `inventory/hosts.yml`, разовый запуск поверх всего +через `-e`. peleng читает паспорт +только при старте, поэтому после `env.yml` нужен повторный `scanner-start.yml`. + +Новый узел сначала вписывается в `inventory/hosts.yml`. Смена роутера: правка +`vars/wifi.yml` и `wifi-on.yml`, профиль на узлах обновится. + +## Плейбуки + +| Плейбук | Что делает | +|---|---| +| `bootstrap.yml` | ключ управляющей машины в `authorized_keys`, вход по паролю | +| `wifi-on.yml` | радио включено, профиль `fleet-wifi` с кредами из `vars/wifi.yml`, подключение, проверка DNS и HTTPS | +| `playbook.yml` | теги `base` (apt, зависимости, plugdev, udev для HackRF, fish), `hostname`, `key` (deploy-ключ Gitea) | +| `wifi-off.yml` | радио выключено, NetworkManager помнит это через перезагрузку | +| `deploy.yml` | `rsync` исходников без `.git` и `build`, ревизия в `~/hackrf-scanner/DEPLOYED`, `cmake` сборка, проверка бинарников | +| `env.yml` | `~/node.env` (`SDR_ID`, `X`, `Y`, `SERVER`) из инвентаря, перезаписывается целиком | +| `scanner-start.yml` | `node.py start`: освободить HackRF, переинициализировать USB, peleng в фоне, `status` | +| `scanner-stop.yml` | `node.py stop`: peleng и любой процесс с HackRF остановлены, проверка `status` | +| `reboot.yml` | перезагрузка с ожиданием возврата, печатает ядро | +| `poweroff.yml` | штатное выключение и ожидание, пока узел пропадёт из сети | + +Ограничение по узлам и тегам как обычно: `-l node106`, `--tags base`. ## Инвентарь -`inventory/hosts.yml`: адреса узлов в домашней сети (транзитные), а также -справочно -- статический IP для поля, серийник HackRF и координаты x, y (м). -Ветка репозитория -- переменная `scanner_branch`. +`inventory/hosts.yml`: адрес узла в проводной сети, `sdr_id`, серийник HackRF, +координаты x, y в метрах. Общие переменные: `server_ip` (куда узлы шлют замеры), +`scanner_dir` (каталог сканера на узле). Параметры запуска сканера - в +`inventory/group_vars/all/scanner.yml`. Инвентарь главный: `env.yml` перезаписывает паспорт узла, +правки руками на узле до следующего прогона. ## Приёмка -1. Прогон без `failed`. -2. Второй прогон подряд -- `changed=0` на всех узлах. -3. На узле: `hackrf_info` видит устройство, `~/hackrf-scanner/build/` собран, - `git rev-parse --abbrev-ref HEAD` = `scanner_branch`, `hostname` = имя узла. -4. `ssh -T git@monitor.yss.su` с узла отвечает Gitea. +1. Все плейбуки без `failed`, второй прогон подряд `changed=0`. +2. После `wifi-on.yml` каждый узел печатает адрес в домашней сети и + "интернет есть", после `wifi-off.yml` у `wlan0` нет адреса. +3. На узле `~/hackrf-scanner/build/peleng` и `scan` собраны, `DEPLOYED` + совпадает с `git describe` на управляющей машине, `hostname` = имя узла. +4. После `scanner-start.yml` каждый узел печатает "peleng запущен" и строку + замера, после `scanner-stop.yml` статус "не запущен". diff --git a/ansible.cfg b/ansible.cfg index a91ab09..ddd4611 100644 --- a/ansible.cfg +++ b/ansible.cfg @@ -3,6 +3,8 @@ inventory = inventory/hosts.yml remote_user = pi host_key_checking = False interpreter_python = auto_silent +# Все узлы парка одновременно: старт сканера ждёт USB и первый замер ~15 с на узел +forks = 16 [ssh_connection] pipelining = True diff --git a/bootstrap.yml b/bootstrap.yml new file mode 100644 index 0000000..cde1553 --- /dev/null +++ b/bootstrap.yml @@ -0,0 +1,13 @@ +# Голый узел: вход по паролю pi/raspberry, кладём ключ управляющей машины. +# После этого остальные плейбуки ходят по ключу. +# ansible-playbook bootstrap.yml -l node107 +- name: Ключ управляющей машины на узел + hosts: all + gather_facts: false + vars: + ansible_password: raspberry + tasks: + - name: Публичный ключ в authorized_keys пользователя pi + ansible.posix.authorized_key: + user: pi + key: "{{ lookup('file', control_pubkey) }}" diff --git a/deploy.yml b/deploy.yml new file mode 100644 index 0000000..050aadd --- /dev/null +++ b/deploy.yml @@ -0,0 +1,56 @@ +# Исходники hackrf-scanner с управляющей машины (scanner_src) на узлы и сборка +# на месте. Интернет не нужен, зависимости ставит playbook.yml (тег base). +# Что уехало, видно в ~/hackrf-scanner/DEPLOYED (git describe). +- name: Код hackrf-scanner на узлы и сборка + hosts: all + gather_facts: false + tasks: + - name: Ревизия исходников на управляющей машине + delegate_to: localhost + run_once: true + ansible.builtin.command: git -C {{ scanner_src }} describe --always --dirty + register: rev + changed_when: false + + - name: Исходники на узле (без .git и build), лишние файлы удаляются + ansible.posix.synchronize: + src: "{{ scanner_src }}/" + dest: "{{ scanner_dir }}/" + delete: true + rsync_opts: + - "--exclude=.git" + - "--exclude=build*" + - "--exclude=.cache" + - "--exclude=__pycache__" + - "--exclude=DEPLOYED" + + - name: След клона прежнего провижнинга не нужен + ansible.builtin.file: + path: "{{ scanner_dir }}/.git" + state: absent + + - name: Метка ревизии + ansible.builtin.copy: + content: "{{ rev.stdout }}\n" + dest: "{{ scanner_dir }}/DEPLOYED" + mode: "0644" + + - name: Сборка + ansible.builtin.shell: | + cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo >/dev/null + cmake --build build -j"$(nproc)" + args: + chdir: "{{ scanner_dir }}" + register: build + changed_when: "'Building CXX' in build.stdout or 'Linking' in build.stdout" + + - name: Бинарники на месте + ansible.builtin.stat: + path: "{{ scanner_dir }}/build/{{ item }}" + register: bins + failed_when: not bins.stat.exists + loop: [peleng, scan] + + - name: Итог по узлу + ansible.builtin.debug: + msg: "[+] {{ inventory_hostname }}: {{ rev.stdout }} собран" diff --git a/env.yml b/env.yml new file mode 100644 index 0000000..4ae8327 --- /dev/null +++ b/env.yml @@ -0,0 +1,22 @@ +# Паспорт узла ~/node.env из инвентаря: SDR_ID, X, Y, SERVER. Инвентарь главный, +# файл на узле перезаписывается целиком. peleng читает паспорт только при +# старте, поэтому после смены расстановки нужен scanner-start.yml. +# ansible-playbook env.yml --diff +- name: Паспорт узла из инвентаря + hosts: all + gather_facts: false + tasks: + - name: ~/node.env + ansible.builtin.copy: + dest: ~/node.env + mode: "0644" + content: | + SDR_ID={{ sdr_id }} + X={{ x }} + Y={{ y }} + SERVER={{ server_ip }} + register: env + + - name: Итог по узлу + ansible.builtin.debug: + msg: "[{{ '+' if env.changed else 'i' }}] {{ inventory_hostname }}: SDR_ID={{ sdr_id }} X={{ x }} Y={{ y }} SERVER={{ server_ip }}{{ ' (обновлён)' if env.changed else '' }}" diff --git a/install-on-alt.sh b/install-on-alt.sh new file mode 100644 index 0000000..13c32cc --- /dev/null +++ b/install-on-alt.sh @@ -0,0 +1,3 @@ +apt-get install ansible-core python3-module-packaging glibc-locales sshpass rsync openssh-clients +export LANG=en_US.UTF-8 +ansible-galaxy collection install community.general ansible.posix diff --git a/inventory/group_vars/all/scanner.yml b/inventory/group_vars/all/scanner.yml new file mode 100644 index 0000000..8e64820 --- /dev/null +++ b/inventory/group_vars/all/scanner.yml @@ -0,0 +1,12 @@ +# Как запускать сканер: scanner-start.yml берёт эти значения на всех узлах. +# Правка тут, затем ansible-playbook scanner-start.yml. +# +# Узлу можно задать своё значение в inventory/hosts.yml (например, другой +# --lna у PortaPack node104), оно перекроет этот файл. Разовый запуск поверх +# всего: ansible-playbook scanner-start.yml -e scanner_args="--freq 2437". +# +# Профили node.py: dji24, vtx58, lte, pp24, pn24. Флаги peleng переопределяют +# профиль; калибровка сервера должна быть снята с теми же --lna и --vga. + +scanner_profile: dji24 +scanner_args: "--freq 2422 --lna 8" diff --git a/inventory/hosts.yml b/inventory/hosts.yml index ec34ed4..609abab 100644 --- a/inventory/hosts.yml +++ b/inventory/hosts.yml @@ -1,37 +1,53 @@ +# Координаты x, y в метрах, замер 27.09.2026 (комната). all: vars: - scanner_repo: ssh://git@monitor.yss.su:2222/IU9/hackrf-scanner.git - scanner_branch: feature/scanner-v2 + scanner_src: "{{ playbook_dir }}/../hackrf-scanner" + control_pubkey: ~/.ssh/id_ed25519.pub gitea_host: monitor.yss.su gitea_port: 2222 server_ip: 11.0.0.100 + scanner_dir: /home/pi/hackrf-scanner hosts: node102: - ansible_host: 192.168.1.45 + ansible_host: 11.0.0.102 sdr_id: 1 - static_ip: 11.0.0.102 sdr_serial: a32868dc35944247 - x: -0.68 - y: -1.28 + x: 0.34 + y: 0.47 + node103: + ansible_host: 11.0.0.103 + sdr_id: 6 + sdr_serial: d63861dc2d9b4353 + x: 0.77 + y: 0.60 node104: - ansible_host: 192.168.1.50 + ansible_host: 11.0.0.104 sdr_id: 2 - static_ip: 11.0.0.104 sdr_serial: 42a068dc377ab507 note: PortaPack x: 2.28 y: 0.45 node105: - ansible_host: 192.168.1.87 + ansible_host: 11.0.0.105 sdr_id: 3 - static_ip: 11.0.0.105 sdr_serial: a32868dc33894f47 - x: 3.77 - y: -0.74 - node106: - ansible_host: 192.168.1.42 - sdr_id: 4 - static_ip: 11.0.0.106 - sdr_serial: a32868dc346d2847 x: 0.00 - y: 0.50 + y: -1.02 + node106: + ansible_host: 11.0.0.106 + sdr_id: 4 + sdr_serial: a32868dc346d2847 + x: 3.77 + y: -0.78 + node107: + ansible_host: 11.0.0.107 + sdr_id: 5 + sdr_serial: b25062dc2242970b + x: 3.77 + y: 0.00 + node108: + ansible_host: 11.0.0.108 + sdr_id: 7 + sdr_serial: a32868dc33324c47 + x: -0.74 + y: 0.47 diff --git a/playbook.yml b/playbook.yml index 703a5c1..3021c25 100644 --- a/playbook.yml +++ b/playbook.yml @@ -1,3 +1,5 @@ +# Базовый провижнинг: пакеты, права на HackRF, имя узла, deploy-ключ. +# Нужен интернет на узлах (wifi-on.yml). Код на узлы кладёт deploy.yml. - name: Провижнинг приёмников пеленгации hosts: all tasks: @@ -16,10 +18,10 @@ upgrade: full tags: [base] - - name: Зависимости сборки и утилиты HackRF + - name: Зависимости сборки, утилиты HackRF, python для node.py become: true ansible.builtin.apt: - name: [cmake, g++, pkg-config, git, rsync, libhackrf-dev, libusb-1.0-0-dev, libfftw3-dev, hackrf, fish] + name: [cmake, g++, pkg-config, git, rsync, libhackrf-dev, libusb-1.0-0-dev, libfftw3-dev, hackrf, python3, fish] state: present tags: [base] @@ -76,7 +78,7 @@ - name: Ключа нет run_once: true ansible.builtin.fail: - msg: "[!] нет keys/gitea_deploy -- запустите scripts/gen-key.sh" + msg: "[!] нет keys/gitea_deploy, запустите scripts/gen-key.sh" when: not deploy_key.stat.exists tags: [key] @@ -108,57 +110,3 @@ IdentitiesOnly yes StrictHostKeyChecking accept-new tags: [key] - - - name: ~/node.env для обёртки node.sh (только засев, полевые правки не трогаем) - ansible.builtin.copy: - dest: ~/node.env - mode: "0644" - force: false - content: | - SDR_ID={{ sdr_id }} - X={{ x }} - Y={{ y }} - SERVER={{ server_ip }} - tags: [env] - - - name: Репозиторий уже клонирован? - ansible.builtin.stat: - path: ~/hackrf-scanner/.git - register: repo_dir - tags: [repo] - - - name: Локальные правки в репо (rsync-разработка)? - ansible.builtin.command: git status --porcelain - args: - chdir: ~/hackrf-scanner - register: dirty - changed_when: false - when: repo_dir.stat.exists - tags: [repo] - - - name: Stash локальных правок перед обновлением - ansible.builtin.command: git stash push -m fleet-provision - args: - chdir: ~/hackrf-scanner - when: repo_dir.stat.exists and dirty.stdout != "" - tags: [repo] - - - name: Репозиторий hackrf-scanner - ansible.builtin.git: - repo: "{{ scanner_repo }}" - dest: ~/hackrf-scanner - version: "{{ scanner_branch }}" - update: true - force: true - register: repo - tags: [repo] - - - name: Сборка - ansible.builtin.shell: | - cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo >/dev/null - cmake --build build -j4 - args: - chdir: ~/hackrf-scanner - register: build - changed_when: "'Building CXX' in build.stdout or 'Linking' in build.stdout" - tags: [build] diff --git a/poweroff.yml b/poweroff.yml new file mode 100644 index 0000000..cc70eb8 --- /dev/null +++ b/poweroff.yml @@ -0,0 +1,18 @@ +# Штатное выключение всех узлов перед снятием питания. +# Плейбук ждёт, пока ssh каждого узла перестанет отвечать. +- name: Выключение узлов + hosts: all + gather_facts: false + tasks: + - name: poweroff + become: true + community.general.shutdown: + delay: 0 + + - name: Узел ушёл из сети + delegate_to: localhost + ansible.builtin.wait_for: + host: "{{ ansible_host }}" + port: 22 + state: stopped + timeout: 90 diff --git a/reboot.yml b/reboot.yml new file mode 100644 index 0000000..2eb0a06 --- /dev/null +++ b/reboot.yml @@ -0,0 +1,19 @@ +# Перезагрузка узлов с ожиданием возврата по ssh (например, после обновления +# ядра). В конце каждый узел печатает ядро, на котором поднялся. +- name: Перезагрузка узлов + hosts: all + gather_facts: false + tasks: + - name: reboot и ожидание возврата + become: true + ansible.builtin.reboot: + reboot_timeout: 300 + + - name: Ядро после перезагрузки + ansible.builtin.command: uname -r + register: kernel + changed_when: false + + - name: Итог по узлу + ansible.builtin.debug: + msg: "[+] {{ inventory_hostname }}: поднялся, ядро {{ kernel.stdout }}" diff --git a/run.sh b/run.sh deleted file mode 100755 index 5ba4d85..0000000 --- a/run.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -# run.sh [аргументы ansible-playbook] примеры: -# ./run.sh весь парк, все теги -# ./run.sh --tags base -l node106 -# ./run.sh --check --diff сухой прогон -set -e -cd "$(dirname "$0")" -[ -f keys/gitea_deploy ] || { echo "[!] нет keys/gitea_deploy -- запустите scripts/gen-key.sh"; exit 1; } -exec ansible-playbook playbook.yml "$@" diff --git a/scanner-start.yml b/scanner-start.yml new file mode 100644 index 0000000..fad57e6 --- /dev/null +++ b/scanner-start.yml @@ -0,0 +1,23 @@ +# Запуск peleng на всех узлах одной командой node.py start: остановить прежний +# peleng и любой процесс, держащий HackRF, переинициализировать USB, запустить +# в фоне (лог /tmp/peleng.log). Профиль и флаги в inventory/group_vars/all/scanner.yml, +# разово поверх: ansible-playbook scanner-start.yml -e scanner_args="--freq 2437" +- name: Запуск сканера на узлах + hosts: all + gather_facts: false + tasks: + - name: node.py start {{ scanner_profile }} {{ scanner_args }} + ansible.builtin.command: + argv: "{{ ['python3', scanner_dir + '/scripts/node.py', 'start', scanner_profile] + scanner_args.split() }}" + register: start + changed_when: true + + - name: node.py status + ansible.builtin.command: + argv: ["python3", "{{ scanner_dir }}/scripts/node.py", "status"] + register: status + changed_when: false + + - name: Итог по узлу + ansible.builtin.debug: + msg: "{{ start.stdout_lines + status.stdout_lines }}" diff --git a/scanner-stop.yml b/scanner-stop.yml new file mode 100644 index 0000000..817d312 --- /dev/null +++ b/scanner-stop.yml @@ -0,0 +1,22 @@ +# Остановка peleng на всех узлах: node.py stop останавливает свой peleng и любой +# процесс, держащий HackRF. После этого HackRF свободен для scan или калибровки. +- name: Остановка сканера на узлах + hosts: all + gather_facts: false + tasks: + - name: node.py stop + ansible.builtin.command: + argv: ["python3", "{{ scanner_dir }}/scripts/node.py", "stop"] + register: stop + changed_when: stop.stdout | length > 0 + + - name: node.py status + ansible.builtin.command: + argv: ["python3", "{{ scanner_dir }}/scripts/node.py", "status"] + register: status + changed_when: false + failed_when: "'работает' in status.stdout" + + - name: Итог по узлу + ansible.builtin.debug: + msg: "{{ stop.stdout_lines + status.stdout_lines }}" diff --git a/vars/wifi.yml.example b/vars/wifi.yml.example new file mode 100644 index 0000000..f0f92be --- /dev/null +++ b/vars/wifi.yml.example @@ -0,0 +1,4 @@ +# Домашняя сеть для провижнинга (apt, обновления). Скопировать в vars/wifi.yml, +# он в .gitignore. Смена роутера - смена этих двух строк и прогон wifi-on.yml. +wifi_ssid: Keenetic-6852 +wifi_psk: пароль diff --git a/wifi-off.yml b/wifi-off.yml new file mode 100644 index 0000000..4f49bcf --- /dev/null +++ b/wifi-off.yml @@ -0,0 +1,19 @@ +# Перед работой Wi-Fi узлов выключается: адаптер сидит в 2,4 ГГц рядом +# с приёмником. Состояние радио NetworkManager помнит через перезагрузку, +# обратно включает только wifi-on.yml. +- name: Wi-Fi выключить + hosts: all + gather_facts: false + tasks: + - name: Радио Wi-Fi выключено + become: true + ansible.builtin.shell: | + if [ "$(nmcli radio wifi)" = disabled ]; then echo OK; else nmcli radio wifi off && echo CHANGED; fi + register: radio + changed_when: "'CHANGED' in radio.stdout" + + - name: wlan0 без адреса + ansible.builtin.command: ip -4 -o addr show wlan0 + register: wlan + changed_when: false + failed_when: wlan.stdout != "" diff --git a/wifi-on.yml b/wifi-on.yml new file mode 100644 index 0000000..dc54a8c --- /dev/null +++ b/wifi-on.yml @@ -0,0 +1,62 @@ +# Узлы подключаются к домашней сети (vars/wifi.yml) ради интернета для apt. +# Проводная сеть 11.0.0.0/24 без шлюза, поэтому маршрут по умолчанию +# и DNS приходят от Wi-Fi. В конце каждый узел обязан достучаться до интернета. +- name: Wi-Fi включить и подключить к домашней сети + hosts: all + gather_facts: false + vars_files: + - vars/wifi.yml + vars: + wifi_con: fleet-wifi + tasks: + - name: Радио Wi-Fi включено + become: true + ansible.builtin.shell: | + if [ "$(nmcli radio wifi)" = enabled ]; then echo OK; else nmcli radio wifi on && echo CHANGED; fi + register: radio + changed_when: "'CHANGED' in radio.stdout" + + - name: Профиль {{ wifi_con }} с актуальными SSID и паролем + become: true + community.general.nmcli: + conn_name: "{{ wifi_con }}" + ifname: wlan0 + type: wifi + ssid: "{{ wifi_ssid }}" + wifi_sec: + key-mgmt: wpa-psk + psk: "{{ wifi_psk }}" + autoconnect: true + state: present + register: profile + + - name: Переподключение после смены SSID или пароля + become: true + ansible.builtin.command: nmcli con down {{ wifi_con }} + when: profile.changed + failed_when: false + + - name: Подключение активно + become: true + ansible.builtin.shell: | + state=$(nmcli -t -f GENERAL.STATE con show {{ wifi_con }} | cut -d: -f2) + if [ "$state" = activated ]; then echo OK; else nmcli con up {{ wifi_con }} >/dev/null && echo CHANGED; fi + register: up + changed_when: "'CHANGED' in up.stdout" + + - name: Интернет доступен (DNS и HTTPS) + ansible.builtin.uri: + url: https://deb.debian.org/ + register: inet + retries: 6 + delay: 5 + until: inet.status == 200 + + - name: Адрес в домашней сети + ansible.builtin.command: nmcli -t -f IP4.ADDRESS con show {{ wifi_con }} + register: addr + changed_when: false + + - name: Итог по узлу + ansible.builtin.debug: + msg: "[+] {{ inventory_hostname }}: {{ addr.stdout | regex_replace('^IP4.ADDRESS\\[1\\]:', '') }}, интернет есть"