grafana_gen/ARCHITECTURE.md

580 lines
29 KiB
Markdown
Executable file
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# grafana_gen — архитектура и устройство утилиты
Утилита автоматически генерирует Grafana-дашборды и правила алертинга для клиентов WAF на основе данных из PostgreSQL и шаблонов из Git-репозитория.
---
## Обзор потока данных
```
PostgreSQL
sp_info + manual_info (UNION)
apps_settings
client_info (waf_provider IS NOT NULL)
fetchClientsData()
map[clientTitle]ClientData{WafProvider}
├──────────────────────────────────────────────────────────────────┐
│ │
spikClients (waf_provider=spik) spClients (waf_provider=sp)
│ │
├──────────────────────┐ ┌──────────────────────────┤
│ │ │ │
▼ ▼ ▼ ▼
generateVLDashboard() generateAndSendAlertsVL() generateVLDashboard() generateAndSendAlertsVL()
(SPIK дашборд) (группа: PTAF Grafana) (SP дашборд) (группа: SP PTAF Grafana)
(receiver: tg+mail+...) (receiver: For_SP)
│ │ │ │
▼ └────────────────┘ │
dashboard_template.json activeUIDs (spik+SP+static) │
│ │ │
▼ ▼ │
POST /api/dashboards/db deleteObsoleteAlerts() POST /api/dashboards/db
state.json ── alerts_hash
└── alert_template_hash
```
Генерация дашбордов и алертов управляется независимо через переменные окружения `DASHBOARD_OS_ENABLED`, `DASHBOARD_VL_ENABLED`, `ALERTS_OS_ENABLED`, `ALERTS_VL_ENABLED`.
---
## Структура файлов
| Файл | Назначение |
|---|---|
| `main.go` | Точка входа, оркестрация всего потока, разделение клиентов по `waf_provider` |
| `config.go` | Константы, структуры `Config`, `ClientData`, `DomainInfo`, `DashboardTemplate` |
| `database.go` | Подключение к PostgreSQL, `fetchClientsData()`, чтение `waf_provider` |
| `dashboard.go` | Генерация JSON дашборда (OpenSearch) из шаблона и данных клиентов |
| `dashboard_vl.go` | Генерация JSON дашборда для VictoriaLogs |
| `panels.go` | Построение панелей (OpenSearch), реестр query-режимов, `applyRPSThreshold()` |
| `panels_vl.go` | Построение панелей для VictoriaLogs, LogsQL query builders |
| `alerts.go` | Генерация и отправка правил алертинга (OpenSearch), `deleteObsoleteAlerts()` |
| `alerts_vl.go` | Генерация и отправка правил алертинга для VictoriaLogs, возвращает список активных UID |
| `template_validator.go` | Валидация и автоисправление критичных настроек шаблона |
| `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`. Читаются только клиенты у которых `waf_provider IS NOT NULL`:
```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
WHERE ci.waf_provider IS NOT NULL
```
Дубликаты по SID схлопываются автоматически (`UNION` без `ALL`).
### Таблицы
**`sp_info` / `manual_info`** — список ресурсов:
- `sid` — идентификатор ресурса
- `domain_name` — основной домен
- `aliases` — JSON-массив дополнительных доменов
**`apps_settings`** — маппинг SID → клиент, пороги ошибок per-SID:
- `l7resourceid` — SID ресурса
- `client_title` — название клиента (имя тенанта)
- `four_hundred` — порог 4xx ошибок в % (default 20)
- `five_hundred` — порог 5xx ошибок в % (default 10)
- `ptaf_fallback_code_alert_count` — порог WAF block алерта в штуках (default 1)
**`client_info`** — настройки мониторинга клиента:
- `client_title` — название клиента
- `rps_limit` — порог RPS для алерта (NULL = алерт не создавать)
- `rps_commercial_limit` — коммерческий лимит RPS для синей линии на графике (NULL = 100)
- `waf_provider` — тип провайдера WAF, определяет в какой дашборд и группу алертов попадает клиент:
- `spik` — основной VL дашборд + алерты в группе `PTAF Grafana {client_title}`
- `sp` — отдельный SP дашборд + алерты в группе `SP PTAF Grafana {client_title}` с contact point `For_SP`
- `NULL` — клиент игнорируется полностью
- `ptaf_fallback_code` — HTTP код который PTAF возвращает при блокировке (напр. `418`, `403`). `pass` или NULL = WAF block алерт не создавать
### Разделение клиентов по waf_provider
После загрузки данных `main.go` разделяет клиентов на две группы:
```go
spikClients := map[string]ClientData{} // waf_provider = "spik"
spClients := map[string]ClientData{} // waf_provider = "sp"
```
Хэш для обнаружения изменений алертов считается только от `spikClients`.
### Пример добавления нового клиента
```sql
-- 1. Ресурс появится автоматически из sp_info (или добавить в manual_info)
-- 2. Привязать к клиенту
INSERT INTO apps_settings (l7resourceid, client_title)
VALUES ('SID12345', 'Название клиента');
-- 3. Задать провайдера и лимиты
INSERT INTO client_info (client_title, waf_provider, rps_limit, rps_commercial_limit, four_hundred, five_hundred)
VALUES ('Название клиента', 'spik', 1800, 1200, 20, 10);
-- или для SP клиента: waf_provider = 'sp'
```
---
## Шаблоны
Шаблоны хранятся в отдельном Git-репозитории и обновляются при каждом запуске через `git pull`. Изменение шаблона автоматически приводит к пересозданию дашборда и/или алертов.
### dashboard_template.json
Описывает структуру дашборда: метаданные, Grafana-переменные, строки (rows), панели.
**Ключевые секции:**
```json
{
"version": "3.1.0",
"datasource": { "type": "...", "uid": "..." },
"panels": {
"rps": { "query_mode": "rps", "vl_interval": "1m", ... },
"rps_multi": { "query_mode": "rps_multi", "vl_interval": "1m", ... },
"status_codes": { "query_mode": "multi_target", "vl_interval": "1m", ... },
"response_time": { "query_mode": "range_percent", "vl_interval": "1m", ... },
"traffic_combined": { "query_mode": "multi_sum_expression", "vl_interval": "1m", ... },
"overview_status_codes": { "query_mode": "bucket_logs", ... },
"overview_tenant_per_nodes": { "query_mode": "bucket_logs", ... },
"overview_tenant_per_node": { "query_mode": "bucket_logs", ... },
"overview_uri_top15": { "query_mode": "bucket_logs", ... },
"overview_errors_by_container": { "query_mode": "bucket_logs", ... },
"overview_nginx_vs_angie": { "query_mode": "multi_target", ... },
"error_by_host": { "query_mode": "bucket_logs", ... },
"error_by_path": { "query_mode": "bucket_logs", ... },
"error_by_node": { "query_mode": "bucket_logs", ... }
},
"layout": {
"tenant_panels": [...],
"domain_panels": [...],
"overview_panels": [...],
"overview_row_title": "PTAF-Nginx",
"error_panels": [...],
"error_row_title": "Angie"
},
"templating": { "list": [...] }
}
```
**Query-режимы панелей** (`query_mode`):
| Режим | Описание |
|---|---|
| `rps` | RPS для одного домена (OS: count/60, VL: count/$__interval_ms*1000) |
| `rps_multi` | RPS с разбивкой по доменам клиента |
| `rps_var` | RPS с Grafana-переменной SID |
| `multi_target` | Несколько targets на одной панели (status codes, nginx vs angie) |
| `range_percent` | Процентное распределение по диапазонам (response time) |
| `sum_expression` | Сумма поля + math expression (traffic) |
| `multi_sum_expression` | Несколько sum + math expressions |
| `bucket_logs` | Группировка по полю с terms aggregation (обзорные панели) |
| `static_targets` | Статические targets без подстановки SID |
**VL-специфичные поля панелей:**
| Поле | Описание |
|---|---|
| `vl_interval` | Минимальный интервал агрегации для VL (`"1m"`, `"2m"`) |
| `vl_base_query` | LogsQL запрос вместо Lucene `base_query` для VL |
| `unknown_label` | Метка для записей с пустым полем группировки (напр. `"(unknown)"`) |
**Layout панелей:**
Каждый элемент `tenant_panels` и `domain_panels` описывает позицию панели:
```json
{
"panel_key": "status_codes",
"title_format": "Status Codes {client}",
"width": 8,
"x_offset": 0,
"condition": { "type": "min_domains", "value": 2 }
}
```
Текущая расстановка — три столбца по 8: **Status Codes | RPS | Traffic**.
**Обзорные панели** (`overview_panels`) отображаются в свёрнутой строке «PTAF-Nginx» и используют Grafana-переменные (`${SID}`, `${tenant}`, `${node_name}`, `${response_status_code}`, `${app_name}`, `${error_server}`).
**Error панели** (`error_panels`) отображаются в свёрнутой строке «Angie» и показывают данные из `log_type:angie-error-PTAF`.
### alert_rules_template.json
Описывает шаблон для алертов.
**Структура:**
```json
{
"version": "1.3.0",
"defaults": {
"receiver": "tg+mail+mattermost PTAF Grafana",
"folder": "WAF - PTAF",
"group": "PTAF Grafana"
},
"rps_alert": {
"relative_time_range_from": 1800,
"annotation_summary": "Превышен порог в {rps_limit} RPS в {client_title}"
},
"contact_point": {
"receiver_name": "tg+mail+mattermost PTAF Grafana",
"message_template": "..."
},
"static_alerts": [ ... ]
}
```
---
## Генерация дашборда
### OpenSearch дашборд
Создаётся через `generateSingleDashboard()` для `spikClients`.
### VictoriaLogs дашборды
Генерируются через `generateVLDashboard()` при наличии `VL_DATASOURCE_UID`:
| Дашборд | Клиенты | UID | Папка |
|---|---|---|---|
| `PT AF Requests (VictoriaLogs)` | `spikClients` | `pt-af-requests-auto-vl` | `WAF - PTAF` |
| `SP PT AF Requests (VictoriaLogs)` | `spClients` | `pt-af-requests-auto-sp` | `WAF - PTAF` |
SP дашборд генерируется только если `SP_DASHBOARD_TITLE` задан и есть клиенты с `waf_provider=sp`.
**Особенности VL дашборда:**
- Все запросы используют `log_type:nginx-access-PTAF` (не `log_type:access`)
- `queryType: "statsRange"` для агрегирующих запросов
- `interval: "1m"` из поля `vl_interval` шаблона панели
- `timeShift: "1m"` для обрезки неполной последней минуты
- Math expressions для RPS: `$A / $__interval_ms * 1000`
**Структура дашборда:**
```
┌─────────────────────────────────────────────────┐
│ Grafana-переменные: tenant, SID, node_name, │
│ Status Code, App Name, Error App │
├─────────────────────────────────────────────────┤
│ ▶ PTAF-Nginx (свёрнутая строка) │
│ Response_status_code SID │
│ Request Count by TENANT per nodes/node │
│ URI top 15 │
│ Response status code by Container │
│ Nginx vs Angie Status Codes │
├─────────────────────────────────────────────────┤
│ ▶ Angie (свёрнутая строка) │
│ Errors by Apps │
│ Errors by Upstream Path │
│ Errors by Node │
├─────────────────────────────────────────────────┤
│ ▼ Клиент A │
│ Status Codes | RPS | Total Traffic │
│ [domain1] Status Codes | Response Time | Traffic │
├─────────────────────────────────────────────────┤
│ ▶ Клиент B ... │
└─────────────────────────────────────────────────┘
```
---
## Алерты
### Динамические алерты (per client)
Создаются для каждого клиента у которого задан соответствующий лимит в `client_info`.
**OpenSearch алерты** (`alerts.go`):
| Тип | Условие | Структура запроса |
|---|---|---|
| RPS | `median(count/60) > rps_limit` | OS count → math /60 → reduce median → threshold |
| 4xx response | `(errors/total)*100 > limit_4xx` | 2x OS count по `response_status_code` → reduce → math % → threshold |
| 4xx upstream | `(errors/total)*100 > limit_4xx` | 2x OS count по `upstream_status_code` → reduce → math % → threshold |
| 5xx response | `(errors/total)*100 > limit_5xx` | 2x OS count по `response_status_code` → reduce → math % → threshold |
| 5xx upstream | `(errors/total)*100 > limit_5xx` | 2x OS count по `upstream_status_code` → reduce → math % → threshold |
| WAF block | `count > ptaf_fallback_code_alert_count` | OS count по коду из `ptaf_fallback_code` → reduce last → threshold |
Алерты 4xx/5xx и WAF block создаются **по одному на каждый SID**.
**VictoriaLogs алерты** (`alerts_vl.go`):
| Тип | Условие | Структура запроса |
|---|---|---|
| RPS | `median(count/60) > rps_limit` | VL statsRange (1m) → math /60 → reduce median → threshold |
| 4xx response | `(errors/total)*100 > limit_4xx` | 2x VL statsRange по `response_status_code` → reduce sum → math % → threshold |
| 4xx upstream | `(errors/total)*100 > limit_4xx` | 2x VL statsRange по `upstream_status_code` → reduce sum → math % → threshold |
| 5xx response | `(errors/total)*100 > limit_5xx` | 2x VL statsRange по `response_status_code` → reduce sum → math % → threshold |
| 5xx upstream | `(errors/total)*100 > limit_5xx` | 2x VL statsRange по `upstream_status_code` → reduce sum → math % → threshold |
| WAF block | `count > ptaf_fallback_code_alert_count` | VL statsRange по коду из `ptaf_fallback_code` → reduce last → threshold |
VL алерты имеют `noDataState: "NoData"` — при отсутствии данных алерт не срабатывает.
Алерты 4xx/5xx и WAF block создаются **по одному на каждый SID** (домен) клиента. RPS алерт — один на всего клиента (все SID суммируются).
UID каждого алерта генерируется детерминированно от `client_title + SID + type`. При повторном запуске алерт обновляется (`PUT`), а не создаётся заново.
**Разделение по waf_provider:**
| Клиенты | Группа алертов | Contact point | Папка |
|---|---|---|---|
| `spikClients` | `PTAF Grafana {client_title}` | `tg+mail+mattermost PTAF Grafana` | `WAF - PTAF` |
| `spClients` | `SP PTAF Grafana {client_title}` | `For_SP` | `WAF - PTAF` |
Группировка по тенанту позволяет видеть алерты в Grafana в разделе `WAF - PTAF → PTAF Grafana nloto`.
### Статические алерты (всегда присутствуют)
Описаны в `alert_rules_template.json`, не зависят от БД. Отправляются в группе `[SYS] PTAF Grafana` первыми (до динамических):
| Алерт | Условие | for |
|---|---|---|
| `[SYS] Use in / 75%` | диск `/` > 75% | 3m |
| `[SYS] Use in / 90%` | диск `/` > 90% | 1m |
| `[SYS] Use in /var/log 75%` | диск `/var/log` > 75% | 5m |
| `[SYS] Use in /var/log 90%` | диск `/var/log` > 90% | 1m |
| `[SYS] CPU Busy 75%` | CPU > 75% | 3m |
| `[SYS] CPU Busy 90%` | CPU > 90% | 1m |
| `[SYS] RAM Busy 75%` | RAM > 75% | 3m |
| `[SYS] RAM Busy 90%` | RAM > 90% | 1m |
| `[SYS] Состояние контейнеров` | контейнер упал | 2m |
| `[SYS] Упала Angie` | `angie.service` не active | 1m |
Если `ALERTS_OS_ENABLED=false` — статические алерты отправляются через VL путь.
### Удаление устаревших алертов
После каждой генерации `deleteObsoleteAlerts()` получает все алерты из папки `WAF - PTAF` и удаляет те, чьи UID не входят в актуальный набор (spik + SP + статические). Это автоматически удаляет алерты клиентов которые были удалены из БД или у которых изменился `waf_provider`.
### Параллельная отправка
Все алерты отправляются параллельно через горутины с ограничением **20 одновременных запросов** к Grafana API.
### Обновление шаблона contact point
После каждой отправки алертов `upsertContactPoint()` автоматически обновляет `message` во всех Telegram интеграциях contact point. Если `ALERTS_OS_ENABLED=false` — обновление происходит через VL путь. Шаблон берётся из `alert_rules_template.json``contact_point.message_template`.
**Формат уведомлений:**
Firing:
```
PTAF alerts:
🔴 nloto / nationallottery.ru (SID:10307) — 4xx response ошибок 33.45% за 3m.
Порог сработки >20% для response_status_code (ответ от PTAF, не от origin)
Время: 2026-04-27 10:00:00
```
Resolved:
```
PTAF alerts:
✅ nloto / nationallottery.ru (SID:10307) — 4xx response ошибок трафика.
Текущее значение 12.30% для response_status_code (ответ от PTAF, не от origin)
Время: 2026-04-27 10:15:00
```
WAF block (🟡 — severity=warning):
```
PTAF alerts:
🟡 gorodpay / stage-dev.com (SID:12092) — 418 WAF ошибок 3 шт. за 1m.
Порог сработки >1 штуки для response_status_code (ответ от PTAF, не от origin)
Время: 2026-04-27 14:50:00
---
Проверить логи docker, процитировать ошибку и эскалировать на аналитика.
```
### Подавление DatasourceNoData алертов
VL алерты при отсутствии данных переходят в состояние `NoData`. Для подавления уведомлений в Grafana создан Silence с матчером `alertname = DatasourceNoData`.
---
## Валидатор шаблона
`template_validator.go` запускается автоматически после загрузки шаблона и проверяет/исправляет:
- `vl_interval: "1m"` для панелей: rps, rps_multi, status_codes, response_time, traffic_combined, traffic_combined_total
- `spanNulls: 180000` для панели status_codes
- `vl_base_query` с `TENANT:in(${tenant:csv})` для `overview_tenant_per_nodes`
- `vl_base_query` с `node_name:in(${node_name:csv})` для `overview_tenant_per_node`
- Layout tenant_panels в три столбца по 8 (status_codes + rps/rps_multi + traffic_combined_total)
- Layout domain_panels в три столбца по 8 (status_codes + response_time + traffic_combined)
---
## 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)
```
`alerts_hash` считается только от `spikClients` и сохраняется после успешной отправки.
---
## Конфигурация
Приоритет разрешения параметров (от высшего к низшему):
```
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
GIT_TOKEN=your-gitea-token
# Алерты OpenSearch
ALERTS_DATASOURCE_UID=af84zsvlp9blsa
# VictoriaLogs
VL_DATASOURCE_UID=efewdonokxybkf
VL_DASHBOARD_TITLE=PT AF Requests (VictoriaLogs)
VL_GRAFANA_FOLDER=WAF - PTAF
# SP дашборд и алерты
SP_DASHBOARD_TITLE=SP PT AF Requests (VictoriaLogs)
SP_DASHBOARD_UID=pt-af-requests-auto-sp
SP_ALERTS_GROUP=SP PTAF Grafana
SP_ALERTS_RECEIVER=For_SP
# Управление генерацией
DASHBOARD_OS_ENABLED=false
DASHBOARD_VL_ENABLED=true
ALERTS_OS_ENABLED=false
ALERTS_VL_ENABLED=true
```
---
## Флаги запуска
| Флаг | Переменная окружения | По умолчанию | Описание |
|---|---|---|---|
| `-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` | Папка для OS дашборда |
| `-dashboard-title` | `DASHBOARD_TITLE` | `PT AF Requests` | Название OS дашборда |
| `-alerts-folder` | `ALERTS_FOLDER` | `WAF - PTAF` | Папка для алертов |
| `-alerts-receiver` | `ALERTS_RECEIVER` | `tg+mail+mattermost PTAF Grafana` | Contact point для SPIK алертов |
| `-alerts-group` | `ALERTS_GROUP` | `PTAF Grafana` | Группа алертов для SPIK |
| `-alerts-datasource-uid` | `ALERTS_DATASOURCE_UID` | `af84zsvlp9blsa` | UID datasource OpenSearch для алертов |
| `-vl-datasource-uid` | `VL_DATASOURCE_UID` | — | UID VictoriaLogs datasource |
| `-vl-dashboard-title` | `VL_DASHBOARD_TITLE` | `PT AF Requests (VictoriaLogs)` | Название SPIK VL дашборда |
| `-vl-grafana-folder` | `VL_GRAFANA_FOLDER` | — | Папка для SPIK VL дашборда |
| `-vl-dashboard-uid` | `VL_DASHBOARD_UID` | `pt-af-requests-auto-vl` | UID SPIK VL дашборда |
| `-sp-dashboard-title` | `SP_DASHBOARD_TITLE` | `SP PT AF Requests (VictoriaLogs)` | Название SP дашборда |
| `-sp-dashboard-uid` | `SP_DASHBOARD_UID` | `pt-af-requests-auto-sp` | UID SP дашборда |
| `-sp-grafana-folder` | `SP_GRAFANA_FOLDER` | — | Папка для SP дашборда |
| — | `SP_ALERTS_GROUP` | `SP PTAF Grafana` | Группа алертов для SP клиентов |
| — | `SP_ALERTS_RECEIVER` | `For_SP` | Contact point для SP алертов |
| `-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` | Пересоздать всё даже без изменений |
| — | `DASHBOARD_OS_ENABLED` | `true` | Генерировать OS дашборд |
| — | `DASHBOARD_VL_ENABLED` | `true` | Генерировать VL дашборд |
| — | `ALERTS_OS_ENABLED` | `true` | Генерировать OS алерты |
| — | `ALERTS_VL_ENABLED` | `true` | Генерировать VL алерты |
### Примеры запуска
```bash
# Обычный запуск
./grafana_gen
# Тестовый прогон без отправки в Grafana
./grafana_gen -dry-run
# Принудительное пересоздание всего
./grafana_gen -force
# Без обновления шаблонов из Git
./grafana_gen -skip-git-pull
# Только VL дашборды и VL алерты
DASHBOARD_OS_ENABLED=false ALERTS_OS_ENABLED=false ./grafana_gen
# Явное указание параметров
./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 \
-vl-datasource-uid=efewdonokxybkf
```