Метрики збиралися в ts.samples і не показувалися ніде — побачити
зібране можна було лише через psql. Додано GET /devices/{id}/series і
/metrics: джерело (сирі дані, 5m, 1h) обирається за потрібним кроком,
бакетизація в БД, пропуск у даних лишається пропуском, а не лінією
через діру.
Знайдено живим прогоном: зонд працює рівно годину. CredentialTTL —
година, Credentials() свідомо не віддає прострочені (щоб не блокувати
облікові записи на пристроях), а поновлення не просив ніхто:
CredentialRequest є в контракті з Етапу 2, сервер його обробляє, агент
не надсилає. Будь-яка інсталяція припиняла збирати SNMP через годину
після старту й мовчала про це.
Шаблон описує перевірки будь-якого типу, не лише OID. Пачкою в один PDU
збираються тільки snmp.get; решта — елемент на чек, слід у
core.checks.template_item_key. Вбудований шаблон «Доступність (ICMP)».
Імпорт/експорт глобальний і поштучний, свій формат замість Zabbix-YAML.
Спільний розклад бекапів із перевизначенням на хості: прапорець
follows_default, а не порівняння значень — власний розклад може
випадково збігтися зі спільним.
Правило саме каже, куди йде його алерт: канали, тихі години, групи
хостів, повідомлення про відновлення. Канали правила перекривають
маршрути повністю.
Доступи до обладнання отримали свою сторінку: SSH-паролі й
SNMP-community заводяться, змінюються й видаляються з вебу. Секрет
назовні не повертається ніколи.
Дрібниці за скаргами: відступи в картках шаблонів, українська множина,
ручний ввід інтервалу опитування, підтвердження видалення з описом
наслідків замість «Ви впевнені?», помітні кнопки видалення замість
сірого ✕ у кутку.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
73 lines
2.6 KiB
Go
73 lines
2.6 KiB
Go
package session
|
||
|
||
import (
|
||
"context"
|
||
"testing"
|
||
"time"
|
||
|
||
npv1 "github.com/netpulse/netpulse/gen/go/netpulse/v1"
|
||
"google.golang.org/protobuf/types/known/timestamppb"
|
||
)
|
||
|
||
// Комплект доступів живе годину. Якщо його не поновлювати, зонд через
|
||
// цю годину замовкає: Credentials() свідомо не віддає прострочені, і
|
||
// кожна перевірка падає з «немає креденшелів».
|
||
//
|
||
// Перевіряємо саме рішення, а не мережу: підсовуємо пачку, що от-от
|
||
// протухне, і чекаємо на запит поновлення.
|
||
func TestSessionAsksToRenewExpiringCredentials(t *testing.T) {
|
||
s := &Session{}
|
||
out := make(chan *npv1.ControlUp, 4)
|
||
ctx := context.Background()
|
||
|
||
// Свіжа пачка — просити нічого.
|
||
s.applyCredentials(&npv1.CredentialBundle{
|
||
ExpiresAt: timestamppb.New(time.Now().Add(time.Hour)),
|
||
})
|
||
s.maybeRenewCredentials(ctx, out)
|
||
if len(out) != 0 {
|
||
t.Fatal("попросили поновлення на свіжій пачці")
|
||
}
|
||
|
||
// Лишилось менше запасу — час просити.
|
||
s.applyCredentials(&npv1.CredentialBundle{
|
||
ExpiresAt: timestamppb.New(time.Now().Add(credRenewBefore / 2)),
|
||
})
|
||
s.maybeRenewCredentials(ctx, out)
|
||
if len(out) != 1 {
|
||
t.Fatalf("очікували один запит, отримали %d", len(out))
|
||
}
|
||
msg := <-out
|
||
req := msg.GetCredentialRequest()
|
||
if req == nil {
|
||
t.Fatal("надіслано не CredentialRequest")
|
||
}
|
||
if req.Reason != "expiring" {
|
||
t.Fatalf("причина %q", req.Reason)
|
||
}
|
||
|
||
// Повторний тік одразу після запиту не має додати другого.
|
||
s.maybeRenewCredentials(ctx, out)
|
||
if len(out) != 0 {
|
||
t.Fatal("запит продубльовано, антиспам не спрацював")
|
||
}
|
||
|
||
// Уже прострочена пачка — причина інша.
|
||
s.applyCredentials(&npv1.CredentialBundle{
|
||
ExpiresAt: timestamppb.New(time.Now().Add(-time.Minute)),
|
||
})
|
||
s.maybeRenewCredentials(ctx, out)
|
||
if len(out) != 1 {
|
||
t.Fatalf("очікували запит на простроченій пачці, отримали %d", len(out))
|
||
}
|
||
if r := (<-out).GetCredentialRequest(); r == nil || r.Reason != "expired" {
|
||
t.Fatalf("причина %v", r)
|
||
}
|
||
|
||
// Пачка без TTL — поновлювати нічого.
|
||
s.applyCredentials(&npv1.CredentialBundle{})
|
||
s.maybeRenewCredentials(ctx, out)
|
||
if len(out) != 0 {
|
||
t.Fatal("попросили поновлення для пачки без терміну")
|
||
}
|
||
}
|