diff --git a/README.md b/README.md index e6b9f24..b5091d4 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ # fleet Плейбуки ansible, которые приводят любую малинку парка (Raspberry Pi + -HackRF) в рабочее состояние и обслуживают её дальше: домашний Wi-Fi ради -интернета, пакеты, код `hackrf-scanner` со сборкой на месте, выключение. +HackRF) в рабочее состояние и управляют ею дальше: домашний Wi-Fi ради +интернета, пакеты, код `hackrf-scanner` со сборкой на месте, паспорт узла, +запуск и остановка сканера, перезагрузка и выключение. Управление идёт по проводной сети 11.0.0.0/24 (`ansible_host` в инвентаре), Wi-Fi нужен только на время установки пакетов и перед работой выключается, потому что адаптер сидит в 2,4 ГГц рядом с приёмником. @@ -23,11 +24,28 @@ Wi-Fi нужен только на время установки пакетов 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 playbook.yml # пакеты, права, имя ansible-playbook wifi-off.yml # Wi-Fi выключен до следующего раза ansible-playbook deploy.yml # код с этой машины, сборка на узле +ansible-playbook env.yml # паспорт ~/node.env из инвентаря ``` +## Работа + +```bash +# 1. расстановка: x, y узлов и server_ip в inventory/hosts.yml +ansible-playbook env.yml --diff # 2. паспорта на узлы +ansible-playbook scanner-start.yml # 3. peleng на всех узлах +ansible-playbook scanner-start.yml -e scanner_args="--freq 2437 --lna 8" +ansible-playbook scanner-stop.yml # HackRF свободен (scan, калибровка) +``` + +`scanner-start.yml` на каждом узле зовёт `node.py start <профиль> <флаги>`: +останавливает прежний peleng и любой процесс, держащий HackRF, переинициализирует +USB и запускает peleng в фоне с логом `/tmp/peleng.log`. Профиль и флаги по +умолчанию - `scanner_profile` и `scanner_args` в инвентаре. peleng читает паспорт +только при старте, поэтому после `env.yml` нужен повторный `scanner-start.yml`. + Новый узел сначала вписывается в `inventory/hosts.yml`. Смена роутера: правка `vars/wifi.yml` и `wifi-on.yml`, профиль на узлах обновится. @@ -37,9 +55,12 @@ ansible-playbook deploy.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), `env` (`~/node.env`, только засев) | +| `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` | штатное выключение и ожидание, пока узел пропадёт из сети | @@ -48,11 +69,10 @@ ansible-playbook deploy.yml # код с этой маши ## Инвентарь `inventory/hosts.yml`: адрес узла в проводной сети, `sdr_id`, серийник HackRF, -координаты x, y в метрах. Координаты и `server_ip` засеваются в `~/node.env` -один раз, полевые правки на узле плейбук не перетирает. После смены -расстановки в инвентаре паспорта перезаписываются явно: - - ansible-playbook playbook.yml --tags env -e env_force=true +координаты x, y в метрах. Общие переменные: `server_ip` (куда узлы шлют замеры), +`scanner_dir` (каталог сканера на узле), `scanner_profile` и `scanner_args` +(запуск по умолчанию). Инвентарь главный: `env.yml` перезаписывает паспорт узла, +правки руками на узле до следующего прогона. ## Приёмка @@ -61,3 +81,5 @@ ansible-playbook deploy.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/deploy.yml b/deploy.yml index 71f5572..050aadd 100644 --- a/deploy.yml +++ b/deploy.yml @@ -4,8 +4,6 @@ - name: Код hackrf-scanner на узлы и сборка hosts: all gather_facts: false - vars: - scanner_dest: /home/pi/hackrf-scanner tasks: - name: Ревизия исходников на управляющей машине delegate_to: localhost @@ -17,7 +15,7 @@ - name: Исходники на узле (без .git и build), лишние файлы удаляются ansible.posix.synchronize: src: "{{ scanner_src }}/" - dest: "{{ scanner_dest }}/" + dest: "{{ scanner_dir }}/" delete: true rsync_opts: - "--exclude=.git" @@ -28,13 +26,13 @@ - name: След клона прежнего провижнинга не нужен ansible.builtin.file: - path: "{{ scanner_dest }}/.git" + path: "{{ scanner_dir }}/.git" state: absent - name: Метка ревизии ansible.builtin.copy: content: "{{ rev.stdout }}\n" - dest: "{{ scanner_dest }}/DEPLOYED" + dest: "{{ scanner_dir }}/DEPLOYED" mode: "0644" - name: Сборка @@ -42,13 +40,13 @@ cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo >/dev/null cmake --build build -j"$(nproc)" args: - chdir: "{{ scanner_dest }}" + chdir: "{{ scanner_dir }}" register: build changed_when: "'Building CXX' in build.stdout or 'Linking' in build.stdout" - name: Бинарники на месте ansible.builtin.stat: - path: "{{ scanner_dest }}/build/{{ item }}" + path: "{{ scanner_dir }}/build/{{ item }}" register: bins failed_when: not bins.stat.exists loop: [peleng, scan] diff --git a/scanner-start.yml b/scanner-start.yml new file mode 100644 index 0000000..8ee6a41 --- /dev/null +++ b/scanner-start.yml @@ -0,0 +1,23 @@ +# Запуск peleng на всех узлах одной командой node.py start: остановить прежний +# peleng и любой процесс, держащий HackRF, переинициализировать USB, запустить +# в фоне (лог /tmp/peleng.log). Профиль и флаги из инвентаря или поверх: +# ansible-playbook scanner-start.yml -e scanner_args="--freq 2437 --lna 8" +- 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 }}"