From d3ad0f70134c8a8d4957ed68075b26b9909f1de7 Mon Sep 17 00:00:00 2001 From: Jason Staack Date: Sun, 22 Mar 2026 08:41:35 -0500 Subject: [PATCH] fix(poller): fall back to generic-snmp when device has no profile assigned SNMP devices added without a profile (e.g., via simplified add flow) were failing with "no SNMP profile assigned". Now falls back to the generic-snmp profile which collects standard MIB-II metrics. Co-Authored-By: Claude Opus 4.6 (1M context) --- poller/internal/snmp/collector.go | 17 ++++++++++++----- poller/internal/snmp/profiles.go | 7 +++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/poller/internal/snmp/collector.go b/poller/internal/snmp/collector.go index 595c441..07a3b7b 100644 --- a/poller/internal/snmp/collector.go +++ b/poller/internal/snmp/collector.go @@ -64,13 +64,20 @@ func NewSNMPCollector( func (c *SNMPCollector) Collect(ctx context.Context, dev store.Device, pub *bus.Publisher) error { startTime := time.Now() - // Step 1: Validate profile. - if dev.SNMPProfileID == nil { - return fmt.Errorf("device %s: no SNMP profile assigned (SNMPProfileID is nil)", dev.ID) + // Step 1: Resolve profile. Fall back to generic-snmp if none assigned. + profileID := "" + if dev.SNMPProfileID != nil { + profileID = *dev.SNMPProfileID + } else { + profileID = c.profiles.GetGenericID() + if profileID == "" { + return fmt.Errorf("device %s: no SNMP profile assigned and no generic-snmp fallback found", dev.ID) + } + slog.Debug("using generic-snmp fallback profile", "device_id", dev.ID) } - profile := c.profiles.Get(*dev.SNMPProfileID) + profile := c.profiles.Get(profileID) if profile == nil { - return fmt.Errorf("device %s: SNMP profile not found for ID %s", dev.ID, *dev.SNMPProfileID) + return fmt.Errorf("device %s: SNMP profile not found for ID %s", dev.ID, profileID) } // Step 2: Get credentials. diff --git a/poller/internal/snmp/profiles.go b/poller/internal/snmp/profiles.go index 0064f75..ddc725c 100644 --- a/poller/internal/snmp/profiles.go +++ b/poller/internal/snmp/profiles.go @@ -154,6 +154,13 @@ func (c *ProfileCache) Get(profileID string) *CompiledProfile { return c.profiles[profileID] } +// GetGenericID returns the profile ID of the generic-snmp fallback profile. +func (c *ProfileCache) GetGenericID() string { + c.mu.RLock() + defer c.mu.RUnlock() + return c.genericID +} + // MatchSysObjectID finds the best profile for a device's sysObjectID value // using longest-prefix matching. Returns the generic-snmp profile ID if // no vendor-specific prefix matches.