diff --git a/docs/analysis-2026-09-21.md b/docs/analysis-2026-09-21.md index c5812f1..804083f 100644 --- a/docs/analysis-2026-09-21.md +++ b/docs/analysis-2026-09-21.md @@ -2,7 +2,7 @@ Состояние после 17 доработок (план и итоги каждой лежат в `docs/`): надёжность и безопасность, тесты в контейнере, форматы вывода, разделение процессов, управление ASN/FQDN через API, контейнер приложения, SQLite, `POST /collect`, `GET /addresses/diff`, репозиторий git, закрепление версий, резервные копии и автовосстановление, защита ввода и данных, защита от пустой выдачи, исправления ревью 5-10, защита от пустых копий, наблюдаемость. Предыдущая версия этого файла описывала состояние после восьми доработок. Отчёт ревью: `review-2026-09-21.md` (находки 1-11 закрыты). -Тестовый запуск на копиях боевых файлов с реальным ASN 62041 выполнен и описан в `summary-real-data-run.md`. +Тестовый запуск на копиях боевых файлов с реальным ASN 62041 описан в `summary-real-data-run.md`; **боевое развёртывание в контейнерах на порту 18000 выполнено 2026-09-21** (`summary-production-deploy.md`, работает по расписанию). Проект: 7 модулей Python, 1719 строк (`db.py` 544, `cidr_collector.py` 386, `api_server.py` 381, `collector_daemon.py` 191, `formatters.py` 115, `storage.py` 70, `healthcheck.py` 32), 30 тестов (27 функций, 5 файлов и `conftest.py`), 37 документов в `docs/` (17 планов, 17 итогов, 2 анализа, ревью), 9 коммитов, ветка `main` синхронизирована с `origin` (`artstore.rxmsk.ru`). @@ -32,6 +32,7 @@ | Защита от пустой выдачи | Потеря базы без копий или восстановление из пустой копии при настроенных источниках: метка `db_recreated.json`, `503` на `/addresses` и `/addresses/diff` до нового сбора; пустая база не копируется. | | Данные DNS и внешний источник | Фильтр глобальных адресов (`allow_non_global_ips`), повторы запросов к RIPEstat с `sourceapp` и потолком `Retry-After`. | | Наблюдаемость | Состояние каждого источника (таблица `source_status`), блок `sources` и `degraded` в `/health`, `GET /sources`, итоговая строка запуска в логе. | +| Боевое развёртывание | Compose на `192.168.5.9:18000` (доступ открыт для всех, токен в `.env`), шесть ASN и три FQDN, миграция боевых файлов без потерь, плановый запуск проверен; копии на томе (`summary-production-deploy.md`). | | Ревью и граф знаний | Отчёт ревью (11 находок, все закрыты), граф `graphify-out/` (вне git и образа). | | Тесты | 30 проверок, запуск в контейнере, изоляция файлов состояния (`conftest.py`). | @@ -39,7 +40,6 @@ | Направление | Статус | |---|---| -| Боевое развёртывание с полной конфигурацией | Не начато; тестовый запуск на копиях боевых файлов с AS62041 выполнен (`summary-real-data-run.md`) | | Уведомления (webhook, Telegram) | Не начато; основа (журнал, `/health`, `/sources`) есть | | Метрики Prometheus (`/metrics`) | Исключены из плана решением пользователя; при необходимости - отдельная доработка | | Ограничение частоты `POST /collect` | Не начато | @@ -59,7 +59,7 @@ | 6 | Один общий токен, без ротации и аудита. | Не закрыт | | 7 | Тестов минимум, что соответствует правилам проекта. | Осознанно | | 8 | `POST /collect` без ограничения частоты: повторные запросы во время сбора пропускаются, но защиты от нагрузки на RIPE нет (при этом запросы к RIPEstat теперь идут с повторами). | Не закрыт | -| 9 | Журнал diff и состояние источников проверены на копиях боевых файлов и одном реальном ASN (база 45 КБ, ответы 6-9 мс); поведение при шести ASN, по расписанию и во времени (TTL, рост журнала) не наблюдалось. | Частично закрыт | +| 9 | Журнал diff и состояние источников: на боевом развёртывании с шестью ASN и расписанием база и ответы малы (десятки КБ, миллисекунды); поведение во времени (сутки и более, TTL, рост журнала) ещё предстоит наблюдать. | Частично закрыт | | 10 | Копии базы лежат на том же томе, что и база: защита от порчи файла, но не от потери тома. | Не закрыт (описан в README) | | 11 | Нет активных оповещений: о сбое источников можно узнать только опросом `/health` или из лога. | Не закрыт | @@ -67,7 +67,7 @@ | # | Наблюдение | Состояние | |---|---|---| -| 1 | **Боевое развёртывание не выполнено.** Миграция боевых файлов проверена в изолированном стенде на их копиях (`summary-real-data-run.md`: без потерь, сбор AS62041 и восстановление на реальных данных работают). В каталоге проекта нет `ripe.db`; `data.json` (6 ASN) и `fqdn_data.json` (4 имени) остались в старом формате; всё проверено только на копиях. Первый запуск на боевых данных выполнит миграцию сразу до схемы версии 3: `last_seen` старых записей станет равным времени миграции, журнал diff и состояние источников начнутся пустыми (клиентам стартовать с `X-Changes-Cursor`), первые запуски сбора создадут состояние источников. | Частично закрыто | +| 1 | ~~Боевое развёртывание не выполнено.~~ **Выполнено 2026-09-21** (`summary-production-deploy.md`); ниже - исходное описание. Миграция боевых файлов проверена в изолированном стенде на их копиях (`summary-real-data-run.md`: без потерь, сбор AS62041 и восстановление на реальных данных работают). В каталоге проекта нет `ripe.db`; `data.json` (6 ASN) и `fqdn_data.json` (4 имени) остались в старом формате; всё проверено только на копиях. Первый запуск на боевых данных выполнит миграцию сразу до схемы версии 3: `last_seen` старых записей станет равным времени миграции, журнал diff и состояние источников начнутся пустыми (клиентам стартовать с `X-Changes-Cursor`), первые запуски сбора создадут состояние источников. | Закрыто | | 2 | ~~`/health` не видит сбоев источников.~~ Сбои учитываются по каждому источнику, порог `source_failure_threshold` (по умолчанию 3): при суточном расписании FQDN это три дня до `degraded`. | Закрыто | | 3 | **Безымянные образы Docker: 21 на хосте.** Часть - от пересборок тестового образа `ripe-tests` при разработке, на хосте есть и чужие (`docker image prune` затронет все). | Ухудшилось (было 3) | | 4 | **Повреждённый `config.json`** переименовывается при чтении; первый успешный `POST /asns` после этого создаст файл без остальных источников, расписания и `ttl_days`. | Без изменений | @@ -83,7 +83,7 @@ ## Рекомендуемый порядок -1. **Боевое развёртывание с полной конфигурацией (главный шаг; тестовый запуск с AS62041 пройден).** Перед запуском: копия `config.json`, `data.json`, `fqdn_data.json` вне каталога проекта и вне тома (миграция переименует оригиналы в `*.migrated-*`, но копия на случай ошибки обязательна). Затем `docker compose up -d` с переносом файлов в том (порядок в README), проверка `/health`, `/sources`, `/addresses` и `/addresses/diff`, первый ручной сбор через `POST /collect`, оценка размера базы и журнала, выбор порога `source_failure_threshold`. Нужен отдельный план с откатом. +1. ~~Боевое развёртывание~~ **выполнено** (порт 18000, шесть ASN); далее - наблюдение: 03:00 плановый сбор FQDN, 04:30 первая плановая копия, суточный просмотр `/health` и `/sources`. Исходный порядок запуска: копия `config.json`, `data.json`, `fqdn_data.json` вне каталога проекта и вне тома (миграция переименует оригиналы в `*.migrated-*`, но копия на случай ошибки обязательна). Затем `docker compose up -d` с переносом файлов в том (порядок в README), проверка `/health`, `/sources`, `/addresses` и `/addresses/diff`, первый ручной сбор через `POST /collect`, оценка размера базы и журнала, выбор порога `source_failure_threshold`. Нужен отдельный план с откатом. 2. **Обновить граф** (`/graphify . --update`, документы выгружать целиком) и при желании поставить хук после коммита. 3. **Уведомления** (webhook, Telegram) на основе журнала и состояния источников: закрывает риск 11. 4. **Архитектурный рефакторинг:** `settings.py` (пути и умолчания), разделение `db.py` и `api_server.py`; снимает наблюдения 10-11. diff --git a/docs/plan-production-deploy.md b/docs/plan-production-deploy.md new file mode 100644 index 0000000..6d10314 --- /dev/null +++ b/docs/plan-production-deploy.md @@ -0,0 +1,28 @@ +# План: боевое развёртывание в контейнерах (порт 18000) + +Источник: `docs/analysis-2026-09-21.md` (рекомендуемый порядок, п. 1), `docs/summary-real-data-run.md` (тестовый запуск с AS62041 пройден). + +## Решения пользователя +- Токен записывается в переменные окружения проекта (`.env`, вне git). +- Развёртывание в контейнерах на порту **18000** (если свободен; проверено: свободен). +- Доступ открыт для всех: порт публикуется на всех интерфейсах хоста (доверенный контур; TLS нет - риск 5 анализа принят). +- Резервные копии остаются на томе `/data/backups`, отдельно не выносятся (риск 10 принят). + +## Параметры +- Проект Compose по умолчанию (`ripe_cidr_collector`), образ `ripe-cidr-collector`, том `ripe_cidr_collector_ripe_data`, перезапуск `unless-stopped` (Docker на хосте включён при загрузке). +- `.env` (права 600): `RIPE_API_TOKEN` (случайный, 64 hex-символа), `API_PORT=18000`, `TZ=Europe/Moscow` (часовой пояс хоста; расписания `*/15` для ASN, `0 3 * * *` для FQDN и `30 4 * * *` для копий считаются по нему). +- Данные: в том копируются **копии** реальных `config.json` (шесть ASN и три FQDN), `data.json`, `fqdn_data.json`; исходные файлы проекта не меняются (сверка контрольных сумм). Миграция в SQLite выполняется при первом обращении. + +## Шаги +1. Проверка предпосылок, контрольные суммы исходных файлов. +2. Токен и `.env`; сборка образа; перенос копий файлов в том; `docker compose up -d`. +3. Проверка: сервисы `healthy`, миграция без потерь (24 префикса, 4 значения FQDN), часовой пояс контейнеров. +4. Первый сбор по всем источникам (`POST /collect`): `/sources`, `/health`, `/addresses`, diff; источник AS11917 (в данных февраля был пуст). +5. Доступ извне: запрос по адресу хоста (не `127.0.0.1`), запись без токена отклоняется (401), с токеном проходит. +6. Наблюдение штатного расписания (ближайший квартал часа для ASN), если ожидание короткое. +7. Итоги `docs/summary-production-deploy.md`, обновление анализа, сверка сумм исходных файлов. + +## Риски и откат +- Токен передаётся по HTTP открытым текстом, порт доступен всем в сети: принято (доверенный контур). +- Копии на том же томе: защита от порчи файла, не от потери тома: принято. +- Откат: `docker compose down` (данные остаются в томе) или `docker compose down -v` (с удалением тома); исходные файлы проекта не затрагиваются. diff --git a/docs/summary-production-deploy.md b/docs/summary-production-deploy.md new file mode 100644 index 0000000..bc7a537 --- /dev/null +++ b/docs/summary-production-deploy.md @@ -0,0 +1,33 @@ +# Итоги: боевое развёртывание в контейнерах (порт 18000) + +План: `docs/plan-production-deploy.md`. Предшествовал тестовый запуск `docs/summary-real-data-run.md`. + +## Параметры развёртывания +- **Адрес:** `http://192.168.5.9:18000` (порт опубликован на всех интерфейсах хоста, доступ открыт для всех в доверенном контуре, TLS нет; риск 5 принят). Файрвол на хосте входящий трафик не фильтрует (`INPUT ACCEPT`). +- **Токен:** `RIPE_API_TOKEN` (64 hex-символа, сгенерирован) записан в `/opt/lvraid/claude/ripe_cidr_collector/.env` (права 600, файл в `.gitignore`); там же `API_PORT=18000` и `TZ=Europe/Moscow` (часовой пояс хоста: расписания считаются по московскому времени). Смена токена: изменить `.env` и выполнить `docker compose up -d`. +- **Контейнеры:** проект Compose по умолчанию (`ripe_cidr_collector`), сервисы `api` и `collector`, образ `ripe-cidr-collector`, том `ripe_cidr_collector_ripe_data`, перезапуск `unless-stopped` (Docker на хосте включён при загрузке). +- **Данные:** в том скопированы копии реальных `config.json` (6 ASN: 62014, 62041, 59930, 44907, 211157, 11917; 3 FQDN), `data.json`, `fqdn_data.json`; исходные файлы проекта не менялись (контрольные суммы совпали). +- **Расписание:** ASN `*/15 * * * *`, FQDN `0 3 * * *`, копия базы `30 4 * * *` (по умолчанию), копии на том же томе (`/data/backups`, 7 штук), отдельно не выносятся (риск 10 принят). + +## Результаты проверки +| Проверка | Итог | +|---|---| +| Сервисы | `api` и `collector` `healthy`, порт `0.0.0.0:18000`, часовой пояс контейнеров MSK. | +| Миграция | Схема версии 3, 24 префикса и 4 значения FQDN (28 строк) без потерь, оригиналы в томе переименованы, журнал пуст. | +| Первый сбор (`POST /collect`, реальные RIPEstat и DNS) | 6 ASN из 6 успешно, 3 FQDN из 3 успешно; `+18` префиксов и `+3` строки IP; сбоев нет. | +| Состояние источников | `/sources`: у всех источников 0 сбоев; AS11917 отвечает без префиксов (`addresses: 0`, успех), как и в данных февраля. | +| Diff | С момента миграции 19 добавлений, 0 удалений; все старые значения подтверждены RIPE. AS62014 теперь анонсирует и прежние префиксы, и их более специфичные части (`91.108.16.0/23`, `91.108.18.0/23`, `91.108.56.0/24`, `91.108.57.0/24`): для потребителей есть смысл использовать `aggregate=true`. | +| Доступ извне | По адресу хоста: `/health` 200, `/addresses` 45 значений; запись без токена и с неверным токеном - 401. | +| Штатное расписание | Плановый запуск ASN в 11:45:00: 6 из 6, `+0/-0`, ошибок нет; следующий 12:00. | +| Логи | Ошибок и трейсбеков нет. | + +## Что наблюдать +- **Завтра 03:00:** первый плановый сбор FQDN; **04:30:** первая плановая копия базы (`/health` -> `jobs.backup`, каталог `/data/backups`). +- `GET /health` (`status`, `sources.*.failing`) и `GET /sources`; порог сбоев `source_failure_threshold` = 3. +- `google.com` (адрес из старого файла, в конфигурации его нет) истечёт по TTL через 90 дней. +- Размер базы и журнала (после миграции: десятки КБ). + +## Замечания +- Токен хранится открытым текстом в `.env` на хосте и передаётся по HTTP (доверенный контур, риск 5); один общий токен без ротации и аудита (риск 6). +- Копии на том же томе не защищают от потери тома (риск 10). +- Управление: `docker compose ps`, `docker compose logs -f collector`, `docker compose down` (данные остаются в томе), `docker compose up -d`; обновление после изменений кода: `docker compose build && docker compose up -d`.