Add the admin guide for manual database cleanup (SQL)
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>
This commit is contained in:
1 parent
0532baff09
commit
1366ecbdea
2 files changed
+249
No files matched your search
@@ -0,0 +1,248 @@
|
||||
# Ручная очистка базы данных 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 сверяет их на каждом такте и исправит расхождение,
|
||||
но до этого результат непредсказуем.
|
||||
Reference in new issue
Block a user