feat(db): implement PostgreSQL monitoring and maintenance features
CI / changes (push) Successful in 9s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 26s
CI / web (push) Successful in 33s
CI / go (push) Successful in 2m11s
CI / bird2 (push) Successful in 16s
CI / release (push) Successful in 3m27s
CI / changes (push) Successful in 9s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 26s
CI / web (push) Successful in 33s
CI / go (push) Successful in 2m11s
CI / bird2 (push) Successful in 16s
CI / release (push) Successful in 3m27s
Added PostgreSQL monitoring and maintenance capabilities to the API, including new endpoints for instance-level metrics, maintenance operations, and job scheduling. Updated the HTTP API to support PostgreSQL monitoring routes and integrated a background scheduler for metrics collection. Enhanced the CLI with database commands for maintenance tasks. Updated documentation to reflect these changes.
This commit is contained in:
@@ -52,6 +52,18 @@ opkey|01ARZ3NDEKTSV4RRFFQ69G5FAV|operator,nodekey|01ARZ3NDEKTSV4RRFFQ69G5FAV|nod
|
||||
|
||||
**Запрещено** в продакшене: не оставляйте demo-seed с известным токеном `dev` на боевых данных. Переменная `EVOBGP_DEV_INSECURE` в текущей версии **не влияет** на аутентификацию (оставлена в compose для совместимости; не включайте в production — см. SEC-02 в инженерных правилах).
|
||||
|
||||
### PostgreSQL monitoring и maintenance (control plane)
|
||||
|
||||
При `EVOBGP_DATABASE_URL` (не memory backend):
|
||||
|
||||
| Операция | Минимальная роль |
|
||||
|----------|------------------|
|
||||
| `GET /v1/monitoring/postgres/*`, `GET /v1/monitoring/correlation` | viewer |
|
||||
| `POST /v1/postgres/vacuum`, `vacuum-analyze`, `analyze`, `reindex`, `cleanup` | **operator** (async job, rate limit 60s на kind) |
|
||||
| `GET /v1/postgres/maintenance/logs` | viewer |
|
||||
|
||||
Метрики **instance-level** (не per-tenant). CLI: `evobgp-api db …` / `evobgp-all db …`.
|
||||
|
||||
### Синхронные «тяжёлые» GET (control plane)
|
||||
|
||||
- `POST /v1/modules/{module_id}/cdn-sources/preview` — загрузка CDN в том же HTTP-запросе (лимит тела ~8 MiB, см. OpenAPI).
|
||||
|
||||
@@ -8,6 +8,21 @@ Runbook для оценки объёма БД и узких мест **пере
|
||||
psql "$EVOBGP_DATABASE_URL"
|
||||
```
|
||||
|
||||
## HTTP API (панель / мониторинг)
|
||||
|
||||
При подключённом PostgreSQL control plane отдаёт instance-level метрики (роль **viewer+**):
|
||||
|
||||
- `GET /v1/monitoring/postgres/overview` — подключения, TPS, cache hit, размер БД
|
||||
- `GET /v1/monitoring/postgres/queries` — top queries (`pg_stat_statements`, если extension включён)
|
||||
- `GET /v1/monitoring/postgres/locks`, `/tables`, `/recommendations`
|
||||
- `GET /v1/monitoring/correlation?window=60` — корреляция refresh jobs и cache hit
|
||||
|
||||
Обслуживание (**operator**, async `202` + `job_id`): `POST /v1/postgres/vacuum`, `vacuum-analyze`, `analyze`, `reindex`, `cleanup`; журнал `GET /v1/postgres/maintenance/logs`.
|
||||
|
||||
CLI на CP: `evobgp-api db report|vacuum|analyze|cleanup` (см. `internal/dbcli`).
|
||||
|
||||
Миграция `000023` создаёт `pg_stat_statements`; в production может потребоваться `shared_preload_libraries` и перезапуск Postgres.
|
||||
|
||||
## 1. Размеры таблиц и индексов
|
||||
|
||||
```sql
|
||||
|
||||
@@ -49,6 +49,8 @@ tags:
|
||||
description: Управление API-ключами tenant (operator). Секрет возвращается только при создании и ротации.
|
||||
- name: Auth
|
||||
description: Сессия текущего API-ключа (tenant и роль).
|
||||
- name: Monitoring
|
||||
description: Наблюдаемость PostgreSQL и корреляция (instance-level, viewer+). Maintenance — operator.
|
||||
|
||||
security:
|
||||
- bearerAuth: []
|
||||
@@ -910,6 +912,64 @@ components:
|
||||
type: string
|
||||
additionalProperties: true
|
||||
|
||||
PostgresOverview:
|
||||
type: object
|
||||
description: Instance-level PostgreSQL snapshot (GET /v1/monitoring/postgres/overview).
|
||||
additionalProperties: true
|
||||
|
||||
PostgresQueriesResponse:
|
||||
type: object
|
||||
properties:
|
||||
collected_at:
|
||||
type: string
|
||||
format: date-time
|
||||
source:
|
||||
type: string
|
||||
enum: [live, snapshot]
|
||||
items:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
|
||||
PostgresRecommendations:
|
||||
type: object
|
||||
properties:
|
||||
collected_at:
|
||||
type: string
|
||||
format: date-time
|
||||
items:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
severity:
|
||||
type: string
|
||||
code:
|
||||
type: string
|
||||
title:
|
||||
type: string
|
||||
detail:
|
||||
type: string
|
||||
refs:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
|
||||
PostgresMaintenanceBody:
|
||||
type: object
|
||||
properties:
|
||||
table:
|
||||
type: string
|
||||
dry_run:
|
||||
type: boolean
|
||||
default: false
|
||||
policy:
|
||||
type: string
|
||||
description: job_audit_retention | asn_cache_retention
|
||||
limit:
|
||||
type: integer
|
||||
|
||||
BirdLocalStatus:
|
||||
type: object
|
||||
description: Статус локального BIRD на хосте API (GET /v1/bird/status).
|
||||
@@ -3135,6 +3195,278 @@ paths:
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultProblem"
|
||||
|
||||
/v1/monitoring/postgres/overview:
|
||||
get:
|
||||
tags: [Monitoring]
|
||||
summary: PostgreSQL overview (instance-level)
|
||||
operationId: getPostgresOverview
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/TenantId"
|
||||
responses:
|
||||
"200":
|
||||
description: Успешно.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/PostgresOverview"
|
||||
"503":
|
||||
description: PostgreSQL backend не подключён.
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultProblem"
|
||||
|
||||
/v1/monitoring/postgres/queries:
|
||||
get:
|
||||
tags: [Monitoring]
|
||||
summary: Top queries (pg_stat_statements or snapshot)
|
||||
operationId: getPostgresQueries
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/TenantId"
|
||||
- $ref: "#/components/parameters/Limit"
|
||||
responses:
|
||||
"200":
|
||||
description: Успешно.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/PostgresQueriesResponse"
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultProblem"
|
||||
|
||||
/v1/monitoring/postgres/locks:
|
||||
get:
|
||||
tags: [Monitoring]
|
||||
summary: Active locks
|
||||
operationId: getPostgresLocks
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/TenantId"
|
||||
responses:
|
||||
"200":
|
||||
description: Успешно.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
items:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultProblem"
|
||||
|
||||
/v1/monitoring/postgres/tables:
|
||||
get:
|
||||
tags: [Monitoring]
|
||||
summary: Table sizes and scan stats
|
||||
operationId: getPostgresTables
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/TenantId"
|
||||
- $ref: "#/components/parameters/Limit"
|
||||
responses:
|
||||
"200":
|
||||
description: Успешно.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
items:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultProblem"
|
||||
|
||||
/v1/monitoring/postgres/recommendations:
|
||||
get:
|
||||
tags: [Monitoring]
|
||||
summary: Heuristic optimization recommendations
|
||||
operationId: getPostgresRecommendations
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/TenantId"
|
||||
responses:
|
||||
"200":
|
||||
description: Успешно.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/PostgresRecommendations"
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultProblem"
|
||||
|
||||
/v1/monitoring/correlation:
|
||||
get:
|
||||
tags: [Monitoring]
|
||||
summary: Timeline correlation (jobs vs cache hit)
|
||||
operationId: getMonitoringCorrelation
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/TenantId"
|
||||
- name: window
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 60
|
||||
description: Window in minutes (max 1440).
|
||||
responses:
|
||||
"200":
|
||||
description: Успешно.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultProblem"
|
||||
|
||||
/v1/postgres/vacuum:
|
||||
post:
|
||||
tags: [Monitoring]
|
||||
summary: VACUUM (async job, operator)
|
||||
operationId: postPostgresVacuum
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/TenantId"
|
||||
- $ref: "#/components/parameters/IdempotencyKey"
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/PostgresMaintenanceBody"
|
||||
responses:
|
||||
"202":
|
||||
description: Задача поставлена.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/AsyncJobAccepted"
|
||||
"403":
|
||||
$ref: "#/components/responses/Forbidden"
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultProblem"
|
||||
|
||||
/v1/postgres/vacuum-analyze:
|
||||
post:
|
||||
tags: [Monitoring]
|
||||
summary: VACUUM ANALYZE (async job, operator)
|
||||
operationId: postPostgresVacuumAnalyze
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/TenantId"
|
||||
- $ref: "#/components/parameters/IdempotencyKey"
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/PostgresMaintenanceBody"
|
||||
responses:
|
||||
"202":
|
||||
description: Задача поставлена.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/AsyncJobAccepted"
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultProblem"
|
||||
|
||||
/v1/postgres/analyze:
|
||||
post:
|
||||
tags: [Monitoring]
|
||||
summary: ANALYZE (async job, operator)
|
||||
operationId: postPostgresAnalyze
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/TenantId"
|
||||
- $ref: "#/components/parameters/IdempotencyKey"
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/PostgresMaintenanceBody"
|
||||
responses:
|
||||
"202":
|
||||
description: Задача поставлена.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/AsyncJobAccepted"
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultProblem"
|
||||
|
||||
/v1/postgres/reindex:
|
||||
post:
|
||||
tags: [Monitoring]
|
||||
summary: REINDEX TABLE (async job, operator)
|
||||
operationId: postPostgresReindex
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/TenantId"
|
||||
- $ref: "#/components/parameters/IdempotencyKey"
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/PostgresMaintenanceBody"
|
||||
responses:
|
||||
"202":
|
||||
description: Задача поставлена.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/AsyncJobAccepted"
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultProblem"
|
||||
|
||||
/v1/postgres/cleanup:
|
||||
post:
|
||||
tags: [Monitoring]
|
||||
summary: Retention cleanup (async job, operator)
|
||||
operationId: postPostgresCleanup
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/TenantId"
|
||||
- $ref: "#/components/parameters/IdempotencyKey"
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/PostgresMaintenanceBody"
|
||||
responses:
|
||||
"202":
|
||||
description: Задача поставлена.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/AsyncJobAccepted"
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultProblem"
|
||||
|
||||
/v1/postgres/maintenance/logs:
|
||||
get:
|
||||
tags: [Monitoring]
|
||||
summary: Maintenance audit log
|
||||
operationId: listPostgresMaintenanceLogs
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/TenantId"
|
||||
- $ref: "#/components/parameters/Cursor"
|
||||
- $ref: "#/components/parameters/Limit"
|
||||
responses:
|
||||
"200":
|
||||
description: Успешно.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
items:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
next_cursor:
|
||||
type: string
|
||||
has_more:
|
||||
type: boolean
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultProblem"
|
||||
|
||||
/v1/settings:
|
||||
get:
|
||||
tags: [Settings]
|
||||
|
||||
Reference in New Issue
Block a user