# GHard Monitor

**Gnexus Hardware Monitor** — сбор мониторинга всех серверов в одном месте.

```
┌───────────────┐   POST /api/v1/ingest   ┌────────────────────┐
│ hard-monitor  │ ─────────────────────► │  hard-panel        │
│ (агент,       │   метрики + ключ       │  FastAPI + SQLite  │
│  stateless)   │                        │  + Vue UI          │
└───────────────┘                        └────────────────────┘
```

- **panel/** — панель: приём метрик, SQLite, ивенты, алерты, веб-интерфейс
  (Vue 3 + [gnexus-ui-kit](https://git.gnexus.space/root/gnexus-ui-kit) + chart.js)
- **monitor/** — агент на серверах: psutil-сбор фактов, POST на панель.
  Агент stateless, вся логика (пороги, ивенты, скорость сети по дельте
  счётчиков) — на панели.

## Стек

| Часть | Технологии |
|---|---|
| panel backend | Python 3.12, FastAPI, aiosqlite (SQLite, WAL) |
| panel frontend | Vue 3, gnexus-ui-kit, chart.js |
| monitor | Python 3.8+ (psutil, requests), systemd |
| Деплой | Docker / docker-compose |

## Разворачивание panel

Нужен сервер с docker и docker compose. SQLite живёт в volume — отдельной
БД не надо.

```bash
git clone https://git.gnexus.space/git/root/hard-panel.git
cd hard-panel
```

**1. Конфиг** — корень репо, рядом с docker-compose.yml:

```bash
cp panel/backend/.env.example .env
```

Отредактируй `.env`:

```ini
# порт, на котором панель слушает снаружи (по умолчанию 8000)
GHARD_PANEL_PORT=8000
```

`GHARD_ADMIN_TOKEN` — опционален: веб-интерфейс работает без логина.
Если задать токен, API панели (создание серверов, метрики) закроется
Bearer-токеном — удобно, когда панель торчит в интернет, а UI тебе не нужен.
Единственная настоящая авторизация в системе — ключи агентов (`ghm_...`).

**2. Запуск:**

```bash
docker compose up -d --build
```

Проверка: `curl http://localhost:8000/api/v1/health` → `{"status":"ok"}`.
OpenAPI-документация: `http://localhost:8000/docs`.

**3. Reverse proxy (рекомендуется)** — агенты будут слать метрики из
интернета, поэтому панель стоит закрыть TLS-ом. Пример Caddy:

```
panel.example.com {
    reverse_proxy 127.0.0.1:8000
}
```

Caddy сам выпустит сертификат. Для nginx: `proxy_pass http://127.0.0.1:8000;`
и обычный certbot. Заголовок `X-Forwarded-For` панель учитывает — в
карточке сервера будет виден реальный IP агента.

## Добавление сервера и установка агента

Проще всего — кнопка «Добавить сервер» в веб-интерфейсе. Через API то же самое:

```bash
curl -X POST https://panel.example.com/api/v1/servers \
    -H "Content-Type: application/json" \
    -d '{"name": "web-01"}'
```

Ответ — **plaintext-ключ, показывается один раз**, сохрани сразу:

```json
{"id": 1, "name": "web-01", "key": "ghm_KyfA9jheG9OSZxFlfFmdx8yFpO3tZAcO"}
```

Дальше на целевом сервере (python3 + pip):

```bash
curl -fsSL https://git.gnexus.space/root/hard-panel/raw/branch/master/monitor/install.sh | \
    sudo bash -s -- https://panel.example.com ghm_KyfA9jheG9OSZ... 30
```

Скрипт поставит всё в `/opt/hard-monitor` (venv + psutil + requests),
запишет `.env` с правами 600, установит systemd-юнит `hard-monitor` и
запустит. Повторный запуск — обновление агента.

Логи и управление:

```bash
journalctl -u hard-monitor -f      # смотреть логи
systemctl restart hard-monitor     # рестарт
```

Проверка на панели — сервер должен получить `status: "online"`:

```bash
curl -s https://panel.example.com/api/v1/servers
```

## Массовое развёртывание агентов (в том числе ИИ-агентом)

`monitor/deploy.sh` делает весь цикл сам: создаёт сервер на панели →
заходит по SSH → ставит агента → ждёт первый пакет. Одна команда на
любое число хостов:

```bash
cd monitor
./deploy.sh --panel https://panel.example.com user@web-01 user@db-01 user@cache-01
```

Опции:

| Опция | Что делает |
| --- | --- |
| `--panel URL` | адрес панели (обязательно) |
| `--token TOKEN` | GHARD_ADMIN_TOKEN — нужен, только если токен на панели задан |
| `--interval N` | интервал агента в секундах (по умолчанию 30) |
| `--recreate` | удалить существующую запись сервера на панели и создать заново (новый ключ); без него ключ переиспользуется из `/opt/hard-monitor/.env` на хосте |
| `--git-install` | ставить curl-ом из репозитория; по умолчанию файлы агента заливаются scp с локальной машины |

Требования к хостам: SSH-доступ по ключу, `python3`, `sudo` без пароля.
Повторный запуск на уже развёрнутом хосте — обновление агента
(запись на панели и ключ сохраняются).

### Развёртывание ИИ-агентом (Claude Code и т.п.)

Скрипт специально сделан неинтерактивным и идемпотентным, чтобы его мог
запустить ИИ-агент с SSH-доступом к машинам. Промт для агента:

```text
Разверни hard-monitor на моих серверах. Панель: https://panel.example.com
1. Склонируй https://git.gnexus.space/git/root/hard-panel.git (нужна папка monitor/)
2. Запусти: cd monitor && ./deploy.sh --panel https://panel.example.com user@host1 user@host2 ...
3. Если какой-то хост упал с ошибкой — разберись (ssh, journalctl -u hard-monitor),
   почини и перезапусти deploy.sh только для этого хоста
4. Проверь, что все серверы online: curl -s https://panel.example.com/api/v1/servers
   (у каждого status: "online")
```

Агенту не нужен доступ к UI панели: серверы создаются через API, ключи
никогда не показываются человеку и не сохраняются — install.sh сразу
кладёт их в `/opt/hard-monitor/.env` (права 600).

## Обновление

**Panel** — на сервере с панелью:

```bash
cd hard-panel
git pull
docker compose up -d --build
```

**Агент** — на каждом сервере (нужны свежие `hard_monitor.py` /
`hard-monitor.service` в текущем каталоге — склонируй репо):

```bash
git clone https://git.gnexus.space/git/root/hard-panel.git && cd hard-panel/monitor
sudo ./install.sh   # с теми же PANEL_URL/SERVER_KEY — перезапишет файлы и рестартанёт
```

Или вручную: скопируй `hard_monitor.py` в `/opt/hard-monitor/` и
`systemctl restart hard-monitor`. Конфиг `.env` не трогается.

## Бэкапы

Вся панель — один файл SQLite в volume `panel-data`. Полный бэкап:

```bash
docker compose exec panel python -c \
    "import sqlite3; sqlite3.connect('/data/hard-panel.db').backup(sqlite3.connect('/data/backup.db'))"
docker compose cp panel:/data/backup.db ./hard-panel-backup.db
```

(или просто остановить и скопировать volume). Ключи серверов в БД —
хэши, восстановить plaintext из бэкапа нельзя: потерянный ключ —
пересоздай сервер.

## Конфигурация panel (env)

| Переменная | По умолчанию | Описание |
|---|---|---|
| `GHARD_ADMIN_TOKEN` | *(пусто)* | опциональный Bearer-токен API; веб-интерфейс работает без логина |
| `GHARD_DATABASE_PATH` | `/data/hard-panel.db` | путь к SQLite |
| `GHARD_PANEL_PORT` | `8000` | host-порт (docker-compose) |
| `GHARD_OFFLINE_MULTIPLIER` | `3` | offline = нет пакетов дольше N × interval |

## API (кратко)

- `POST /api/v1/servers` — создать сервер, получить ключ агента (один раз)
- `POST /api/v1/ingest` — пакет метрик агента, заголовок `X-Server-Key`
- `GET /api/v1/servers` — сводка для дашборда
- `GET /api/v1/servers/{id}` — карточка + последняя точка
- `GET /api/v1/servers/{id}/metrics?since=…&until=…` — история для графиков
- `PATCH /api/v1/servers/{id}` — имя / заметка
- `DELETE /api/v1/servers/{id}` — удалить сервер (с каскадом метрик)

## Статус

- [x] Этап 1 — скелет: FastAPI, SQLite-схема, ingest, servers API, docker
- [x] Этап 2 — hard-monitor агент + install.sh + systemd
- [ ] Этап 3 — веб-интерфейс (Vue + ui-kit + chart.js)
- [ ] Этап 4 — ивенты + алерты (Telegram, webhook)
- [ ] Этап 5 — downsample истории (7 дней), финальный деплой