2026-10-02 16:45:59 +03:00
# Ручная очистка базы данных 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. Что в базе и что нельзя трогать
| Группа | Таблицы | Можно чистить |
|---|---|---|
2026-10-03 18:36:03 +03:00
| Данные прогона | `ip_queue` (очередь), `ip_registry` (реестр адресов), `checks` (реестр проверок), `ip_site_checks` (признаки площадок по адресам в работе), `check_runs` и `run_results` (запуски и итоги адресов в них), `events` (журнал событий) | да |
| Настройки (не трогать) | `validators` , `sites` , `target_groups` (цели), `check_types` , `inbound_checks_settings` , `settings` , `auto_cycle` , `subnets` (список подсетей для аналитики) | **нет** |
2026-10-02 16:45:59 +03:00
| Служебное | `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 ;
2026-10-03 18:36:03 +03:00
DELETE FROM run_results ;
DELETE FROM check_runs ;
2026-10-02 16:45:59 +03:00
DELETE FROM checks ;
DELETE FROM events ;
DELETE FROM ip_queue ;
DELETE FROM ip_registry ;
-- нумерация снова с 1 (необязательно)
2026-10-03 18:36:03 +03:00
DELETE FROM sqlite_sequence WHERE name IN ( 'ip_registry' , 'checks' , 'ip_queue' , 'events' , 'check_runs' );
2026-10-02 16:45:59 +03:00
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 );
2026-10-03 18:36:03 +03:00
DELETE FROM run_results WHERE registry_id IN ( SELECT id FROM doomed_reg );
2026-10-02 16:45:59 +03:00
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 сверяет их на каждом такте и исправит расхождение,
но до этого результат непредсказуем.