New readme
This commit is contained in:
parent
dbe38ec816
commit
7b711c2317
2 changed files with 410 additions and 316 deletions
367
ARCHITECTURE.md
Normal file
367
ARCHITECTURE.md
Normal file
|
|
@ -0,0 +1,367 @@
|
||||||
|
# grafana_gen — архитектура и устройство утилиты
|
||||||
|
|
||||||
|
Утилита автоматически генерирует Grafana-дашборды и правила алертинга для клиентов WAF на основе данных из PostgreSQL и шаблонов из Git-репозитория.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Обзор потока данных
|
||||||
|
|
||||||
|
```
|
||||||
|
PostgreSQL
|
||||||
|
sp_info + manual_info (UNION)
|
||||||
|
apps_settings
|
||||||
|
client_info
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
fetchClientsData()
|
||||||
|
map[clientTitle]ClientData
|
||||||
|
│
|
||||||
|
├──────────────────────────────────────┐
|
||||||
|
▼ ▼
|
||||||
|
generateSingleDashboard() generateAndSendAlerts()
|
||||||
|
│ │
|
||||||
|
▼ ▼
|
||||||
|
dashboard_template.json alert_rules_template.json
|
||||||
|
(Git-репозиторий) (Git-репозиторий)
|
||||||
|
│ │
|
||||||
|
▼ ▼
|
||||||
|
POST /api/dashboards/db POST/PUT /api/v1/provisioning/alert-rules
|
||||||
|
(Grafana API) (Grafana Provisioning API, параллельно x5)
|
||||||
|
│ │
|
||||||
|
▼ ▼
|
||||||
|
state.json ──── clients_hash state.json ──── alerts_hash
|
||||||
|
└─── alert_template_hash
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Структура файлов
|
||||||
|
|
||||||
|
| Файл | Назначение |
|
||||||
|
|---|---|
|
||||||
|
| `main.go` | Точка входа, оркестрация всего потока |
|
||||||
|
| `config.go` | Константы, структуры `Config`, `ClientData`, `DomainInfo`, `DashboardTemplate` |
|
||||||
|
| `database.go` | Подключение к PostgreSQL, `fetchClientsData()` |
|
||||||
|
| `dashboard.go` | Генерация JSON дашборда из шаблона и данных клиентов |
|
||||||
|
| `panels.go` | Построение отдельных панелей, реестр query-режимов, `applyRPSThreshold()` |
|
||||||
|
| `alerts.go` | Генерация и отправка правил алертинга, параллельный upsert |
|
||||||
|
| `grafana.go` | HTTP-клиент для Grafana API (дашборды, папки) |
|
||||||
|
| `template.go` | Загрузка `dashboard_template.json` и `alert_rules_template.json` |
|
||||||
|
| `state.go` | Чтение/запись `state.json`, обнаружение изменений |
|
||||||
|
| `git.go` | `git clone` / `git pull` шаблонов из репозитория |
|
||||||
|
| `env.go` | Загрузка `.env` файла |
|
||||||
|
| `dashboard_template.json` | JSON-шаблон дашборда (Git-репозиторий) |
|
||||||
|
| `alert_rules_template.json` | JSON-шаблон алертов (Git-репозиторий) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## База данных
|
||||||
|
|
||||||
|
### Источник данных
|
||||||
|
|
||||||
|
Данные всегда берутся из **обеих** таблиц одновременно через `UNION`:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT ... FROM (
|
||||||
|
SELECT sid, domain_name, aliases FROM sp_info WHERE sid IS NOT NULL
|
||||||
|
UNION
|
||||||
|
SELECT sid, domain_name, aliases FROM manual_info WHERE sid IS NOT NULL
|
||||||
|
) s
|
||||||
|
LEFT JOIN apps_settings a ON s.sid = a.l7resourceid
|
||||||
|
LEFT JOIN client_info ci ON a.client_title = ci.client_title
|
||||||
|
```
|
||||||
|
|
||||||
|
Дубликаты по SID схлопываются автоматически (`UNION` без `ALL`).
|
||||||
|
|
||||||
|
### Таблицы
|
||||||
|
|
||||||
|
**`sp_info` / `manual_info`** — список ресурсов:
|
||||||
|
- `sid` — идентификатор ресурса
|
||||||
|
- `domain_name` — основной домен
|
||||||
|
- `aliases` — JSON-массив дополнительных доменов
|
||||||
|
|
||||||
|
**`apps_settings`** — маппинг SID → клиент:
|
||||||
|
- `l7resourceid` — SID ресурса
|
||||||
|
- `client_title` — название клиента (имя тенанта)
|
||||||
|
|
||||||
|
**`client_info`** — настройки мониторинга клиента:
|
||||||
|
- `client_title` — название клиента
|
||||||
|
- `rps_limit` — порог RPS для алерта (NULL = алерт не создавать)
|
||||||
|
- `rps_commercial_limit` — коммерческий лимит RPS для синей линии на графике (NULL = 100)
|
||||||
|
- `four_hundred` — порог 4xx ошибок в % (NULL = алерт не создавать)
|
||||||
|
- `five_hundred` — порог 5xx ошибок в % (NULL = алерт не создавать)
|
||||||
|
|
||||||
|
### Пример добавления нового клиента
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 1. Ресурс появится автоматически из sp_info
|
||||||
|
|
||||||
|
-- 2. Привязать к клиенту
|
||||||
|
INSERT INTO apps_settings (l7resourceid, client_title)
|
||||||
|
VALUES ('SID12345', 'Название клиента');
|
||||||
|
|
||||||
|
-- 3. Задать лимиты для алертов (опционально)
|
||||||
|
INSERT INTO client_info (client_title, rps_limit, rps_commercial_limit, four_hundred, five_hundred)
|
||||||
|
VALUES ('Название клиента', 1800, 1200, 20, 10);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Шаблоны
|
||||||
|
|
||||||
|
Шаблоны хранятся в отдельном Git-репозитории и обновляются при каждом запуске через `git pull`. Изменение шаблона автоматически приводит к пересозданию дашборда и/или алертов.
|
||||||
|
|
||||||
|
### dashboard_template.json
|
||||||
|
|
||||||
|
Описывает структуру дашборда: метаданные, Grafana-переменные, строки (rows), панели.
|
||||||
|
|
||||||
|
**Ключевые секции:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"version": "3.1.0",
|
||||||
|
"datasource": { "type": "...", "uid": "..." },
|
||||||
|
"panels": {
|
||||||
|
"rps": { "query_mode": "bucket_logs", ... },
|
||||||
|
"status_codes": { ... },
|
||||||
|
"response_time": { ... },
|
||||||
|
"traffic_combined": { ... }
|
||||||
|
},
|
||||||
|
"layout": {
|
||||||
|
"client_panels": [...],
|
||||||
|
"overview_panels": [...],
|
||||||
|
"overview_row_title": "Обзор"
|
||||||
|
},
|
||||||
|
"templating": { ... }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Query-режимы панелей** (`query_mode`):
|
||||||
|
|
||||||
|
| Режим | Описание |
|
||||||
|
|---|---|
|
||||||
|
| `bucket_logs` | Запрос к OpenSearch по одному SID |
|
||||||
|
| `multi_sid` | Запрос к OpenSearch по всем SID клиента |
|
||||||
|
| `combined_sids` | Объединённый запрос по SID + алиасам |
|
||||||
|
| `static` | Статические данные без запроса |
|
||||||
|
|
||||||
|
**Обзорные панели** (`overview_panels`) используют Grafana-переменные (`$SID`, `$tenant`, `$node_name`) и отображаются в свёрнутой строке «Обзор» поверх клиентских строк.
|
||||||
|
|
||||||
|
### alert_rules_template.json
|
||||||
|
|
||||||
|
Описывает шаблон для алертов.
|
||||||
|
|
||||||
|
**Структура:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"version": "1.3.0",
|
||||||
|
"defaults": {
|
||||||
|
"receiver": "Telegram PTAF Grafana",
|
||||||
|
"folder": "WAF - PTAF",
|
||||||
|
"group": "PTAF Grafana"
|
||||||
|
},
|
||||||
|
"rps_alert": {
|
||||||
|
"relative_time_range_from": 1800,
|
||||||
|
"annotation_summary": "Превышен порог в {rps_limit} RPS в {client_title}"
|
||||||
|
},
|
||||||
|
"static_alerts": [ ... ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Генерация дашборда
|
||||||
|
|
||||||
|
Создаётся **один дашборд** со всеми клиентами. Структура дашборда:
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────┐
|
||||||
|
│ Grafana-переменные: tenant, SID, node │
|
||||||
|
├─────────────────────────────────────────┤
|
||||||
|
│ ▶ Обзор (свёрнутая строка) │
|
||||||
|
│ overview_status_codes │
|
||||||
|
│ overview_tenant_per_nodes │
|
||||||
|
│ overview_tenant_per_node │
|
||||||
|
│ overview_uri_top15 │
|
||||||
|
├─────────────────────────────────────────┤
|
||||||
|
│ ▼ Клиент A (развёрнутая строка) │
|
||||||
|
│ RPS | Status codes | Response time │
|
||||||
|
│ Traffic combined │
|
||||||
|
│ [панели по доменам если > 1 домена] │
|
||||||
|
├─────────────────────────────────────────┤
|
||||||
|
│ ▶ Клиент B (свёрнутая строка) │
|
||||||
|
│ ... │
|
||||||
|
└─────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Threshold на графике RPS
|
||||||
|
|
||||||
|
На панель RPS автоматически накладываются цветные линии из `client_info`:
|
||||||
|
|
||||||
|
| Линия | Значение | Источник |
|
||||||
|
|---|---|---|
|
||||||
|
| Синяя | `rps_commercial_limit` | `client_info.rps_commercial_limit` (NULL → 100) |
|
||||||
|
| Красная | `rps_limit` | `client_info.rps_limit` (0 → линия не рисуется) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Алерты
|
||||||
|
|
||||||
|
### Динамические алерты (per client)
|
||||||
|
|
||||||
|
Создаются для каждого клиента у которого задан соответствующий лимит в `client_info`:
|
||||||
|
|
||||||
|
| Тип | Условие | Структура запроса |
|
||||||
|
|---|---|---|
|
||||||
|
| RPS | `median(count/60) > rps_limit` | OpenSearch count → math /60 → reduce median → threshold |
|
||||||
|
| 4xx | `(errors/total)*100 > four_hundred` | 2x OpenSearch count → reduce → math % → threshold |
|
||||||
|
| 5xx | `(errors/total)*100 > five_hundred` | 2x OpenSearch count → reduce → math % → threshold |
|
||||||
|
|
||||||
|
UID каждого алерта генерируется детерминированно: `md5(client_title + ":" + type)[:8]`. При повторном запуске алерт обновляется (`PUT`), а не создаётся заново.
|
||||||
|
|
||||||
|
### Статические алерты (всегда присутствуют)
|
||||||
|
|
||||||
|
Описаны в `alert_rules_template.json` в секции `static_alerts`, не зависят от БД:
|
||||||
|
|
||||||
|
| Алерт | Условие | for |
|
||||||
|
|---|---|---|
|
||||||
|
| Use in / | диск `/` > 75% | 3m |
|
||||||
|
| Use in /var/log | диск `/var/log` > 75% | 5m |
|
||||||
|
| CPU Busy | CPU > 75% | 3m |
|
||||||
|
| RAM Busy | RAM > 75% | 3m |
|
||||||
|
| Состояние контейнеров | `docker_container_status == 0` | 2m |
|
||||||
|
| Упала Angie | `angie.service` не active | 1m |
|
||||||
|
|
||||||
|
### Параллельная отправка
|
||||||
|
|
||||||
|
Все алерты (динамические + статические) отправляются параллельно через горутины с ограничением **5 одновременных запросов** к Grafana API:
|
||||||
|
|
||||||
|
```
|
||||||
|
[RPS client1] [RPS client2] [4xx client1] [5xx client2] [static: CPU] ← 5 горутин
|
||||||
|
↓ освободился слот
|
||||||
|
[static: RAM] ...
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## State-файл
|
||||||
|
|
||||||
|
Путь по умолчанию: `/var/lib/grafana_gen/state.json`
|
||||||
|
|
||||||
|
Хранит хэши для обнаружения изменений между запусками:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"last_run": "2026-02-25T10:00:00Z",
|
||||||
|
"template_commit": "a1b2c3d4...",
|
||||||
|
"template_version": "3.1.0",
|
||||||
|
"clients_hash": "sha256...",
|
||||||
|
"client_count": 42,
|
||||||
|
"domain_count": 87,
|
||||||
|
"sids": ["SID001", "SID002", "..."],
|
||||||
|
"alerts_hash": "sha256...",
|
||||||
|
"alert_template_hash": "sha256..."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Логика запуска:**
|
||||||
|
|
||||||
|
```
|
||||||
|
изменился clients_hash → пересоздать дашборд
|
||||||
|
изменился template_commit → пересоздать дашборд
|
||||||
|
изменился template_version → пересоздать дашборд
|
||||||
|
изменился alerts_hash → переотправить алерты (без пересоздания дашборда)
|
||||||
|
изменился alert_template_hash → переотправить алерты (без пересоздания дашборда)
|
||||||
|
ничего не изменилось → выход без действий (если не указан -force)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Конфигурация
|
||||||
|
|
||||||
|
Приоритет разрешения параметров (от высшего к низшему):
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Флаг командной строки (-grafana-url=...)
|
||||||
|
2. Переменная окружения (GRAFANA_URL=...)
|
||||||
|
3. .env файл (/etc/grafana_gen/grafana_gen.env)
|
||||||
|
4. Константа в config.go (DefaultGrafanaURL)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Пути к .env файлу (перебираются по порядку)
|
||||||
|
|
||||||
|
1. `$GRAFANA_GEN_ENV_FILE` (переменная окружения)
|
||||||
|
2. `/etc/grafana_gen/grafana_gen.env`
|
||||||
|
3. `./grafana_gen.env`
|
||||||
|
4. `./.env`
|
||||||
|
|
||||||
|
### Пример .env файла
|
||||||
|
|
||||||
|
```env
|
||||||
|
# База данных
|
||||||
|
DB_USER=grafana_reader
|
||||||
|
DB_PASSWORD=secret
|
||||||
|
|
||||||
|
# Grafana
|
||||||
|
GRAFANA_URL=https://grafana.example.com
|
||||||
|
GRAFANA_API_KEY=glsa-xxxxxxxxxxxxxxxxxxxx
|
||||||
|
|
||||||
|
# Git (Gitea)
|
||||||
|
GIT_TOKEN=your-gitea-token
|
||||||
|
|
||||||
|
# Алерты
|
||||||
|
ALERTS_DATASOURCE_UID=af84zsvlp9blsa
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Флаги запуска
|
||||||
|
|
||||||
|
| Флаг | Переменная окружения | По умолчанию | Описание |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `-db-host` | — | `10.100.10.8` | PostgreSQL хост |
|
||||||
|
| `-db-port` | — | `5432` | PostgreSQL порт |
|
||||||
|
| `-db-user` | `DB_USER` | — | PostgreSQL пользователь |
|
||||||
|
| `-db-password` | `DB_PASSWORD` | — | PostgreSQL пароль |
|
||||||
|
| `-db-name` | — | `waf_info` | PostgreSQL база данных |
|
||||||
|
| `-grafana-url` | `GRAFANA_URL` | — | URL Grafana |
|
||||||
|
| `-grafana-api-key` | `GRAFANA_API_KEY` | — | Grafana API ключ |
|
||||||
|
| `-grafana-folder` | `GRAFANA_FOLDER` | `WAF - Auto Generated` | Папка для дашбордов |
|
||||||
|
| `-dashboard-title` | `DASHBOARD_TITLE` | `PT AF Nodes` | Название дашборда |
|
||||||
|
| `-alerts-folder` | `ALERTS_FOLDER` | `WAF - PTAF` | Папка для алертов |
|
||||||
|
| `-alerts-receiver` | `ALERTS_RECEIVER` | `Telegram PTAF Grafana` | Получатель уведомлений |
|
||||||
|
| `-alerts-group` | `ALERTS_GROUP` | `PTAF Grafana` | Группа алертов |
|
||||||
|
| `-alerts-datasource-uid` | `ALERTS_DATASOURCE_UID` | `af84zsvlp9blsa` | UID datasource OpenSearch |
|
||||||
|
| `-git-token` | `GIT_TOKEN` | — | Gitea токен |
|
||||||
|
| `-templates-repo` | — | `svc-git.cirex.ru/...` | URL Git-репозитория шаблонов |
|
||||||
|
| `-templates-branch` | — | `master` | Ветка шаблонов |
|
||||||
|
| `-templates-path` | — | `/etc/grafana_gen/templates` | Локальный путь шаблонов |
|
||||||
|
| `-skip-git-pull` | — | `false` | Не обновлять шаблоны из Git |
|
||||||
|
| `-state-file` | — | `/var/lib/grafana_gen/state.json` | Путь к state-файлу |
|
||||||
|
| `-dry-run` | — | `false` | Не отправлять в Grafana, только логировать |
|
||||||
|
| `-force` | — | `false` | Пересоздать всё даже без изменений |
|
||||||
|
|
||||||
|
### Примеры запуска
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Обычный запуск
|
||||||
|
./grafana_gen
|
||||||
|
|
||||||
|
# Тестовый прогон без отправки в Grafana
|
||||||
|
./grafana_gen -dry-run
|
||||||
|
|
||||||
|
# Принудительное пересоздание всего
|
||||||
|
./grafana_gen -force
|
||||||
|
|
||||||
|
# Без обновления шаблонов из Git
|
||||||
|
./grafana_gen -skip-git-pull
|
||||||
|
|
||||||
|
# Явное указание всех параметров
|
||||||
|
./grafana_gen \
|
||||||
|
-db-host=10.100.10.8 \
|
||||||
|
-db-user=reader \
|
||||||
|
-db-password=secret \
|
||||||
|
-grafana-url=https://grafana.example.com \
|
||||||
|
-grafana-api-key=glsa-xxx
|
||||||
|
```
|
||||||
359
README.md
359
README.md
|
|
@ -1,344 +1,71 @@
|
||||||
# grafana_gen — Руководство пользователя
|
# grafana_gen
|
||||||
|
|
||||||
Утилита автоматически генерирует дашборды Grafana на основе данных из PostgreSQL. При каждом запуске она читает список клиентов и их ресурсов из БД, сравнивает с предыдущим состоянием и пересоздаёт единый дашборд только при наличии изменений.
|
Утилита автоматической генерации Grafana-дашбордов и правил алертинга для клиентов WAF/PTAF.
|
||||||
|
|
||||||
---
|
## Что делает
|
||||||
|
|
||||||
## Как это работает
|
- Читает список клиентов и их SID из PostgreSQL (`sp_info` + `manual_info`)
|
||||||
|
- Генерирует единый дашборд с панелями на каждого клиента
|
||||||
|
- Создаёт правила алертинга: RPS, 4xx/5xx ошибки (пороги из БД), CPU, RAM, диск, контейнеры, Angie
|
||||||
|
- Обновляет шаблоны дашборда и алертов из Git-репозитория при каждом запуске
|
||||||
|
- Пропускает запуск если ничего не изменилось (отслеживает хэши)
|
||||||
|
|
||||||
```
|
## Быстрый старт
|
||||||
PostgreSQL (test_info)
|
|
||||||
↓
|
|
||||||
Список клиентов и ресурсов (SID, domain_name, aliases)
|
|
||||||
↓
|
|
||||||
Проверка изменений (state.json)
|
|
||||||
↓ нет изменений → выход
|
|
||||||
Загрузка шаблона (dashboard_template.json из Git)
|
|
||||||
↓
|
|
||||||
Генерация JSON дашборда
|
|
||||||
↓
|
|
||||||
Grafana API → создание/обновление дашборда
|
|
||||||
```
|
|
||||||
|
|
||||||
На каждый запуск создаётся **один дашборд** со всеми клиентами. Каждый клиент отображается как свёрнутая строка (collapsed row), внутри которой — панели по каждому ресурсу.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Требования
|
|
||||||
|
|
||||||
- Go 1.21+
|
|
||||||
- PostgreSQL с базой `test_info`
|
|
||||||
- Grafana с API-доступом (Service Account Token или Legacy API Key)
|
|
||||||
- Git (для загрузки шаблонов)
|
|
||||||
- Доступ к Gitea-репозиторию с шаблоном
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Установка и запуск
|
|
||||||
|
|
||||||
### Сборка
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone <репозиторий утилиты>
|
|
||||||
cd grafana_gen
|
|
||||||
go build -o grafana_gen .
|
|
||||||
```
|
|
||||||
|
|
||||||
### Первый запуск
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# Минимальный запуск
|
||||||
./grafana_gen \
|
./grafana_gen \
|
||||||
-grafana-url https://grafana.example.com \
|
-db-user=reader \
|
||||||
-grafana-api-key glsa_xxxxxxxxxxxx \
|
-db-password=secret \
|
||||||
-db-user waf_reader \
|
-grafana-url=https://grafana.example.com \
|
||||||
-db-password secret
|
-grafana-api-key=glsa-xxx
|
||||||
```
|
|
||||||
|
|
||||||
### Через .env файл (рекомендуется)
|
# Или через .env файл (приоритет ниже переменных окружения)
|
||||||
|
cp grafana_gen.env.example /etc/grafana_gen/grafana_gen.env
|
||||||
Создайте файл `/etc/grafana_gen/grafana_gen.env`:
|
|
||||||
|
|
||||||
```env
|
|
||||||
GRAFANA_URL=https://grafana.example.com
|
|
||||||
GRAFANA_API_KEY=glsa_xxxxxxxxxxxx
|
|
||||||
DB_USER=waf_reader
|
|
||||||
DB_PASSWORD=secret
|
|
||||||
GIT_TOKEN=your-gitea-token
|
|
||||||
```
|
|
||||||
|
|
||||||
Затем просто:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./grafana_gen
|
./grafana_gen
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Конфигурация
|
## Конфигурация
|
||||||
|
|
||||||
### Способы задать параметры (в порядке приоритета)
|
Параметры разрешаются в порядке приоритета:
|
||||||
|
**флаг → переменная окружения → .env файл → константа в config.go**
|
||||||
|
|
||||||
| Приоритет | Способ | Пример |
|
Минимально необходимые параметры:
|
||||||
|-----------|--------|--------|
|
|
||||||
| 1 | Флаг командной строки | `-grafana-url https://...` |
|
|
||||||
| 2 | Переменная окружения | `export GRAFANA_URL=https://...` |
|
|
||||||
| 3 | `.env` файл | `GRAFANA_URL=https://...` |
|
|
||||||
| 4 | Константа в `config.go` | `DefaultGrafanaURL = "https://..."` |
|
|
||||||
|
|
||||||
### Пути поиска .env файла
|
| Параметр | Флаг | Переменная окружения |
|
||||||
|
|---|---|---|
|
||||||
|
| PostgreSQL пользователь | `-db-user` | `DB_USER` |
|
||||||
|
| PostgreSQL пароль | `-db-password` | `DB_PASSWORD` |
|
||||||
|
| URL Grafana | `-grafana-url` | `GRAFANA_URL` |
|
||||||
|
| Grafana API ключ | `-grafana-api-key` | `GRAFANA_API_KEY` |
|
||||||
|
|
||||||
Утилита ищет `.env` файл в следующем порядке:
|
Пример `.env` файла:
|
||||||
|
|
||||||
1. Путь из переменной `GRAFANA_GEN_ENV_FILE`
|
```env
|
||||||
2. `/etc/grafana_gen/grafana_gen.env`
|
DB_USER=grafana_reader
|
||||||
3. `./grafana_gen.env` (рядом с бинарником)
|
DB_PASSWORD=secret
|
||||||
4. `./.env`
|
GRAFANA_URL=https://grafana.example.com
|
||||||
|
GRAFANA_API_KEY=glsa-xxxxxxxxxxxxxxxxxxxx
|
||||||
---
|
GIT_TOKEN=your-gitea-token
|
||||||
|
|
||||||
## Флаги командной строки
|
|
||||||
|
|
||||||
### База данных
|
|
||||||
|
|
||||||
| Флаг | Переменная окружения | По умолчанию | Описание |
|
|
||||||
|------|---------------------|--------------|----------|
|
|
||||||
| `-db-host` | — | `10.100.10.8` | Хост PostgreSQL |
|
|
||||||
| `-db-port` | — | `5432` | Порт PostgreSQL |
|
|
||||||
| `-db-user` | `DB_USER` | — | Пользователь БД (**обязательно**) |
|
|
||||||
| `-db-password` | `DB_PASSWORD` | — | Пароль БД (**обязательно**) |
|
|
||||||
| `-db-name` | — | `test_info` | Имя базы данных |
|
|
||||||
| `-use-manual` | — | `false` | Использовать таблицу `manual_info` вместо `sp_info` |
|
|
||||||
|
|
||||||
### Grafana
|
|
||||||
|
|
||||||
| Флаг | Переменная окружения | По умолчанию | Описание |
|
|
||||||
|------|---------------------|--------------|----------|
|
|
||||||
| `-grafana-url` | `GRAFANA_URL` | — | URL Grafana (**обязательно**) |
|
|
||||||
| `-grafana-api-key` | `GRAFANA_API_KEY` | — | API-ключ Grafana (**обязательно**) |
|
|
||||||
| `-grafana-folder` | `GRAFANA_FOLDER` | `WAF - Auto Generated` | Папка в Grafana для дашборда |
|
|
||||||
| `-dashboard-title` | `DASHBOARD_TITLE` | `PT AF Nodes` | Название дашборда |
|
|
||||||
|
|
||||||
### Git / шаблоны
|
|
||||||
|
|
||||||
| Флаг | Переменная окружения | По умолчанию | Описание |
|
|
||||||
|------|---------------------|--------------|----------|
|
|
||||||
| `-git-token` | `GIT_TOKEN` | — | Токен доступа к Gitea |
|
|
||||||
| `-templates-repo` | — | *(см. config.go)* | URL Git-репозитория с шаблонами |
|
|
||||||
| `-templates-branch` | — | `master` | Ветка репозитория |
|
|
||||||
| `-templates-path` | — | `/etc/grafana_gen/templates` | Локальный путь для шаблонов |
|
|
||||||
| `-skip-git-pull` | — | `false` | Не обновлять шаблоны из Git |
|
|
||||||
|
|
||||||
### Управление запуском
|
|
||||||
|
|
||||||
| Флаг | По умолчанию | Описание |
|
|
||||||
|------|--------------|----------|
|
|
||||||
| `-dry-run` | `false` | Сгенерировать JSON, но не отправлять в Grafana |
|
|
||||||
| `-force` | `false` | Принудительная регенерация даже без изменений |
|
|
||||||
| `-state-file` | `/var/lib/grafana_gen/state.json` | Путь к файлу состояния |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Приоритет параметров
|
|
||||||
|
|
||||||
Пример: если одновременно задан флаг `-grafana-api-key`, переменная `GRAFANA_API_KEY` и значение в `.env` — используется **флаг командной строки** как наиболее приоритетный.
|
|
||||||
|
|
||||||
```
|
|
||||||
Флаг CLI > Переменная окружения > .env файл > константа в config.go
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Это позволяет безопасно хранить секреты в `.env` и при необходимости переопределять их на лету без изменения файлов.
|
## Полезные флаги
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## State-файл
|
|
||||||
|
|
||||||
Утилита сохраняет состояние после каждого успешного запуска в JSON-файл (по умолчанию `/var/lib/grafana_gen/state.json`).
|
|
||||||
|
|
||||||
При следующем запуске сравниваются:
|
|
||||||
|
|
||||||
- Коммит шаблона в Git
|
|
||||||
- Версия шаблона (`version` в `dashboard_template.json`)
|
|
||||||
- SHA-256 хэш данных из БД (список клиентов, доменов, SID)
|
|
||||||
- Количество клиентов и доменов
|
|
||||||
|
|
||||||
Если ничего не изменилось — дашборд не пересоздаётся, утилита завершается с кодом 0.
|
|
||||||
|
|
||||||
```
|
|
||||||
=== No Changes Detected ===
|
|
||||||
No changes in templates or database since last run.
|
|
||||||
Skipping dashboard generation.
|
|
||||||
|
|
||||||
Use -force flag to regenerate anyway.
|
|
||||||
```
|
|
||||||
|
|
||||||
Если изменения есть — выводится подробный отчёт:
|
|
||||||
|
|
||||||
```
|
|
||||||
=== Changes Detected ===
|
|
||||||
Changes detected:
|
|
||||||
Template commit changed: abc12345 -> def67890
|
|
||||||
Database content changed
|
|
||||||
- New SIDs: [SID_001, SID_002]
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Режим dry-run
|
|
||||||
|
|
||||||
Позволяет проверить что будет сгенерировано без отправки в Grafana:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./grafana_gen -dry-run
|
-dry-run # Сгенерировать и показать в логах, не отправлять в Grafana
|
||||||
|
-force # Пересоздать всё даже если изменений нет
|
||||||
|
-skip-git-pull # Не обновлять шаблоны из Git
|
||||||
```
|
```
|
||||||
|
|
||||||
В лог выводится превью JSON дашборда и итоговая статистика:
|
## Шаблоны
|
||||||
|
|
||||||
```
|
Дашборд и алерты строятся по JSON-шаблонам из Git-репозитория:
|
||||||
DRY RUN: Dashboard generated but not sent to Grafana
|
|
||||||
=== Summary ===
|
|
||||||
Clients: 12
|
|
||||||
Skipped: 0
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
- `dashboard_template.json` — структура и панели дашборда
|
||||||
|
- `alert_rules_template.json` — правила алертинга
|
||||||
|
|
||||||
## Запуск через cron
|
Изменение любого шаблона автоматически триггерит пересоздание при следующем запуске.
|
||||||
|
|
||||||
Рекомендуемый вариант — запуск каждые 15 минут:
|
## Подробнее
|
||||||
|
|
||||||
```cron
|
См. [ARCHITECTURE.md](ARCHITECTURE.md).
|
||||||
*/15 * * * * /usr/local/bin/grafana_gen >> /var/log/grafana_gen.log 2>&1
|
|
||||||
```
|
|
||||||
|
|
||||||
Утилита сама определяет нужно ли обновлять дашборд — частые запуски без изменений завершаются мгновенно.
|
|
||||||
|
|
||||||
### Systemd timer (альтернатива)
|
|
||||||
|
|
||||||
`/etc/systemd/system/grafana-gen.service`:
|
|
||||||
```ini
|
|
||||||
[Unit]
|
|
||||||
Description=Grafana Dashboard Generator
|
|
||||||
After=network.target postgresql.service
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=oneshot
|
|
||||||
EnvironmentFile=/etc/grafana_gen/grafana_gen.env
|
|
||||||
ExecStart=/usr/local/bin/grafana_gen
|
|
||||||
StandardOutput=journal
|
|
||||||
StandardError=journal
|
|
||||||
```
|
|
||||||
|
|
||||||
`/etc/systemd/system/grafana-gen.timer`:
|
|
||||||
```ini
|
|
||||||
[Unit]
|
|
||||||
Description=Run grafana-gen every 15 minutes
|
|
||||||
|
|
||||||
[Timer]
|
|
||||||
OnBootSec=2min
|
|
||||||
OnUnitActiveSec=15min
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=timers.target
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
systemctl enable --now grafana-gen.timer
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Типичные сценарии
|
|
||||||
|
|
||||||
### Первое развёртывание
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Создать .env
|
|
||||||
cp grafana_gen.env.example /etc/grafana_gen/grafana_gen.env
|
|
||||||
vim /etc/grafana_gen/grafana_gen.env
|
|
||||||
|
|
||||||
# 2. Проверить без отправки
|
|
||||||
./grafana_gen -dry-run
|
|
||||||
|
|
||||||
# 3. Создать дашборд
|
|
||||||
./grafana_gen
|
|
||||||
```
|
|
||||||
|
|
||||||
### Принудительное обновление после изменения шаблона
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./grafana_gen -force
|
|
||||||
```
|
|
||||||
|
|
||||||
### Переключение на резервную БД
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./grafana_gen -db-host 10.10.10.5
|
|
||||||
```
|
|
||||||
|
|
||||||
### Тестирование с другим шаблоном
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./grafana_gen \
|
|
||||||
-templates-path /tmp/my-templates \
|
|
||||||
-skip-git-pull \
|
|
||||||
-dry-run
|
|
||||||
```
|
|
||||||
|
|
||||||
### Использование таблицы ручного ввода
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./grafana_gen -use-manual
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Структура БД
|
|
||||||
|
|
||||||
Утилита читает данные из двух таблиц базы `test_info`.
|
|
||||||
|
|
||||||
### Таблица `sp_info` (основная)
|
|
||||||
|
|
||||||
| Колонка | Тип | Описание |
|
|
||||||
|---------|-----|----------|
|
|
||||||
| `sid` | text | Идентификатор ресурса |
|
|
||||||
| `domain_name` | text | Доменное имя |
|
|
||||||
| `aliases` | jsonb | JSON-массив дополнительных доменов |
|
|
||||||
|
|
||||||
### Таблица `apps_settings` (справочник клиентов)
|
|
||||||
|
|
||||||
| Колонка | Тип | Описание |
|
|
||||||
|---------|-----|----------|
|
|
||||||
| `l7resourceid` | text | SID ресурса (связь с `sp_info.sid`) |
|
|
||||||
| `client_title` | text | Название клиента |
|
|
||||||
|
|
||||||
Если `client_title` не найден — клиент группируется под именем `Unknown`.
|
|
||||||
|
|
||||||
Таблица `manual_info` имеет ту же структуру, что и `sp_info`, и используется при флаге `-use-manual` для ручного управления данными без изменения основной таблицы.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Файловая система
|
|
||||||
|
|
||||||
```
|
|
||||||
/etc/grafana_gen/
|
|
||||||
├── grafana_gen.env # Конфигурация (секреты)
|
|
||||||
└── templates/ # Клонированный Git-репозиторий с шаблонами
|
|
||||||
└── dashboard_template.json
|
|
||||||
|
|
||||||
/var/lib/grafana_gen/
|
|
||||||
└── state.json # Состояние последнего запуска
|
|
||||||
|
|
||||||
/usr/local/bin/
|
|
||||||
└── grafana_gen # Бинарник утилиты
|
|
||||||
```
|
|
||||||
|
|
||||||
### Права доступа
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Директории
|
|
||||||
install -d -m 755 /etc/grafana_gen
|
|
||||||
install -d -m 755 /var/lib/grafana_gen
|
|
||||||
|
|
||||||
# .env файл — только для владельца процесса
|
|
||||||
chmod 600 /etc/grafana_gen/grafana_gen.env
|
|
||||||
```
|
|
||||||
Loading…
Add table
Reference in a new issue