# Ручная очистка базы данных control-api (SQL) Когда нужна: подготовка к новому полному прогону, разбор после инцидента, освобождение места, удаление отдельных адресов. Все примеры проверены 2026-10-02 на копии боевой БД (20 валидаторов, 4 площадки, 6445 адресов в реестре, 29 889 проверок, 19 897 событий): без ошибок, `integrity_check` = `ok`, нарушений внешних ключей нет. > **Сначала API.** Если в очереди есть адреса в работе, очищайте очередь штатно: кнопка «Очистить всё» на `/ips` или > `POST /api/v1/admin/ips/clear` (см. [USAGE.md](USAGE.md#удаление-адресов-из-очереди)). Только так control-api отвяжет Floating IP от портов > валидаторов. SQL ниже работает с базой «в покое»: он не обращается к OpenStack. ## 1. Что в базе и что нельзя трогать | Группа | Таблицы | Можно чистить | |---|---|---| | Данные прогона | `ip_queue` (очередь), `ip_registry` (реестр адресов), `checks` (реестр проверок), `ip_site_checks` (признаки площадок по адресам в работе), `events` (журнал событий) | да | | Настройки (не трогать) | `validators`, `sites`, `target_groups` (цели), `check_types`, `inbound_checks_settings`, `settings`, `auto_cycle` | **нет** | | Служебное | `sqlite_sequence` (нумерация записей), `PRAGMA user_version` (версия схемы) | нумерацию можно сбросить, версию не менять | Связи (внешние ключи): `checks`, `events`, `ip_site_checks` ссылаются на `ip_queue`; `checks`, `events`, `ip_queue` — на `ip_registry`; `validators.current_ip_id` — на `ip_queue`. Поэтому порядок удаления всегда такой: сначала `validators.current_ip_id` в `NULL`, затем `ip_site_checks`, `checks`, `events`, `ip_queue` и в конце `ip_registry`. Времена в БД хранятся строками `2026-10-02T07:14:58.857Z` (UTC). ## 2. Подготовка (всегда, перед любой очисткой) **2.1. Где лежит база и чем её открывать.** Нужен клиент `sqlite3` на хосте (`apt install sqlite3`). | Развёртывание | Файл базы | |---|---| | `rxprod-compose/` (боевой стенд) | `rxprod-compose/capi-db/control-api.db` | | Docker (`deploy/docker`) | в томе `cloud-ip-validator-db`: `docker volume inspect cloud-ip-validator-db --format '{{.Mountpoint}}'`, файл `control-api.db` в этом каталоге (нужен root) | | systemd | `/var/lib/cloud-ip-validator/control-api.db` (`database.path` в `control-api.yaml`) | Дальше в примерах `DB=путь/к/control-api.db`. **2.2. Проверить, что в очереди ничего не в работе:** ```bash sqlite3 -readonly "$DB" " SELECT state, COUNT(*) FROM ip_queue WHERE state NOT IN ('done', 'failed', 'occupied') GROUP BY state;" ``` Пустой вывод — всё завершено. Адреса в работе есть — сначала «Очистить всё» через API (см. выше). Затем проверьте в OpenStack, что на портах валидаторов нет лишних Floating IP; по базе видно только то, что control-api считает привязанным: ```bash sqlite3 -readonly "$DB" " SELECT ip_address, state, fip_id FROM ip_queue WHERE fip_id <> '' AND state NOT IN ('done', 'failed', 'occupied');" ``` **2.3. Остановить control-api.** Он держит базу открытой и пишет в неё на каждом такте; ручные правки поверх работающего процесса ненадёжны. ```bash cd rxprod-compose && docker compose stop control-api # compose-развёртывание sudo systemctl stop control-api # systemd ``` **2.4. Сделать резервную копию** (штатной командой SQLite, не `cp`: у базы есть журнал `-wal`): ```bash TS=$(date -u +%Y-%m-%d_%H-%M) sqlite3 "$DB" ".backup '$(dirname "$DB")/backup-$TS-before-cleanup.db'" sqlite3 -readonly "$(dirname "$DB")/backup-$TS-before-cleanup.db" "PRAGMA integrity_check;" # должно быть: ok ``` Лог контейнера до чистки при необходимости сохраните отдельно: `docker logs <контейнер> > backup-$TS.container.log 2>&1`. **2.5. Посмотреть, что и сколько лежит** (до и после чистки): ```bash sqlite3 -readonly "$DB" " SELECT 'ip_queue' AS tbl, COUNT(*) AS n FROM ip_queue UNION ALL SELECT 'ip_registry', COUNT(*) FROM ip_registry UNION ALL SELECT 'checks', COUNT(*) FROM checks UNION ALL SELECT 'ip_site_checks', COUNT(*) FROM ip_site_checks UNION ALL SELECT 'events', COUNT(*) FROM events UNION ALL SELECT 'validators', COUNT(*) FROM validators UNION ALL SELECT 'sites', COUNT(*) FROM sites;" ``` ## 3. Сценарии Команды выполняются так: `sqlite3 "$DB"` и вставить блок, либо сохранить блок в файл и выполнить `sqlite3 "$DB" < файл.sql`. ### 3.1. Полный сброс данных прогона (перед новым полным прогоном) Очищает очередь, реестр адресов, реестр проверок, журнал событий. Валидаторы, площадки, цели, типы проверок и все настройки остаются. ```sql PRAGMA foreign_keys = ON; BEGIN; -- валидаторы больше не ссылаются на адреса очереди UPDATE validators SET current_ip_id = NULL WHERE current_ip_id IS NOT NULL; UPDATE validators SET state = 'idle' WHERE state = 'assigned'; -- порядок важен: сначала зависимые таблицы DELETE FROM ip_site_checks; DELETE FROM checks; DELETE FROM events; DELETE FROM ip_queue; DELETE FROM ip_registry; -- нумерация снова с 1 (необязательно) DELETE FROM sqlite_sequence WHERE name IN ('ip_registry', 'checks', 'ip_queue', 'events'); COMMIT; ``` Затем освободите место (отдельной командой, не внутри транзакции): ```sql PRAGMA wal_checkpoint(TRUNCATE); VACUUM; ``` Файл сжимается до сотен килобайт (на проверочной копии: 20 МБ → 128 КБ). ### 3.2. Только журнал событий Очередь, реестр и проверки не затрагиваются. Весь журнал: ```sql DELETE FROM events; DELETE FROM sqlite_sequence WHERE name = 'events'; ``` Только старше 7 дней (число дней меняйте в `'-7 days'`): ```sql DELETE FROM events WHERE occurred_at < strftime('%Y-%m-%dT%H:%M:%fZ', 'now', '-7 days'); ``` ### 3.3. Только реестр проверок (история проверок) Адреса и их итоги в очереди остаются; пропадает подробная история проверок (на странице «Реестр» исчезнут результаты). Вся история: ```sql DELETE FROM checks; DELETE FROM sqlite_sequence WHERE name = 'checks'; ``` Оставить последние 3 цикла каждого адреса (число `3` меняйте): ```sql DELETE FROM checks WHERE cycle_id <= (SELECT MAX(c2.cycle_id) FROM checks c2 WHERE c2.registry_id = checks.registry_id) - 3; ``` Постоянное ограничение глубины истории лучше задать настройкой `history_retention_cycles` (страница `/settings` или `PUT /api/v1/admin/config/orchestrator`): control-api сам подрезает историю при завершении каждого адреса. SQL выше нужен для разовой чистки. ### 3.4. Удалить конкретные адреса целиком Удаляет адрес из очереди и реестра вместе со всей его историей (проверки и события). Список адресов подставьте в первую команду `CREATE TEMP TABLE doomed_reg`. Адрес, который сейчас проверяется, удалять этим способом нельзя: используйте API (раздел 5). ```sql PRAGMA foreign_keys = ON; BEGIN; CREATE TEMP TABLE doomed_reg AS SELECT id FROM ip_registry WHERE ip_address IN ('5.188.140.6', '5.188.140.62'); -- ваши адреса CREATE TEMP TABLE doomed_ip AS SELECT id FROM ip_queue WHERE registry_id IN (SELECT id FROM doomed_reg); UPDATE validators SET current_ip_id = NULL WHERE current_ip_id IN (SELECT id FROM doomed_ip); DELETE FROM ip_site_checks WHERE ip_id IN (SELECT id FROM doomed_ip); DELETE FROM checks WHERE registry_id IN (SELECT id FROM doomed_reg); DELETE FROM events WHERE registry_id IN (SELECT id FROM doomed_reg) OR ip_id IN (SELECT id FROM doomed_ip); DELETE FROM ip_queue WHERE id IN (SELECT id FROM doomed_ip); DELETE FROM ip_registry WHERE id IN (SELECT id FROM doomed_reg); DROP TABLE doomed_ip; DROP TABLE doomed_reg; COMMIT; ``` ### 3.5. Только освободить место Если удалили много, а файл не уменьшился (SQLite не отдаёт место ОС до `VACUUM`): ```sql PRAGMA wal_checkpoint(TRUNCATE); VACUUM; ``` Размер и свободные страницы: ```sql SELECT page_count * page_size / 1024 AS size_kb, freelist_count * page_size / 1024 AS free_kb FROM pragma_page_count(), pragma_page_size(), pragma_freelist_count(); ``` ## 4. После очистки: запуск и проверка ```bash cd rxprod-compose && docker compose up -d --no-deps control-api # или: sudo systemctl start control-api ``` Если нужно, чтобы и лог контейнера начался с нуля, пересоздайте контейнер: `docker compose up -d --force-recreate --no-deps control-api` (старый лог сохраните заранее, п. 2.4). Проверка базы (до запуска или на копии): ```bash sqlite3 -readonly "$DB" " PRAGMA integrity_check; PRAGMA foreign_key_check; SELECT state, COUNT(*) FROM validators GROUP BY state; SELECT COUNT(*) AS validators_with_address FROM validators WHERE current_ip_id IS NOT NULL; SELECT COUNT(*) AS queue_rows FROM ip_queue;" ``` Ожидается: `ok`; пустой результат `foreign_key_check`; у валидаторов состояние `idle`; `validators_with_address` = 0; для полного сброса `queue_rows` = 0. Через API: `GET /api/v1/admin/status` (`total_ips` = 0, `total_validators` = число валидаторов) и `GET /api/v1/admin/validators` (через 10–15 секунд после запуска у всех свежий `last_heartbeat_at`). ## 5. Что делать через API, а не через SQL | Задача | Как | |---|---| | Остановить проверку адреса, удалить адрес в работе | `POST /api/v1/admin/ips/{ip}/cancel`, `DELETE /api/v1/admin/ips/{ip}` | | Очистить всю очередь с отвязкой Floating IP | `POST /api/v1/admin/ips/clear` | | Перепроверить завершённые адреса | `POST /api/v1/admin/ips` со списком адресов | | Валидатор «завис» с адресом | ничего не править: лизинг истечёт, адрес вернётся в очередь, валидатор освободится сам | | Добавить/убрать валидатор, площадку, цель | `/api/v1/admin/config/*` или страницы дашборда | ## 6. Восстановление из копии ```bash cd rxprod-compose && docker compose stop control-api cp capi-db/backup-<метка>-before-cleanup.db capi-db/control-api.db rm -f capi-db/control-api.db-wal capi-db/control-api.db-shm # старый журнал к новой копии не относится docker compose up -d --no-deps control-api ``` ## 7. Ловушки - Не выполняйте `DELETE` при работающем control-api: он пишет в ту же базу. - Не удаляйте строки настроек (`validators`, `sites`, `target_groups`, `check_types`, `inbound_checks_settings`, `settings`, `auto_cycle`): после этого control-api либо не стартует, либо работает без площадок и целей. - Не нарушайте порядок удаления (раздел 1) и не отключайте `PRAGMA foreign_keys = ON` в блоках выше: база сама остановит ошибочное удаление. - `VACUUM` нельзя вызывать внутри транзакции и пока control-api запущен. - Не копируйте файл базы командой `cp` при работающем процессе: журнал `-wal` останется в неконсистентном состоянии. Используйте `.backup`. - Не меняйте `PRAGMA user_version`: по нему control-api применяет миграции схемы. - Не правьте состояние адресов и валидаторов вручную (`state`, `owner_validator_id`, `lease_expires_at`) вместо API: control-api сверяет их на каждом такте и исправит расхождение, но до этого результат непредсказуем.