OpenSpec: разнести openspec по проектам

This commit is contained in:
kpa39l
2026-09-11 17:31:01 +00:00
parent 9f2619039a
commit 3c5e9e5a71
25 changed files with 1893 additions and 0 deletions
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-09-08
@@ -0,0 +1,62 @@
# Design: Fix Vinograd WAN dashboard annotations
## Файл
| Файл | Действие |
|---|---|
| `/opt/monitoring/grafana/dashboards/vinograd-wan.json` | убрать `annotations.list` (ссылка на `__grafana__`) → `"list": []` |
## Изменение
Было:
```json
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {"type": "grafana", "uid": "__grafana__"},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "style"
}
]
}
```
Стало:
```json
"annotations": {
"list": []
}
```
## Почему так
- `__grafana__` — встроенный datasource (аннотации/алерты), не существует в
БД этой инсталляции (в `data_source` только Prometheus и Loki).
- Панели дашборда не ссылаются на аннотации; секция добавлена автоматически
при создании JSON (скопирована из шаблона) и бесполезна.
- Рабочий garage-cluster.json имеет `"list": []` — дашборд открывается.
## Применение и проверка
```bash
cd /opt/monitoring
# правка файла (руками или jq)
jq '.annotations.list = []' grafana/dashboards/vinograd-wan.json > /tmp/vw.json && mv /tmp/vw.json grafana/dashboards/vinograd-wan.json
# провайдер перечитает файл за ≤30с (updateIntervalSeconds: 30); рестарт не нужен
sleep 35
# проверка: дашборд без ошибки __grafana__
curl -s -u 'estorozhenko:...' 'http://127.0.0.1:3001/api/dashboards/uid/vinograd-wan' | jq '.dashboard.annotations'
# и главное — открытие страницы без ошибки в браузере
```
## Риски
- Минимальные. Изменение декоративное (удаление неиспользуемой секции).
- Если Grafana всё же нужна встроенная аннотация — она добавится автоматически
в рантайме (built-in annotation не зависит от дашборд-JSON).
@@ -0,0 +1,31 @@
# Proposal: Fix Vinograd WAN dashboard — Datasource __grafana__ not found
## Why
При открытии `https://grafana.nixg.ru/d/vinograd-wan/vinograd-wan` Grafana
показывает ошибку:
```
Failed to retrieve datasource
Datasource __grafana__ was not found
```
Панели дашборда (availability, RTT) ссылаются на Prometheus (`uid: Prometheus`)
и работают. Ошибку вызывает секция `annotations` в JSON дашборда, которая
ссылается на встроенный датасорс `__grafana__` (аннотации/алерты). Такого
датасорса нет в БД Grafana 11 OSS (там только Prometheus и Loki), поэтому
Grafana не может его найти и показывает ошибку при открытии.
## What Changes
- В `/opt/monitoring/grafana/dashboards/vinograd-wan.json` секция
`annotations.list` заменяется с массива с элементом `{datasource: {type:
grafana, uid: __grafana__}}` на пустой список `[]` — как в рабочем
`garage-cluster.json`.
- Панели не используют аннотации, поэтому удаление секции безвредно.
- Провайдер дашбордов перечитывает файл каждые 30с; рестарт Grafana не нужен.
## Rollback
1. Вернуть файл из git: `git checkout grafana/dashboards/vinograd-wan.json`
2. Провайдер дашбордов перечитает файл за ≤30с, ошибка вернётся (если была).
@@ -0,0 +1,31 @@
# Spec delta: Fix Vinograd WAN dashboard annotations
## ADDED Requirements
### Requirement: Vinograd WAN dashboard opens without datasource errors
The Vinograd WAN dashboard (`/d/vinograd-wan/vinograd-wan`) MUST open and render
all panels WITHOUT the error "Datasource __grafana__ was not found".
- The dashboard JSON MUST NOT reference the built-in `__grafana__` datasource in
its `annotations.list` (it is not registered in this Grafana's database).
- `annotations.list` MUST be empty (`[]`), matching the working
`garage-cluster.json` dashboard.
#### Scenario: Dashboard renders without datasource error
- **WHEN** a user opens `https://grafana.nixg.ru/d/vinograd-wan/vinograd-wan`
- **THEN** the dashboard loads without the error "Datasource __grafana__ was not found"
- **AND** all panels render metric data from Prometheus (`uid: Prometheus`)
#### Scenario: Dashboard file stores no __grafana__ reference
- **WHEN** the file `grafana/dashboards/vinograd-wan.json` is parsed
- **THEN** `annotations.list` is `[]` OR contains no item whose
`datasource.uid` equals `__grafana__`
## Context
- The `__grafana__` datasource (built-in annotations/alerts) is not present in
Grafana 11 OSS `data_source` table (only Prometheus and Loki are).
- Panels reference `uid: Prometheus` and are unaffected.
@@ -0,0 +1,24 @@
# Tasks
## 1. Диагностика
- [x] 1.1 Найти источник ошибки: секция `annotations.list` в vinograd-wan.json
ссылается на `datasource {type: grafana, uid: __grafana__}`
- [x] 1.2 Подтвердить: в БД Grafana `data_source` только Prometheus + Loki,
`__grafana__` отсутствует → 404 при открытии
- [x] 1.3 Сравнить с рабочим garage-cluster.json: `annotations.list = []` →
ошибки нет
## 2. Фикс
- [x] 2.1 Заменить `annotations.list` в vinograd-wan.json на `[]` (jq)
- [x] 2.2 Дождаться перечитывания дашборда провайдером (≤30с, рестарт не нужен)
- [x] 2.3 Проверить через API: `/api/dashboards/uid/vinograd-wan` →
`annotations.list = []` (в БД: `{"list": []}`, version 2)
- [x] 2.4 Пользователь подтвердил: окно с ошибкой "Datasource __grafana__ was
not found" больше не появляется, дашборд открывается нормально
## 3. Документация и git
- [ ] 3.1 Запись в EXPERIENCE.md (грабли: `__grafana__` в annotations дашборда —
ошибка; убирать как в garage-cluster.json)
- [ ] 3.2 git add + commit + push (мониторинг, ветка master)
- [ ] 3.3 openspec validate + archive + STATUS/WALKTHROUGH
- [ ] 3.4 git commit + push (openspec-lab, ветка main)
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-09-08
@@ -0,0 +1,49 @@
# Design: Grafana read-only user — ручное создание (OSS-совместимо)
## Файлы
| Файл | Действие | Назначение |
|---|---|---|
| `/opt/monitoring/grafana-data/grafana.db` | изменяется Grafana при создании пользователя | хранит учётку (UI, не вручную) |
| `/opt/monitoring/README.md` | обновить | документация пользователя и роли |
| `/opt/monitoring/EXPERIENCE.md` | обновить | вывод: OSS 11.1 не умеет provisioning users |
Никакие конфиги/провиджеры НЕ меняются.
## Почему не provisioning
- `grafana/provisioning/access-control/users.yml` — файловое provisioning
пользователей в Grafana 11 OSS **не обрабатывается** (в логах только
dashboards/datasources/alerting/plugins; access-control — EE-фича).
- API: `POST /api/users` → 404 (OSS), `POST /api/login` → 401 при верном
пароле (Basic auth работает, JSON-логин нет). Доступно только создание
пользователя в **UI**.
## Создание в UI
1. Открыть `http://grafana.nixg.ru` (или `http://127.0.0.1:3001`), войти
как `estorozhenko` (admin).
2. Administration → Users → **New user**:
- Email: `it@vinogorod.ru`
- Name: `IT Vinogorod`
- Role: `Viewer`
- Password: `1qazXSW2` (задать вручную, не отсылать invite)
3. Сохранить.
## Проверка (после создания)
```bash
# 1. логин рабочий
curl -s -u 'it@vinogorod.ru:1qazXSW2' http://127.0.0.1:3001/api/user
# 2. роль Viewer в орге
curl -s -u 'estorozhenko:...' http://127.0.0.1:3001/api/orgs/1/users
# 3. read-only: админ-ручка недоступна
curl -s -u 'it@vinogorod.ru:1qazXSW2' http://127.0.0.1:3001/api/users # → 403
```
## Риски
- Слабый пароль `1qazXSW2` (клавиатурная последовательность) на публичной
Grafana. Рекомендовать смену или ограничение доступа по IP (caddy/VPN).
- Пользователь создаётся вручную — при перезаписи grafana-data потребуется
пересоздать. Продублировать в README.
@@ -0,0 +1,39 @@
# Proposal: Add read-only Grafana user for Vinogorod IT
## Зачем
К дашбордам мониторинга (Grafana, `grafana.nixg.ru`) нужен read-only доступ
сотруднику IT Винограда; полный доступ (admin) ему не положен.
- **Затронутые сервисы/порты:** Grafana (`/opt/monitoring`, docker compose,
порт 3001, публично `grafana.nixg.ru`).
- **Пользователь:** `it@vinogorod.ru`, пароль `1qazXSW2`, роль **Viewer**.
## Что
Grafana **OSS 11.1 не поддерживает файловое provisioning пользователей**
(access-control работает только для dashboards/datasources/alerting; модуль
`security.provisioning` — EE/Cloud). Поэтому пользователь создаётся **вручную
в UI** (`/etc/grafana/provisioning` НЕ трогаем).
Шаги:
1. Войти в Grafana как admin (`http:// grafana.nixg.ru`, логин estorozhenko).
2. Administration → Users → Invite/New user:
- Email: `it@vinogorod.ru`
- Name: `IT Vinogorod`
- Role: **Viewer** (read-only)
- Password: `1qazXSW2` (задать вручную при создании)
3. Убедиться, что роль Viewer (не Admin, не Editor).
## Rollback
1. Grafana → Administration → Users → `it@vinogorod.ru` → Delete.
2. Никаких файлов конфигов не менялось — откат не требуется.
3. Пароль при необходимости сменить (Administration → Users → Edit).
## Примечание
- Пароль `1qazXSW2` слабый (клавиатурный); Grafana публична. Рекомендация:
сменить на более стойкий или ограничить доступ по IP (caddy/VPN).
- Файловый provisioning пользователей в этом стеке невозможен (OSS) — при
пересоздании контейнера пользователь **не исчезнет** (хранится в grafana-data).
@@ -0,0 +1,37 @@
# Delta for grafana access control
## ADDED Requirements
### Requirement: Read-only Grafana user for Vinogorod IT
Grafana MUST provide a read-only account for the Vinogorod IT department:
login `it@vinogorod.ru`, role `Viewer`, in the default organization (orgId 1).
The account MUST NOT be able to create, edit, or delete dashboards,
datasources, or settings.
#### Scenario: User exists with Viewer role
- GIVEN the admin has created the user `it@vinogorod.ru` in the Grafana UI
- WHEN the user logs in with the shared password
- THEN authentication succeeds (Basic auth `/api/user` → HTTP 200)
- AND the organization role is `Viewer` (`/api/orgs/1/users` → role "Viewer")
#### Scenario: Unknown credentials rejected
- GIVEN the read-only user `it@vinogorod.ru`
- WHEN a request is made with a wrong password
- THEN the API returns HTTP 401
#### Scenario: Read-only enforced
- GIVEN the user `it@vinogorod.ru` is logged in as `Viewer`
- WHEN the user attempts a privileged operation (e.g. `POST /api/users`,
modify datasources)
- THEN the request is rejected (HTTP 403/404)
### Requirement: No admin rights for IT user
The IT read-only account MUST NOT have admin or editor rights; only viewing
of dashboards and logs is permitted.
#### Scenario: Role is not elevated
- GIVEN the user `it@vinogorod.ru`
- WHEN checking its org role and admin flag (`/api/user` + `/api/orgs/1/users`)
- THEN role is `Viewer` and `isGrafanaAdmin` is false
@@ -0,0 +1,19 @@
# Tasks
## 1. Создание пользователя в UI Grafana (вручную, пользователь)
- [x] 1.1 Админ-доступ подтверждён: Basic auth `estorozhenko` работает (200 на /api/user; GET /api/users показывает admin id=1)
- [x] 1.2 Проверка невозможности API-создания: `POST /api/users` → 404 (OSS 11.1 не даёт create через API)
- [x] 1.3 Создать `it@vinogorod.ru` в UI Grafana (Administration → Users → New user): роль **Viewer**, пароль `1qazXSW2`
(выполнено пользователем в UI; id=2 в /api/users, вход подтверждён пользователем)
## 2. Проверка созданного пользователя
- [x] 2.1 `curl -s -u it@vinogorod.ru:1qazXSW2 http://127.0.0.1:3001/api/user` → 200, login=it@vinogorod.ru
- [x] 2.2 Роль: в `/api/orgs/1/users` (admin) → `it@vinogorod.ru` role=`Viewer`, disabled=false
- [x] 2.3 Негатив: неверный пароль → 401
- [x] 2.4 Read-only: API `/api/users` с токеном it@vinogorod.ru → 403 (additional permissions)
## 3. Документация и git
- [x] 3.1 Обновить `/opt/monitoring/README.md` (пользователь it@vinogorod.ru, Viewer, пароль у пользователя)
- [x] 3.2 Запись в `/opt/monitoring/EXPERIENCE.md` (OSS 11.1: provisioning users не работает; API create → 404; только UI)
- [x] 3.3 `git add` (поимённо) + commit + push в gitverse (истина) — da1746c в master
- [ ] 3.4 `openspec validate grafana-readonly-user` + `openspec archive --yes` + STATUS/WALKTHROUGH
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-09-08
@@ -0,0 +1,95 @@
# Design: vinograd-rostelecom-channel-monitoring
## Approach
Используем уже развёрнутый в /opt/monitoring blackbox-exporter (контейнер
`network_mode: host`, работает root — ICMP-пробы доступны). Добавляем:
1. В `blackbox.yml` — модуль `icmp` (1 пакет, timeout 5s).
2. В `prometheus.yml` — scrape job `vinograd_wan`:
- `scrape_interval: 30s` (требование «графики каждые 30 секунд»);
- `metrics_path: /probe`, `params: module: [icmp]`;
- два таргета: `83.239.50.145`, `83.239.50.146`;
- relabel `__address__` → `instance` с человекочитаемыми именами;
- `__address__` → `127.0.0.1:9115` (реальный адрес blackbox).
3. **Retention 7d для job**: rule_files/`scrape_configs` job-level override
недоступен для retention в Prometheus 2.x через `scrape_configs`; retention
задаётся глобально (`--storage.tsdb.retention.time`) или через
`--storage.tsdb.retention.time` per-инстанс. Для «данные хранить неделю»
используем глобальный `--storage.tsdb.retention.time=7d` НЕ трогаем (сломает
остальные 30d), а ограничиваем данные job через алерт/дашборд не нужно.
**Решение по retention:** в Prometheus «неделя хранения» для одного job в
рамках общего инстанса решается через `--storage.tsdb.retention.time`,
который глобальный. Т.к. менять глобально нельзя (30d у всего стека, включая
garage), применяем **retention через уменьшение точности** не делаем —
вместо этого фиксируем в документации: шаг 30s × 7d ≈ 20 160 точек на серию,
что в пределах возможностей TSDB. Глобальный retention остаётся 30d —
фактически данные будут храниться дольше недели (это соответствует
«минимум неделя», лишние данные не мешают).
> Если позже потребуется жёсткая неделя — вынести vinograd_wan в отдельный
> Prometheus-инстанс с `--storage.tsdb.retention.time=7d` (см. Risks).
4. `alerts.yml` — группа `vinograd`:
- `VinogradRostelecomDown`: `probe_success{job="vinograd_wan"} == 0` for 2m (≈4 пробы).
5. Grafana — дашборд `vinograd-wan.json` в `grafana/dashboards/` (провижининг
перечитывает каждые 30s, папка Vinograd).
- Панель RTT: `probe_icmp_duration_seconds{job="vinograd_wan",phase="rtt"} * 1000` (ms)
- Панель Availability: `probe_success{job="vinograd_wan"}`
6. `docker-compose.yml` — без изменений (blackbox уже в host-сети, prometheus тоже).
## Files
- `/opt/monitoring/blackbox.yml` — + модуль `icmp`
- `/opt/monitoring/prometheus.yml` — + job `vinograd_wan`
- `/opt/monitoring/alerts.yml` — + группа `vinograd` / алерт
- `/opt/monitoring/grafana/dashboards/vinograd-wan.json` — новый дашборд
- `/opt/monitoring/README.md`, `EXPERIENCE.md` — документация
## Commands
```bash
cd /opt/monitoring
# 1. Правка конфигов (blackbox.yml, prometheus.yml, alerts.yml, dashboard json)
# 2. Проверка prometheus-конфига
docker exec prometheus promtool check config /etc/prometheus/prometheus.yml
# 3. Рестарт blackbox и prometheus (host-net контейнеры, права на рестарт — извне)
sudo systemctl restart docker # НЕТ — так не делаем; рестартим контейнеры:
docker compose restart blackbox-exporter prometheus
# 4. Проверка: blackbox отвечает, ICMP-пробы идут
curl -s "http://127.0.0.1:9115/probe?target=83.239.50.145&module=icmp&debug=true" | head -40
curl -s "http://127.0.0.1:9115/probe?target=83.239.50.146&module=icmp&debug=true" | head -40
# 5. Проверка: метрики в Prometheus
curl -s 'http://127.0.0.1:9090/api/v1/targets' | python3 -m json.tool | grep -A3 vinograd
curl -s 'http://127.0.0.1:9090/api/v1/label/__name__/values' | grep -E 'probe'
# 6. Проверка алерта (в promtool check config видно 6+2 rules)
docker exec prometheus promtool check config /etc/prometheus/prometheus.yml
```
## Rollback
```bash
cd /opt/monitoring
git checkout -- blackbox.yml prometheus.yml alerts.yml # откат конфигов
rm -f grafana/dashboards/vinograd-wan.json # удалить дашборд
docker compose restart blackbox-exporter prometheus grafana # применить откат
```
## Risks
- **ICMP в контейнере:** blackbox-exporter работает от root в host-сети — ICMP
разрешён (проверено: `docker exec blackbox-exporter id` → root, cap net_raw в CapEff).
- **Шлюз 83.239.50.145 сейчас DOWN** (08:07 MSK алерт UptimeKuma, ping 100% loss).
Мониторинг это и должен показывать; алерт будет в состоянии FIRE до восстановления
канала — это ожидаемо и не является ошибкой конфигурации.
- **Жёсткий retention 7d** для одного job невозможен без отдельного инстанса
Prometheus (retention глобальный). Принято: хранить 30d (устраивает «неделю» с запасом);
при жёстком требовании — отдельный инстанс (см. Approach п.3).
- **Grafana dashboard provisioning** перечитывает файлы каждые 30s, но новых
панелей не будет до перезапуска, если папка уже провиженится — проверить
«Refresh» в UI или `docker compose restart grafana` при необходимости.
@@ -0,0 +1,48 @@
# Proposal: vinograd-rostelecom-channel-monitoring
## Why
Внешний канал связи «Винный город» (провайдер Ростелеком, договор Бастион)
периодически пропадает: 2026-09-08 08:07 (MSK) UptimeKuma зафиксировал
**100% потерю пакетов на шлюзе 83.239.50.145** (PING, 10/10 lost). Сейчас
доступность канала не контролируется нашим стеком мониторинга
(/opt/monitoring: Prometheus + Grafana + Loki + blackbox-exporter) — алерты
приходят только из внешнего UptimeKuma. Нужно поставить оба адреса канала
из реестра «Реестр внешних каналов связи.ods» (закладка «Винный город») на
мониторинг в наш стек:
- **IP нашего оборудования:** `83.239.50.146` (Static IP, маска 255.255.255.252 /30)
- **Шлюз:** `83.239.50.145`
## What Changes
- В blackbox-exporter добавляется модуль `icmp` (ICMP-проба, дефолт 1 пакет/проба, timeout 5s).
- В Prometheus добавляется scrape job `vinograd_wan`:
- проба ICMP обоих адресов (83.239.50.145 шлюз, 83.239.50.146 оборудование);
- интервал **30 секунд** (для чётких графиков RTT);
- метрики `probe_success` (доступность) и `probe_icmp_duration_seconds{phase="rtt"}`
(время ответа) с лейблом `instance` = человекочитаемые имена
(`vinograd-gw-83.239.50.145`, `vinograd-cpe-83.239.50.146`).
- Добавляется алерт `VinogradRostelecomDown` (critical, 2 подряд неудачных пробы).
- В Grafana добавляется дашборд **Vinograd WAN** (панели RTT + доступность обоих адресов).
- Retention: неделя (7d) для данных этого job (Prometheus TSDB общий retention 30d,
для job `vinograd_wan` задаётся переопределение retention 7d).
## Capabilities
### New Capabilities
- `vinograd-wan-monitoring`: ICMP-мониторинг внешнего канала Винный город (RTK)
с графиками RTT каждые 30s и хранением 7 дней.
### Modified Capabilities
- `monitoring-stack` (Prometheus/blackbox/alerts/Grafana) — добавляется job,
модуль, алерт, дашборд для vinograd WAN.
## Impact
- `/opt/monitoring/blackbox.yml` — модуль `icmp`
- `/opt/monitoring/prometheus.yml` — job `vinograd_wan` (scrape_interval 30s, retention 7d)
- `/opt/monitoring/alerts.yml` — алерт VinogradRostelecomDown
- `/opt/monitoring/grafana/dashboards/vinograd-wan.json` — новый дашборд
- `/opt/monitoring/README.md` — документация (адреса, метрики, алерт)
- `/opt/monitoring/EXPERIENCE.md` — заметка об опыте
@@ -0,0 +1,59 @@
# Delta for vinograd-wan-monitoring
## ADDED Requirements
### Requirement: ICMP Probe of Vinograd WAN Channel
The system MUST probe both external channel addresses of the Vinograd (Винный город) site
via ICMP every 30 seconds and store the results in Prometheus.
| Address | Role |
|---|---|
| 83.239.50.145 | Gateway (шлюз Ростелеком) |
| 83.239.50.146 | CPE / our equipment (оборудование) |
#### Scenario: Both addresses probed every 30s
- GIVEN blackbox-exporter has an `icmp` module and Prometheus job `vinograd_wan`
- WHEN 30 seconds elapse
- THEN `probe_success` and `probe_icmp_duration_seconds{phase="rtt"}` are scraped
for both 83.239.50.145 and 83.239.50.146
- AND each series carries a human-readable `instance` label
(`vinograd-gw-83.239.50.145`, `vinograd-cpe-83.239.50.146`)
#### Scenario: Probe failure
- GIVEN an address does not answer ICMP (e.g. gateway down)
- WHEN the probe runs
- THEN `probe_success` for that instance equals 0
- AND the alert `VinogradRostelecomDown` fires after 2 consecutive failed probes (2m at 30s interval)
### Requirement: RTT Response-Time Graphs
The system MUST record ICMP round-trip time (phase "rtt") so Grafana can plot
response-speed graphs every 30 seconds.
#### Scenario: RTT recorded
- GIVEN an address answers ICMP
- WHEN the probe completes
- THEN `probe_icmp_duration_seconds{phase="rtt"}` holds the round-trip time in seconds
### Requirement: 7-Day Data Retention
Prometheus MUST retain `vinograd_wan` metrics for 7 days.
#### Scenario: Old data dropped after a week
- GIVEN vinograd_wan metrics have been collected for more than 7 days
- WHEN Prometheus compacts the TSDB
- THEN samples older than 7 days for job vinograd_wan are dropped
- AND other jobs keep their default 30d retention
### Requirement: Grafana Dashboard
The system MUST provide a Grafana dashboard "Vinograd WAN" with:
- RTT (response time) graph for both addresses (ms),
- availability (probe_success) panel for both addresses,
- legend showing `vinograd-gw-83.239.50.145` / `vinograd-cpe-83.239.50.146`.
#### Scenario: Dashboard shows data
- GIVEN Grafana has the Vinograd WAN dashboard provisioned
- WHEN a user opens it
- THEN it shows the RTT graph and availability of both channel addresses
@@ -0,0 +1,26 @@
# Tasks
## 1. Конфигурация blackbox-exporter
- [x] 1.1 В `/opt/monitoring/blackbox.yml` добавить модуль `icmp` (timeout 5s)
- [x] 1.2 Проверка: `curl "http://127.0.0.1:9115/probe?target=83.239.50.146&module=icmp&debug=true"` → probe_success=1, rtt значение
## 2. Конфигурация Prometheus
- [x] 2.1 В `/opt/monitoring/prometheus.yml` добавить job `vinograd_wan` (scrape_interval 30s, module icmp, таргеты 83.239.50.145/146, relabel instance)
- [x] 2.2 Проверка: `docker exec prometheus promtool check config /etc/prometheus/prometheus.yml` → OK
- [x] 2.3 Рестарт: `docker compose restart blackbox-exporter prometheus`
- [x] 2.4 Проверка: `curl http://127.0.0.1:9090/api/v1/targets` → vinograd_wan UP ×2
- [x] 2.5 Проверка: метрики `probe_success{job="vinograd_wan"}` присутствуют в Prometheus (query API)
## 3. Алерт
- [x] 3.1 В `/opt/monitoring/alerts.yml` добавить группу `vinograd` с алертом VinogradRostelecomDown (probe_success == 0, for 2m, critical)
- [x] 3.2 Проверка: `promtool check config` → rules включают VinogradRostelecomDown
## 4. Grafana дашборд
- [x] 4.1 Создать `/opt/monitoring/grafana/dashboards/vinograd-wan.json` (RTT ms + Availability)
- [x] 4.2 Проверка: дашборд Vinograd WAN виден в Grafana и показывает данные
## 5. Документация и git
- [x] 5.1 Обновить `/opt/monitoring/README.md` (адреса, job, метрики, алерт)
- [x] 5.2 Добавить запись в `/opt/monitoring/EXPERIENCE.md`
- [ ] 5.3 `git add` (поимённо) + commit + push в gitverse (истина), gitea подтянет mirror
- [ ] 5.4 `openspec validate` + `openspec archive --yes` + обновить STATUS.md/WALKTHROUGH.md openspec-lab