mirror of
https://gitverse.ru/kpa39l/openspec-lab.git
synced 2026-09-29 09:15:01 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bc206a1159 | |||
| 5b605abd29 | |||
| e195f0030d |
@@ -1,21 +1,24 @@
|
|||||||
# OpenSpec Lab — Статус
|
# OpenSpec Lab — Статус
|
||||||
|
|
||||||
Обновлено: 2026-09-06 (сессия @session:default/20260906_124042_9f05e0)
|
Обновлено: 2026-09-08 (сессия: Grafana read-only пользователь)
|
||||||
|
|
||||||
## Текущее состояние
|
## Текущее состояние
|
||||||
Лаборатория spec-driven подхода (OpenSpec CLI 1.12.0) для задач настройки инфраструктуры Hermes/homelab. Цикл propose→apply→archive работает; 3 change заархивированы. Tavily-прокси (web_extract) работает end-to-end в forward-режиме (решение по задаче 5: оставить как есть). Локальный экстрактор (trafilatura) написан и протестирован (2.2/2.3 зелёные), change заархивирован. Репозиторий создан на gitverse.ru, main запушен.
|
Лаборатория spec-driven подхода (OpenSpec CLI 1.12.0) для задач настройки инфраструктуры Hermes/homelab. Цикл propose→apply→archive работает; **5 change заархивированы**. Tavily-прокси (web_extract) работает end-to-end в forward-режиме (решение по задаче 5: оставить как есть). Локальный экстрактор (trafilatura) написан и протестирован (2.2/2.3 зелёные), change заархивирован. Репозиторий создан на gitverse.ru, main запушен. ICMP-мониторинг канала «Винный город» заархивирован (в /opt/monitoring). Read-only пользователь Grafana (it@vinogorod.ru, Viewer) добавлен через UI — change заархивирован.
|
||||||
|
|
||||||
## Сделано
|
## Сделано
|
||||||
- [x] OpenSpec CLI установлен (npm, 1.12.0), лаба инициализирована с --tools hermes (6 скиллов)
|
- [x] OpenSpec CLI установлен (npm, 1.12.0), лаба инициализирована с --tools hermes (6 скиллов)
|
||||||
- [x] config.yaml с инфраструктурным контекстом (systemd, docker, /opt/<svc>/, gitverse)
|
- [x] config.yaml с инфраструктурным контекстом (systemd, docker, /opt/<svc>/, gitverse)
|
||||||
- [x] change tavily-proxy-setup — ЗААРХИВИРОВАН (delta → specs/web-extract-tavily/spec.md)
|
- [x] change tavily-proxy-setup — ЗААРХИВИРОВАН (delta → specs/web-extract-tavily/spec.md)
|
||||||
- [x] web_extract работает: Hermes → 8971 → SOCKS5-туннель → Tavily (HTTP 200, контент Example Domain)
|
- [x] web_extract работает: Hermes → 8971 → SOCKS5-туннель → Tavily (HTTP 200, контент Example Domain)
|
||||||
- [x] change local-extractor — ЗААРХИВИРОВАН: trafilatura 2.2.0, local-режим в tavily_extract_proxy.py, тесты 2.2/2.3 зелёные (example.com и github через --local; tavily.com — geo-блок из РФ — через --local-socks 127.0.0.1:1080, HTTP 200)
|
- [x] change local-extractor — ЗААРХИВИРОВАН: trafilatura 2.2.0, local-режим в tavily_extract_proxy.py, тесты 2.2/2.3 зелёные
|
||||||
- [x] Репозиторий создан на gitverse.ru (kpa39l/openspec-lab), git push -u origin main выполнен
|
- [x] Репозиторий создан на gitverse.ru (kpa39l/openspec-lab), git push -u origin main выполнен
|
||||||
- [x] systemd tavily-proxy.service — решение по задаче 5: ОСТАВЛЕН forward-режим (облачный Tavily через туннель) — рабочий провайдер без изменений
|
- [x] systemd tavily-proxy.service — решение по задаче 5: ОСТАВЛЕН forward-режим (облачный Tavily через туннель)
|
||||||
|
- [x] change vinograd-rostelecom-channel-monitoring — ЗААРХИВИРОВАН (2026-09-08): ICMP-мониторинг канала «Винный город» в /opt/monitoring, дашборд Vinograd WAN
|
||||||
|
- [x] change grafana-readonly-user — ЗААРХИВИРОВАН (2026-09-08): read-only пользователь Grafana it@vinogorod.ru (role Viewer, пароль 1qazXSW2), создан вручную в UI (OSS 11.1 не умеет provisioning/API create пользователей). delta → openspec/specs/grafana-access-control/spec.md
|
||||||
|
- [x] change fix-vinograd-dashboard-datasource — ЗААРХИВИРОВАН (2026-09-08): убрана ссылка на встроенный датасорс `__grafana__` в annotations дашборда vinograd-wan (была ошибка "Datasource __grafana__ was not found"). delta → openspec/specs/vinograd-wan-monitoring/spec.md
|
||||||
|
|
||||||
## В работе / Следующие шаги
|
## В работе / Следующие шаги
|
||||||
- (ничего — все 5 задач закрыты; лаба в стабильном состоянии)
|
- (ничего — все задачи закрыты; лаба стабильна)
|
||||||
|
|
||||||
## Как запустить / проверить
|
## Как запустить / проверить
|
||||||
```bash
|
```bash
|
||||||
@@ -23,7 +26,7 @@ cd /opt/hermes/openspec-lab
|
|||||||
openspec validate # все changes
|
openspec validate # все changes
|
||||||
openspec status --change local-extractor
|
openspec status --change local-extractor
|
||||||
# локальный экстрактор (тест)
|
# локальный экстрактор (тест)
|
||||||
./venv/bin/python .hermes/scripts/tavily_extract_proxy.py --port 8972 --local # путь: /opt/hermes/.hermes/hermes-agent/venv/bin/python
|
./venv/bin/python .hermes/scripts/tavily_extract_proxy.py --port 8972 --local
|
||||||
curl -s -X POST http://127.0.0.1:8972/extract -d '{"urls":["https://example.com"]}' -H 'Content-Type: application/json'
|
curl -s -X POST http://127.0.0.1:8972/extract -d '{"urls":["https://example.com"]}' -H 'Content-Type: application/json'
|
||||||
# рабочий прокси (systemd)
|
# рабочий прокси (systemd)
|
||||||
systemctl status tavily-proxy # порт 8971, forward через туннель
|
systemctl status tavily-proxy # порт 8971, forward через туннель
|
||||||
@@ -31,11 +34,12 @@ systemctl status tavily-proxy # порт 8971, forward через туннел
|
|||||||
|
|
||||||
## Ключевые артефакты
|
## Ключевые артефакты
|
||||||
- /opt/hermes/openspec-lab/openspec/specs/web-extract-tavily/spec.md — main spec про forward-прокси
|
- /opt/hermes/openspec-lab/openspec/specs/web-extract-tavily/spec.md — main spec про forward-прокси
|
||||||
- /opt/hermes/openspec-lab/openspec/specs/web-extract-local/spec.md — main spec про local-экстрактор (после archive local-extractor)
|
- /opt/hermes/openspec-lab/openspec/specs/web-extract-local/spec.md — main spec про local-экстрактор
|
||||||
- /opt/hermes/openspec-lab/openspec/changes/archive/2026-09-06-local-extractor/
|
- /opt/hermes/openspec-lab/openspec/specs/vinograd-wan-monitoring/spec.md — ICMP-мониторинг канала
|
||||||
|
- /opt/hermes/openspec-lab/openspec/specs/grafana-access-control/spec.md — read-only пользователь Grafana
|
||||||
|
- /opt/hermes/openspec-lab/openspec/changes/archive/2026-09-08-grafana-readonly-user/ — архивный change
|
||||||
- /opt/hermes/.hermes/scripts/tavily_extract_proxy.py — прокси + local-режим
|
- /opt/hermes/.hermes/scripts/tavily_extract_proxy.py — прокси + local-режим
|
||||||
- /etc/systemd/system/tavily-proxy.service — юнит (forward, без изменений)
|
- /etc/systemd/system/tavily-proxy.service — юнит (forward, без изменений)
|
||||||
- /opt/hermes/openspec-lab/.hermes/skills/openspec-*/ — Hermes-скиллы OpenSpec
|
|
||||||
- gitverse: https://gitverse.ru/kpa39l/openspec-lab (remote origin: https://kpa39l:<TOKEN>@gitverse.ru/kpa39l/openspec-lab.git)
|
- gitverse: https://gitverse.ru/kpa39l/openspec-lab (remote origin: https://kpa39l:<TOKEN>@gitverse.ru/kpa39l/openspec-lab.git)
|
||||||
|
|
||||||
## Открытые вопросы
|
## Открытые вопросы
|
||||||
|
|||||||
@@ -2,6 +2,57 @@
|
|||||||
|
|
||||||
Цель: воспроизводимость spec-driven подхода для инфраструктуры. Хронология по датам.
|
Цель: воспроизводимость spec-driven подхода для инфраструктуры. Хронология по датам.
|
||||||
|
|
||||||
|
## 2026-09-08
|
||||||
|
|
||||||
|
### Grafana: дашборд vinograd-wan — ошибка "Datasource __grafana__ was not found" (change fix-vinograd-dashboard-datasource)
|
||||||
|
|
||||||
|
`openspec new change fix-vinograd-dashboard-datasource` → 4 артефакта
|
||||||
|
(proposal с Why/What Changes) → apply → validate → archive.
|
||||||
|
|
||||||
|
- Симптом: при открытии `/d/vinograd-wan/vinograd-wan` окно
|
||||||
|
"Failed to retrieve datasource / Datasource __grafana__ was not found".
|
||||||
|
- Причина: в JSON дашборда секция `annotations.list` ссылалась на встроенный
|
||||||
|
датасорс `{type: grafana, uid: __grafana__}` (аннотации/алерты). В БД
|
||||||
|
Grafana 11 OSS его нет (только Prometheus + Loki) → 404 при открытии.
|
||||||
|
- Фикс: `jq '.annotations.list = []' ...` — как в рабочем garage-cluster.json.
|
||||||
|
Провайдер дашбордов перечитал за ≤30с (version 2), без рестарта.
|
||||||
|
- **Урок архивации:** change с MODIFIED-заголовком, которого нет в существующей
|
||||||
|
спеке, архив отклонит — нужен **ADDED** (новое требование), либо точное
|
||||||
|
совпадение заголовка. OpenSpec архивация строгая.
|
||||||
|
- monitoring запушен (5ea6fd2, master); openspec-lab — следом.
|
||||||
|
|
||||||
|
### Grafana read-only пользователь (it@vinogorod.ru, Viewer) — change grafana-readonly-user
|
||||||
|
|
||||||
|
`openspec new change grafana-readonly-user` → 4 артефакта → validate → archive
|
||||||
|
(delta → openspec/specs/grafana-access-control/spec.md).
|
||||||
|
|
||||||
|
- Задача: добавить read-only пользователя для IT Винограда.
|
||||||
|
- **Главный вывод:** Grafana 11 OSS НЕ поддерживает ни файловое provisioning
|
||||||
|
пользователей (`grafana/provisioning/access-control/users.yml` молча
|
||||||
|
игнорируется — это EE/Cloud `security.provisioning`), ни API-создание
|
||||||
|
(`POST /api/users` → 404). Создание — **только в UI** (Administration →
|
||||||
|
Users → New user, роль Viewer).
|
||||||
|
- Приятный бонус: `POST /api/login` (JSON) даёт 401 даже при верном пароле,
|
||||||
|
а **Basic auth работает** (`curl -u estorozhenko:пароль /api/user` → 200).
|
||||||
|
- Проверено end-to-end: вход it@vinogorod.ru → 200, роль Viewer, `/api/users`
|
||||||
|
→ 403 (read-only), неверный пароль → 401. Пользователь вошёл сам.
|
||||||
|
- git: мониторинг-репо запушен (da1746c, ветка **master** — не main!).
|
||||||
|
|
||||||
|
### Vinograd WAN — ICMP-мониторинг канала «Винный город» (РТК), change в /opt/monitoring
|
||||||
|
|
||||||
|
`openspec new change vinograd-rostelecom-channel-monitoring` → 4 артефакта → validate OK → archive (delta → openspec/specs/vinograd-wan-monitoring/spec.md)
|
||||||
|
|
||||||
|
- Источник адресов: `/mnt/vinogorod/ИТ/Реестр внешних каналов связи.ods` (это ODS, не XLSX), закладка `Винный_город`: шлюз **83.239.50.145**, оборудование **83.239.50.146**.
|
||||||
|
- Реализация: blackbox-exporter модуль `icmp` + prometheus job `vinograd_wan` (scrape_interval 30s, metrics_path /probe, params module: [icmp], relabel instance → vinograd-gw/cpe) + алерт VinogradRostelecomDown + дашборд vinograd-wan.
|
||||||
|
- Проверено: ICMP-проба .146 → probe_success=1 (RTT ~13ms), .145 → probe_success=0 (шлюз ДО СИХ ПОР DOWN — совпадает с UptimeKuma 08:07 MSK). `promtool check config` → 7 rules. Дашборд в grafana.db (uid vinograd-wan).
|
||||||
|
- Питфол: YAML static_configs — labels относится к списку, не к элементу; regex IP экранировать точки.
|
||||||
|
- Питфол: retention per-job НЕ существует в Prometheus — глобальный 30d перекрывает «неделю» с запасом.
|
||||||
|
|
||||||
|
### Нюансы OpenSpec при работе
|
||||||
|
- `openspec instructions <id>` может ВИСЕТЬ (сетевая проверка/телеметрия) — проще писать артефакты руками по образцу archive/.
|
||||||
|
- `OPENSPEC_TELEMETRY=0` перед CLi-командами — не шумит и не висит.
|
||||||
|
- `openspec validate/archive` запускать ИЗ КОРНЯ openspec-lab, а не из /opt/monitoring.
|
||||||
|
|
||||||
## 2026-09-06
|
## 2026-09-06
|
||||||
|
|
||||||
### Установка OpenSpec
|
### Установка OpenSpec
|
||||||
|
|||||||
@@ -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с, ошибка вернётся (если была).
|
||||||
+31
@@ -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).
|
||||||
+37
@@ -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
|
||||||
+2
@@ -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` при необходимости.
|
||||||
+48
@@ -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` — заметка об опыте
|
||||||
+59
@@ -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
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# grafana-access-control Specification
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
TBD - created by archiving change grafana-readonly-user. Update Purpose after archive.
|
||||||
|
|
||||||
|
## 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,84 @@
|
|||||||
|
# vinograd-wan-monitoring Specification
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
TBD - created by archiving change vinograd-rostelecom-channel-monitoring. Update Purpose after archive.
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
|
### 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__`
|
||||||
Reference in New Issue
Block a user