docs/ADMIN_CLEANUP.md: what is in the control-api database and what must not be touched, preparation (stop, backup, checks), ready SQL for a full reset before a new run, the event log, the check registry, single addresses and compaction, verification after the cleanup, restore from a backup, and what to do through the API instead. Every SQL block was run on a copy of the production backup. Linked from the README. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
14 KiB
Ручная очистка базы данных 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). Только так 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. Проверить, что в очереди ничего не в работе:
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 считает привязанным:
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. Он держит базу открытой и пишет в неё на каждом такте; ручные правки поверх работающего процесса ненадёжны.
cd rxprod-compose && docker compose stop control-api # compose-развёртывание
sudo systemctl stop control-api # systemd
2.4. Сделать резервную копию (штатной командой SQLite, не cp: у базы есть журнал -wal):
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. Посмотреть, что и сколько лежит (до и после чистки):
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. Полный сброс данных прогона (перед новым полным прогоном)
Очищает очередь, реестр адресов, реестр проверок, журнал событий. Валидаторы, площадки, цели, типы проверок и все настройки остаются.
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;
Затем освободите место (отдельной командой, не внутри транзакции):
PRAGMA wal_checkpoint(TRUNCATE);
VACUUM;
Файл сжимается до сотен килобайт (на проверочной копии: 20 МБ → 128 КБ).
3.2. Только журнал событий
Очередь, реестр и проверки не затрагиваются.
Весь журнал:
DELETE FROM events;
DELETE FROM sqlite_sequence WHERE name = 'events';
Только старше 7 дней (число дней меняйте в '-7 days'):
DELETE FROM events
WHERE occurred_at < strftime('%Y-%m-%dT%H:%M:%fZ', 'now', '-7 days');
3.3. Только реестр проверок (история проверок)
Адреса и их итоги в очереди остаются; пропадает подробная история проверок (на странице «Реестр» исчезнут результаты).
Вся история:
DELETE FROM checks;
DELETE FROM sqlite_sequence WHERE name = 'checks';
Оставить последние 3 цикла каждого адреса (число 3 меняйте):
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).
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):
PRAGMA wal_checkpoint(TRUNCATE);
VACUUM;
Размер и свободные страницы:
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. После очистки: запуск и проверка
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).
Проверка базы (до запуска или на копии):
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. Восстановление из копии
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 сверяет их на каждом такте и исправит расхождение, но до этого результат непредсказуем.