# План: управление ASN и FQDN через API (реализация - отдельной командой) ## Часть B. Управление ASN и FQDN через API (только план) ### Эндпоинты Изменяющие запросы требуют `X-API-Key` (как `POST /schedule`, тот же `verify_token`); чтение открыто. | Метод и путь | Действие | | :--- | :--- | | `GET /asns`, `GET /fqdns` | список из `config.json` | | `POST /asns` `{"asn": 62041}` | добавить (идемпотентно: 201 при добавлении, 200 если уже есть) | | `POST /fqdns` `{"fqdn": "example.com"}` | то же | | `DELETE /asns/{asn}?purge=false`, `DELETE /fqdns/{fqdn}?purge=false` | убрать из конфигурации; 404, если нет | ### Правила - **Валидация:** ASN - целое `1..4294967295` (pydantic `Field`); FQDN - нормализация (нижний регистр, без завершающей точки), длина до 253, метки до 63 символов из `[a-z0-9-]`, без начального и конечного дефиса, IP-литералы отклоняются. Ошибки -> 422. - **Запись конфига:** общий хелпер `update_config(mutator)` в `cidr_collector.py` (блокировка `flock` + атомарная запись), используется в `POST /schedule`, новых эндпоинтах и в `CIDRCollector.add_asn/remove_asn`, `FQDNCollector.add_fqdn/remove_fqdn` - заодно закрывает риск «CLI меняет конфиг без блокировки». - **Данные удалённого источника:** по умолчанию сохраняются. Чтобы не висеть вечно (TTL применяется только к опрашиваемым источникам), в `run_collection` под блокировкой данных записи, которых уже нет в конфигурации, проходят `merge_entry` с пустым набором: адреса истекают по `ttl_days`, пустая запись удаляется. `purge=true` удаляет запись из `data.json`/`fqdn_data.json` сразу (под блокировкой данных, после обновления конфига, без вложенных блокировок). - В `run_collection` перед слиянием конфигурация перечитывается под блокировкой данных: источник, удалённый во время сбора, не воскресает. - Новые источники подхватываются на ближайшем запуске сбора (демон читает конфиг при каждом запуске); немедленный сбор по запросу (`POST /collect`) - за рамками этого шага. ### Тесты (минимум, в контейнере) 1. Добавление/удаление ASN и FQDN: 401 без ключа, 201/200 идемпотентность, 422 на невалидные значения, 404 при удалении несуществующего, конфиг обновлён. 2. `purge=true` удаляет данные источника, без `purge` - данные остаются; при сборе запись без источника в конфигурации истекает по TTL. ### Проверка Тесты в контейнере; вручную `curl` с токеном на копии данных (добавить, увидеть в `GET /asns`, запуск сбора демоном, удалить с `purge`, адреса исчезли из `/addresses`). Зависит от `docs/plan-process-split.md` (выполняется первым).