Пристрій сам каже, що він таке, і шаблон чіпляється без натискань. Системна група знімається тією ж SNMP-сесією, що й обхід топології: три зайві PDU дешевші за окремий чек із власним розкладом. Збіг за префіксом на межі компонента: моделей у виробника тисячі, і повний збіг означав би рядок на кожну коробку. Довший префікс перемагає. Дванадцять вбудованих правил на основних виробників. Шаблони тільки додаються, ніколи не знімаються: автоматика знає модель пристрою, але не знає, чому цьому хосту дали ще один шаблон руками. DiscoveredDevice отримав device_id: зіставляти за адресою не можна — за одним NAT кілька хостів мають ту саму адресу опитування. Заразом дубль перевірки перестав давати «внутрішню помилку». Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
128 lines
5.5 KiB
Protocol Buffer
128 lines
5.5 KiB
Protocol Buffer
// =====================================================================
|
||
// NetPulse :: discovery.proto
|
||
// Автовиявлення сусідів (LLDP/CDP/ARP/FDB) та інвентаризація інтерфейсів.
|
||
//
|
||
// Агент НЕ вирішує, хто з ким з'єднаний. Він доповідає сире:
|
||
// "на порту X я бачу chassis-id Y, port-id Z". Резолвер на сервері
|
||
// зводить це в topo.links і виставляє confidence. Так автовиявлення
|
||
// лишається відтворюваним і не залежить від версії агента.
|
||
// =====================================================================
|
||
|
||
syntax = "proto3";
|
||
|
||
package netpulse.v1;
|
||
|
||
import "google/protobuf/timestamp.proto";
|
||
import "netpulse/v1/common.proto";
|
||
|
||
option go_package = "github.com/netpulse/netpulse/gen/go/netpulse/v1;netpulsev1";
|
||
|
||
// ---------------------------------------------------------------------
|
||
// Сусід, побачений з конкретного порту. → topo.neighbors
|
||
// ---------------------------------------------------------------------
|
||
|
||
message NeighborRecord {
|
||
// Пристрій, який доповідає (той, що ми опитали).
|
||
string device_id = 1;
|
||
// Локальний порт. Якщо агент ще не знає interface_id — заповнює
|
||
// local_if_index/local_port_name, і сервер резолвить сам.
|
||
string local_interface_id = 2;
|
||
int64 local_if_index = 3;
|
||
string local_port_name = 4;
|
||
|
||
DiscoveryProto proto = 5;
|
||
|
||
// Те, що видно з іншого боку. Порожні поля — норма: CDP не дає
|
||
// chassis_id у форматі LLDP, ARP не дає port_id взагалі.
|
||
string remote_chassis_id = 6;
|
||
string remote_system_name = 7;
|
||
string remote_port_id = 8;
|
||
string remote_port_descr = 9;
|
||
string remote_mgmt_ip = 10;
|
||
string remote_mac = 11;
|
||
string remote_platform = 12;
|
||
repeated string remote_capabilities = 13; // bridge, router, wlan-ap
|
||
|
||
google.protobuf.Timestamp seen_at = 14;
|
||
// Сирий запис як його віддав пристрій — для розбору спірних випадків.
|
||
bytes raw_json = 15;
|
||
}
|
||
|
||
// ---------------------------------------------------------------------
|
||
// Інвентаризація інтерфейсів. → inv.interfaces (upsert за ifIndex)
|
||
// Йде разом із discovery, бо обидва беруться з одного SNMP-walk.
|
||
// ---------------------------------------------------------------------
|
||
|
||
message InterfaceRecord {
|
||
string device_id = 1;
|
||
int64 if_index = 2;
|
||
string name = 3;
|
||
string alias = 4;
|
||
string mac = 5;
|
||
uint32 mtu = 6;
|
||
string type = 7; // ethernetCsmacd, ieee8023adLag, l3ipvlan
|
||
uint64 speed_bps = 8;
|
||
string duplex = 9;
|
||
string admin_status = 10; // up | down | testing | unknown
|
||
string oper_status = 11;
|
||
int64 parent_if_index = 12; // для членів LAG
|
||
repeated string ip_addresses = 13; // CIDR: 10.0.0.1/24
|
||
}
|
||
|
||
// ---------------------------------------------------------------------
|
||
// Знайдений, але ще не заведений пристрій (сканування підмережі).
|
||
// Сервер вирішує, чи створювати його в inv.devices — це впирається
|
||
// в ліміт тарифу, тому рішення не може бути на агенті.
|
||
// ---------------------------------------------------------------------
|
||
|
||
message DiscoveredDevice {
|
||
string address = 1;
|
||
string hostname = 2;
|
||
string mac = 3;
|
||
string sys_name = 4;
|
||
string sys_descr = 5;
|
||
string sys_object_id = 6;
|
||
string vendor = 7;
|
||
string model = 8;
|
||
// Які транспорти відповіли під час сканування.
|
||
repeated Transport reachable_via = 9;
|
||
// Здогад агента про тип пристрою — сервер може перевизначити.
|
||
string guessed_kind = 10;
|
||
google.protobuf.Timestamp seen_at = 11;
|
||
// Заповнене, якщо це не знахідка сканування, а системна інформація
|
||
// про вже відомий хост. Адреси для зіставлення мало: за одним NAT
|
||
// цілком може стояти кілька хостів з тією самою адресою опитування.
|
||
string device_id = 12;
|
||
}
|
||
|
||
// ---------------------------------------------------------------------
|
||
// Звіт про запуск автовиявлення → topo.discovery_runs
|
||
// ---------------------------------------------------------------------
|
||
|
||
message DiscoveryReport {
|
||
string agent_id = 1;
|
||
// Порожній, якщо це фонове періодичне виявлення, а не запуск із UI.
|
||
string run_id = 2;
|
||
|
||
repeated NeighborRecord neighbors = 3;
|
||
repeated InterfaceRecord interfaces = 4;
|
||
repeated DiscoveredDevice devices = 5;
|
||
|
||
// Звіт розбитий на частини: сервер має чекати final = true,
|
||
// перш ніж закривати run і чистити застарілих сусідів.
|
||
bool final = 6;
|
||
uint32 part = 7;
|
||
|
||
google.protobuf.Timestamp started_at = 8;
|
||
google.protobuf.Timestamp finished_at = 9;
|
||
repeated Error errors = 10;
|
||
}
|
||
|
||
message DiscoveryAck {
|
||
bool accepted = 1;
|
||
// Скільки записів сервер зміг зіставити з інвентарем.
|
||
uint32 neighbors_resolved = 2;
|
||
uint32 links_created = 3;
|
||
uint32 devices_created = 4;
|
||
Error error = 5;
|
||
}
|