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) <noreply@anthropic.com>
This commit is contained in:
Jason Staack
2026-03-22 08:41:35 -05:00
parent f47438a5a5
commit d3ad0f7013
2 changed files with 19 additions and 5 deletions

View File

@@ -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.

View File

@@ -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.