From da83fb1a8579fa5a19e3580126c14b9bf914b39e Mon Sep 17 00:00:00 2001 From: Daniel Lepage Date: Fri, 13 Dec 2024 16:56:25 -0500 Subject: [PATCH 1/5] Have config generate a Profile The .Metrics, .MetricTags, etc. fields on CheckConfig are storing all the same attributes as a profile; it is easier if we just create a Profile from the CheckConfig and pass that around. This also removes the caching of those fields from the CheckConfig; a later commit caches this generated profile in the DeviceCheck. --- .../snmp/internal/checkconfig/buildprofile.go | 74 +++ .../internal/checkconfig/buildprofile_test.go | 226 ++++++++ .../snmp/internal/checkconfig/config.go | 165 +----- .../snmp/internal/checkconfig/config_oid.go | 50 -- .../internal/checkconfig/config_oid_test.go | 40 -- .../snmp/internal/checkconfig/config_test.go | 541 +++++------------- 6 files changed, 452 insertions(+), 644 deletions(-) create mode 100644 pkg/collector/corechecks/snmp/internal/checkconfig/buildprofile.go create mode 100644 pkg/collector/corechecks/snmp/internal/checkconfig/buildprofile_test.go delete mode 100644 pkg/collector/corechecks/snmp/internal/checkconfig/config_oid.go delete mode 100644 pkg/collector/corechecks/snmp/internal/checkconfig/config_oid_test.go diff --git a/pkg/collector/corechecks/snmp/internal/checkconfig/buildprofile.go b/pkg/collector/corechecks/snmp/internal/checkconfig/buildprofile.go new file mode 100644 index 0000000000000..3ee5090a865b7 --- /dev/null +++ b/pkg/collector/corechecks/snmp/internal/checkconfig/buildprofile.go @@ -0,0 +1,74 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2016-present Datadog, Inc. + +package checkconfig + +import ( + "fmt" + "github.com/DataDog/datadog-agent/pkg/networkdevice/profile/profiledefinition" + "github.com/DataDog/datadog-agent/pkg/util/log" + "slices" +) + +// BuildProfile builds the fetchable profile for this config. +// +// If ProfileName == ProfileNameInline, then the result just contains the inline +// metrics and tags from the initconfig. This is also true if ProfileName == +// ProfileNameAuto and sysObjectID == "" (this is useful when you want basic +// metadata for a device that you can't yet get the sysObjectID from). +// +// Otherwise, the result will be a copy of the profile from ProfileProvider that +// matches this config, either by sysObjectID if ProfileName == ProfileNameAuto +// or by ProfileName directly otherwise. +// +// The error will be non-nil if ProfileProvider doesn't know ProfileName, or if +// ProfileName is ProfileNameAuto and ProfileProvider finds no match for +// sysObjectID. In this case the returned profile will still be non-nil, and +// will be the same as what you'd get for an inline profile. +func (c *CheckConfig) BuildProfile(sysObjectID string) (profiledefinition.ProfileDefinition, error) { + var parentProfile *profiledefinition.ProfileDefinition + var profileErr error + + switch c.ProfileName { + case ProfileNameInline: // inline profile -> no parent + parentProfile = nil + case ProfileNameAuto: // determine based on sysObjectID + // empty sysObjectID happens when we need the profile but couldn't connect to the device. + if sysObjectID != "" { + if profileConfig, err := c.ProfileProvider.GetProfileForSysObjectID(sysObjectID); err != nil { + profileErr = fmt.Errorf("failed to get profile for sysObjectID %q: %v", sysObjectID, err) + } else { + parentProfile = &profileConfig.Definition + log.Debugf("detected profile %q for sysobjectid %q", parentProfile.Name, sysObjectID) + } + } + default: + if profile := c.ProfileProvider.GetProfile(c.ProfileName); profile == nil { + profileErr = fmt.Errorf("unknown profile %q", c.ProfileName) + } else { + parentProfile = &profile.Definition + } + } + + profile := *profiledefinition.NewProfileDefinition() + profile.Metrics = slices.Clone(c.RequestedMetrics) + profile.MetricTags = slices.Clone(c.RequestedMetricTags) + if parentProfile != nil { + profile.Name = parentProfile.Name + profile.Version = parentProfile.Version + profile.StaticTags = append(profile.StaticTags, "snmp_profile:"+parentProfile.Name) + vendor := parentProfile.GetVendor() + if vendor != "" { + profile.StaticTags = append(profile.StaticTags, "device_vendor:"+vendor) + } + profile.StaticTags = append(profile.StaticTags, parentProfile.StaticTags...) + profile.Metadata = parentProfile.Metadata + profile.Metrics = append(profile.Metrics, parentProfile.Metrics...) + profile.MetricTags = append(profile.MetricTags, parentProfile.MetricTags...) + } + profile.Metadata = updateMetadataDefinitionWithDefaults(profile.Metadata, c.CollectTopology) + + return profile, profileErr +} diff --git a/pkg/collector/corechecks/snmp/internal/checkconfig/buildprofile_test.go b/pkg/collector/corechecks/snmp/internal/checkconfig/buildprofile_test.go new file mode 100644 index 0000000000000..5c1992f848e81 --- /dev/null +++ b/pkg/collector/corechecks/snmp/internal/checkconfig/buildprofile_test.go @@ -0,0 +1,226 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2024-present Datadog, Inc. + +package checkconfig + +import ( + "github.com/DataDog/datadog-agent/pkg/collector/corechecks/snmp/internal/profile" + "github.com/DataDog/datadog-agent/pkg/networkdevice/profile/profiledefinition" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "testing" +) + +func TestBuildProfile(t *testing.T) { + metrics := []profiledefinition.MetricsConfig{ + {Symbol: profiledefinition.SymbolConfig{OID: "1.2.3.4.5", Name: "someMetric"}}, + { + Symbols: []profiledefinition.SymbolConfig{ + { + OID: "1.2.3.4.6", + Name: "abc", + }, + }, + MetricTags: profiledefinition.MetricTagConfigList{ + profiledefinition.MetricTagConfig{ + Symbol: profiledefinition.SymbolConfigCompat{ + OID: "1.2.3.4.7", + }, + }, + }, + }, + } + profile1 := profiledefinition.ProfileDefinition{ + Name: "profile1", + Version: 12, + Metrics: metrics, + MetricTags: []profiledefinition.MetricTagConfig{ + {Tag: "location", Symbol: profiledefinition.SymbolConfigCompat{OID: "1.3.6.1.2.1.1.6.0", Name: "sysLocation"}}, + }, + Metadata: profiledefinition.MetadataConfig{ + "device": { + Fields: map[string]profiledefinition.MetadataField{ + "vendor": { + Value: "a-vendor", + }, + "description": { + Symbol: profiledefinition.SymbolConfig{ + OID: "1.3.6.1.2.1.1.99.3.0", + Name: "sysDescr", + }, + }, + "name": { + Symbols: []profiledefinition.SymbolConfig{ + { + OID: "1.3.6.1.2.1.1.99.1.0", + Name: "symbol1", + }, + { + OID: "1.3.6.1.2.1.1.99.2.0", + Name: "symbol2", + }, + }, + }, + }, + }, + "interface": { + Fields: map[string]profiledefinition.MetadataField{ + "oper_status": { + Symbol: profiledefinition.SymbolConfig{ + OID: "1.3.6.1.2.1.2.2.1.99", + Name: "someIfSymbol", + }, + }, + }, + IDTags: profiledefinition.MetricTagConfigList{ + { + Tag: "interface", + Symbol: profiledefinition.SymbolConfigCompat{ + OID: "1.3.6.1.2.1.31.1.1.1.1", + Name: "ifName", + }, + }, + }, + }, + }, + SysObjectIDs: profiledefinition.StringArray{"1.1.1.*"}, + } + + mergedMetadata := make(profiledefinition.MetadataConfig) + mergeMetadata(mergedMetadata, profile1.Metadata) + mergedMetadata["ip_addresses"] = LegacyMetadataConfig["ip_addresses"] + + mockProfiles := profile.StaticProvider(profile.ProfileConfigMap{ + "profile1": profile.ProfileConfig{ + Definition: profile1, + }, + }) + + type testCase struct { + name string + config *CheckConfig + sysObjectID string + expected profiledefinition.ProfileDefinition + expectedError string + } + for _, tc := range []testCase{ + { + name: "inline", + config: &CheckConfig{ + IPAddress: "1.2.3.4", + RequestedMetrics: metrics, + RequestedMetricTags: []profiledefinition.MetricTagConfig{ + {Tag: "location", Symbol: profiledefinition.SymbolConfigCompat{OID: "1.3.6.1.2.1.1.6.0", Name: "sysLocation"}}, + }, + ProfileName: ProfileNameInline, + }, + expected: profiledefinition.ProfileDefinition{ + Metrics: metrics, + MetricTags: []profiledefinition.MetricTagConfig{ + {Tag: "location", Symbol: profiledefinition.SymbolConfigCompat{OID: "1.3.6.1.2.1.1.6.0", Name: "sysLocation"}}, + }, + Metadata: LegacyMetadataConfig, + }, + }, { + name: "static", + config: &CheckConfig{ + IPAddress: "1.2.3.4", + ProfileProvider: mockProfiles, + ProfileName: "profile1", + }, + expected: profiledefinition.ProfileDefinition{ + Name: "profile1", + Version: 12, + Metrics: metrics, + MetricTags: []profiledefinition.MetricTagConfig{ + {Tag: "location", Symbol: profiledefinition.SymbolConfigCompat{OID: "1.3.6.1.2.1.1.6.0", Name: "sysLocation"}}, + }, + StaticTags: []string{"snmp_profile:profile1", "device_vendor:a-vendor"}, + Metadata: mergedMetadata, + }, + }, { + name: "dynamic", + config: &CheckConfig{ + IPAddress: "1.2.3.4", + ProfileProvider: mockProfiles, + ProfileName: ProfileNameAuto, + }, + sysObjectID: "1.1.1.1", + expected: profiledefinition.ProfileDefinition{ + Name: "profile1", + Version: 12, + Metrics: metrics, + MetricTags: []profiledefinition.MetricTagConfig{ + {Tag: "location", Symbol: profiledefinition.SymbolConfigCompat{OID: "1.3.6.1.2.1.1.6.0", Name: "sysLocation"}}, + }, + StaticTags: []string{"snmp_profile:profile1", "device_vendor:a-vendor"}, + Metadata: mergedMetadata, + }, + }, { + name: "static with requested metrics", + config: &CheckConfig{ + IPAddress: "1.2.3.4", + ProfileProvider: mockProfiles, + CollectDeviceMetadata: true, + CollectTopology: false, + ProfileName: "profile1", + RequestedMetrics: []profiledefinition.MetricsConfig{ + {Symbol: profiledefinition.SymbolConfig{OID: "3.1", Name: "global-metric"}}}, + RequestedMetricTags: []profiledefinition.MetricTagConfig{ + {Tag: "global-tag", Symbol: profiledefinition.SymbolConfigCompat{OID: "3.2", Name: "globalSymbol"}}, + }, + }, + expected: profiledefinition.ProfileDefinition{ + Name: "profile1", + Version: 12, + Metrics: append([]profiledefinition.MetricsConfig{ + {Symbol: profiledefinition.SymbolConfig{OID: "3.1", Name: "global-metric"}}}, + metrics...), + MetricTags: []profiledefinition.MetricTagConfig{ + {Tag: "global-tag", Symbol: profiledefinition.SymbolConfigCompat{OID: "3.2", Name: "globalSymbol"}}, + {Tag: "location", Symbol: profiledefinition.SymbolConfigCompat{OID: "1.3.6.1.2.1.1.6.0", Name: "sysLocation"}}, + }, + Metadata: mergedMetadata, + StaticTags: []string{"snmp_profile:profile1", "device_vendor:a-vendor"}, + }, + }, { + name: "static unknown", + config: &CheckConfig{ + IPAddress: "1.2.3.4", + ProfileProvider: mockProfiles, + ProfileName: "f5", + }, + expectedError: "unknown profile \"f5\"", + }, { + name: "dynamic unknown", + config: &CheckConfig{ + IPAddress: "1.2.3.4", + ProfileProvider: mockProfiles, + ProfileName: ProfileNameAuto, + }, + sysObjectID: "3.3.3.3", + expectedError: "failed to get profile for sysObjectID \"3.3.3.3\": no profiles found for sysObjectID \"3." + + "3.3.3\"", + }, + } { + t.Run(tc.name, func(t *testing.T) { + profile, err := tc.config.BuildProfile(tc.sysObjectID) + if tc.expectedError != "" { + assert.EqualError(t, err, tc.expectedError) + } else { + require.NoError(t, err) + if !assert.Equal(t, tc.expected, profile) { + for k, v := range tc.expected.Metadata["device"].Fields { + t.Log(k, v) + } + t.Log("===") + for k, v := range profile.Metadata["device"].Fields { + t.Log(k, v) + } + } + } + }) + } +} diff --git a/pkg/collector/corechecks/snmp/internal/checkconfig/config.go b/pkg/collector/corechecks/snmp/internal/checkconfig/config.go index 688b2cd9350e2..d027fc50cbf54 100644 --- a/pkg/collector/corechecks/snmp/internal/checkconfig/config.go +++ b/pkg/collector/corechecks/snmp/internal/checkconfig/config.go @@ -8,7 +8,6 @@ package checkconfig import ( "context" - "encoding/json" "fmt" "hash/fnv" "net" @@ -72,6 +71,11 @@ const DefaultPingTimeout = 3 * time.Second // DefaultPingInterval is the default time to wait between sending ping packets const DefaultPingInterval = 10 * time.Millisecond +// config.ProfileName will be set to ProfileNameAuto if the profile is auto-detected, +// and ProfileNameInline if metrics were provided in the initial config (so that no profile is used) +const ProfileNameAuto = "" +const ProfileNameInline = "" + var uptimeMetricConfig = profiledefinition.MetricsConfig{Symbol: profiledefinition.SymbolConfig{OID: "1.3.6.1.2.1.1.3.0", Name: "sysUpTimeInstance"}} // DeviceDigest is the digest of a minimal config used for autodiscovery @@ -164,20 +168,13 @@ type CheckConfig struct { PrivProtocol string PrivKey string ContextName string - OidConfig OidConfig // RequestedMetrics are the metrics explicitly requested by config. RequestedMetrics []profiledefinition.MetricsConfig // RequestedMetricTags are the tags explicitly requested by config. - RequestedMetricTags []profiledefinition.MetricTagConfig - // Metrics combines RequestedMetrics with profile metrics. - Metrics []profiledefinition.MetricsConfig - Metadata profiledefinition.MetadataConfig - // MetricTags combines RequestedMetricTags with profile metric tags. - MetricTags []profiledefinition.MetricTagConfig + RequestedMetricTags []profiledefinition.MetricTagConfig OidBatchSize int BulkMaxRepetitions uint32 ProfileProvider profile.Provider - ProfileTags []string ProfileName string ExtraTags []string InstanceTags []string @@ -188,7 +185,6 @@ type CheckConfig struct { DeviceIDTags []string ResolvedSubnetName string Namespace string - AutodetectProfile bool MinCollectionInterval time.Duration Network string @@ -203,61 +199,6 @@ type CheckConfig struct { PingConfig pinger.Config } -// SetProfile refreshes config based on profile -func (c *CheckConfig) SetProfile(profileName string) error { - profileConf := c.ProfileProvider.GetProfile(profileName) - if profileConf == nil { - return fmt.Errorf("unknown profile `%s`", profileName) - } - log.Debugf("Refreshing with profile `%s`", profileName) - c.ProfileName = profileName - - if log.ShouldLog(log.DebugLvl) { - profileDefJSON, _ := json.Marshal(profileConf.Definition) - log.Debugf("Profile content `%s`: %s", profileName, string(profileDefJSON)) - } - c.RebuildMetadataMetricsAndTags() - return nil -} - -// GetProfileDef returns the autodetected profile definition if there is one, -// the active profile if it exists, or nil if neither is true. -func (c *CheckConfig) GetProfileDef() *profiledefinition.ProfileDefinition { - if c.ProfileName != "" { - profile := c.ProfileProvider.GetProfile(c.ProfileName) - if profile != nil { - return &profile.Definition - } - log.Warnf("profile `%s` not found", c.ProfileName) - } - return nil -} - -// RebuildMetadataMetricsAndTags rebuilds c.Metrics, c.Metadata, c.MetricTags, -// and c.OidConfig by merging data from requested metrics/tags and the current -// profile. -func (c *CheckConfig) RebuildMetadataMetricsAndTags() { - c.Metrics = c.RequestedMetrics - c.MetricTags = c.RequestedMetricTags - c.ProfileTags = nil - profileDef := c.GetProfileDef() - if profileDef != nil { - c.ProfileTags = append(c.ProfileTags, "snmp_profile:"+c.ProfileName) - if profileDef.Device.Vendor != "" { - c.ProfileTags = append(c.ProfileTags, "device_vendor:"+profileDef.Device.Vendor) - } - c.ProfileTags = append(c.ProfileTags, profileDef.StaticTags...) - c.Metadata = updateMetadataDefinitionWithDefaults(profileDef.Metadata, c.CollectTopology) - c.Metrics = append(c.Metrics, profileDef.Metrics...) - c.MetricTags = append(c.MetricTags, profileDef.MetricTags...) - } else { - c.Metadata = updateMetadataDefinitionWithDefaults(nil, c.CollectTopology) - } - c.OidConfig.clean() - c.OidConfig.addScalarOids(c.parseScalarOids(c.Metrics, c.MetricTags, c.Metadata)) - c.OidConfig.addColumnOids(c.parseColumnOids(c.Metrics, c.Metadata)) -} - // UpdateDeviceIDAndTags updates DeviceID and DeviceIDTags func (c *CheckConfig) UpdateDeviceIDAndTags() { c.DeviceIDTags = coreutil.SortUniqInPlace(c.getDeviceIDTags()) @@ -310,8 +251,7 @@ func (c *CheckConfig) getDeviceIDTags() []string { // ToString used for logging CheckConfig without sensitive information func (c *CheckConfig) ToString() string { return fmt.Sprintf("CheckConfig: IPAddress=`%s`, Port=`%d`, SnmpVersion=`%s`, Timeout=`%d`, Retries=`%d`, "+ - "User=`%s`, AuthProtocol=`%s`, PrivProtocol=`%s`, ContextName=`%s`, OidConfig=`%#v`, "+ - "OidBatchSize=`%d`, ProfileTags=`%#v`", + "User=`%s`, AuthProtocol=`%s`, PrivProtocol=`%s`, ContextName=`%s`, OidBatchSize=`%d`, ProfileName=`%s`", c.IPAddress, c.Port, c.SnmpVersion, @@ -321,9 +261,8 @@ func (c *CheckConfig) ToString() string { c.AuthProtocol, c.PrivProtocol, c.ContextName, - c.OidConfig, c.OidBatchSize, - c.ProfileTags, + c.ProfileName, ) } @@ -499,11 +438,13 @@ func NewCheckConfig(rawInstance integration.Data, rawInitConfig integration.Data c.ProfileProvider = profiles // profile configs - profileName := instance.Profile - if profileName != "" || len(instance.Metrics) > 0 { - c.AutodetectProfile = false - } else { - c.AutodetectProfile = true + c.ProfileName = instance.Profile + if c.ProfileName == "" { + if len(instance.Metrics) > 0 { + c.ProfileName = ProfileNameInline + } else { + c.ProfileName = ProfileNameAuto + } } c.InstanceTags = instance.Tags @@ -525,15 +466,6 @@ func NewCheckConfig(rawInstance integration.Data, rawInitConfig integration.Data return nil, fmt.Errorf("validation errors: %s", strings.Join(errors, "\n")) } - if profileName != "" { - err = c.SetProfile(profileName) - if err != nil { - return nil, fmt.Errorf("failed to refresh with profile `%s`: %s", profileName, err) - } - } else { - c.RebuildMetadataMetricsAndTags() - } - // Ping configuration if instance.PingConfig.Enabled != nil { c.PingEnabled = bool(*instance.PingConfig.Enabled) @@ -645,24 +577,14 @@ func (c *CheckConfig) Copy() *CheckConfig { newConfig.PrivKey = c.PrivKey newConfig.ContextName = c.ContextName newConfig.ContextName = c.ContextName - newConfig.OidConfig = c.OidConfig newConfig.RequestedMetrics = make([]profiledefinition.MetricsConfig, len(c.RequestedMetrics)) copy(newConfig.RequestedMetrics, c.RequestedMetrics) - newConfig.Metrics = make([]profiledefinition.MetricsConfig, len(c.Metrics)) - copy(newConfig.Metrics, c.Metrics) - - // Metadata: shallow copy is enough since metadata is not modified. - // However, it might be fully replaced, see CheckConfig.SetProfile - newConfig.Metadata = c.Metadata newConfig.RequestedMetricTags = make([]profiledefinition.MetricTagConfig, len(c.RequestedMetricTags)) copy(newConfig.RequestedMetricTags, c.RequestedMetricTags) - newConfig.MetricTags = make([]profiledefinition.MetricTagConfig, len(c.MetricTags)) - copy(newConfig.MetricTags, c.MetricTags) newConfig.OidBatchSize = c.OidBatchSize newConfig.BulkMaxRepetitions = c.BulkMaxRepetitions newConfig.ProfileProvider = c.ProfileProvider - newConfig.ProfileTags = netutils.CopyStrings(c.ProfileTags) newConfig.ProfileName = c.ProfileName newConfig.ExtraTags = netutils.CopyStrings(c.ExtraTags) newConfig.InstanceTags = netutils.CopyStrings(c.InstanceTags) @@ -674,7 +596,6 @@ func (c *CheckConfig) Copy() *CheckConfig { newConfig.DeviceIDTags = netutils.CopyStrings(c.DeviceIDTags) newConfig.ResolvedSubnetName = c.ResolvedSubnetName newConfig.Namespace = c.Namespace - newConfig.AutodetectProfile = c.AutodetectProfile newConfig.MinCollectionInterval = c.MinCollectionInterval newConfig.InterfaceConfigs = c.InterfaceConfigs @@ -700,62 +621,6 @@ func (c *CheckConfig) IsDiscovery() bool { return c.Network != "" } -func (c *CheckConfig) parseScalarOids(metrics []profiledefinition.MetricsConfig, metricTags []profiledefinition.MetricTagConfig, metadataConfigs profiledefinition.MetadataConfig) []string { - var oids []string - for _, metric := range metrics { - oids = append(oids, metric.Symbol.OID) - } - for _, metricTag := range metricTags { - oids = append(oids, metricTag.Symbol.OID) - } - if c.CollectDeviceMetadata { - for resource, metadataConfig := range metadataConfigs { - if !profiledefinition.IsMetadataResourceWithScalarOids(resource) { - continue - } - for _, field := range metadataConfig.Fields { - oids = append(oids, field.Symbol.OID) - for _, symbol := range field.Symbols { - oids = append(oids, symbol.OID) - } - } - // we don't support tags for now for resource (e.g. device) based on scalar OIDs - // profile root level `metric_tags` (tags used for both metadata, metrics, service checks) - // can be used instead - } - } - return oids -} - -func (c *CheckConfig) parseColumnOids(metrics []profiledefinition.MetricsConfig, metadataConfigs profiledefinition.MetadataConfig) []string { - var oids []string - for _, metric := range metrics { - for _, symbol := range metric.Symbols { - oids = append(oids, symbol.OID) - } - for _, metricTag := range metric.MetricTags { - oids = append(oids, metricTag.Symbol.OID) - } - } - if c.CollectDeviceMetadata { - for resource, metadataConfig := range metadataConfigs { - if profiledefinition.IsMetadataResourceWithScalarOids(resource) { - continue - } - for _, field := range metadataConfig.Fields { - oids = append(oids, field.Symbol.OID) - for _, symbol := range field.Symbols { - oids = append(oids, symbol.OID) - } - } - for _, tagConfig := range metadataConfig.IDTags { - oids = append(oids, tagConfig.Symbol.OID) - } - } - } - return oids -} - func getSubnetFromTags(tags []string) (string, error) { for _, tag := range tags { // `autodiscovery_subnet` is set as tags in AD Template diff --git a/pkg/collector/corechecks/snmp/internal/checkconfig/config_oid.go b/pkg/collector/corechecks/snmp/internal/checkconfig/config_oid.go deleted file mode 100644 index d6992a3d87f79..0000000000000 --- a/pkg/collector/corechecks/snmp/internal/checkconfig/config_oid.go +++ /dev/null @@ -1,50 +0,0 @@ -// Unless explicitly stated otherwise all files in this repository are licensed -// under the Apache License Version 2.0. -// This product includes software developed at Datadog (https://www.datadoghq.com/). -// Copyright 2016-present Datadog, Inc. - -package checkconfig - -import "sort" - -// OidConfig holds configs for OIDs to fetch -type OidConfig struct { - // ScalarOids are all scalar oids to fetch - ScalarOids []string - // ColumnOids are all column oids to fetch - ColumnOids []string -} - -func (oc *OidConfig) addScalarOids(oidsToAdd []string) { - oc.ScalarOids = oc.addOidsIfNotPresent(oc.ScalarOids, oidsToAdd) -} - -func (oc *OidConfig) addColumnOids(oidsToAdd []string) { - oc.ColumnOids = oc.addOidsIfNotPresent(oc.ColumnOids, oidsToAdd) -} - -func (oc *OidConfig) addOidsIfNotPresent(configOids []string, oidsToAdd []string) []string { - for _, oidToAdd := range oidsToAdd { - if oidToAdd == "" { - continue - } - isAlreadyPresent := false - for _, oid := range configOids { - if oid == oidToAdd { - isAlreadyPresent = true - break - } - } - if isAlreadyPresent { - continue - } - configOids = append(configOids, oidToAdd) - } - sort.Strings(configOids) - return configOids -} - -func (oc *OidConfig) clean() { - oc.ScalarOids = nil - oc.ColumnOids = nil -} diff --git a/pkg/collector/corechecks/snmp/internal/checkconfig/config_oid_test.go b/pkg/collector/corechecks/snmp/internal/checkconfig/config_oid_test.go deleted file mode 100644 index 6fae3b75ce024..0000000000000 --- a/pkg/collector/corechecks/snmp/internal/checkconfig/config_oid_test.go +++ /dev/null @@ -1,40 +0,0 @@ -// Unless explicitly stated otherwise all files in this repository are licensed -// under the Apache License Version 2.0. -// This product includes software developed at Datadog (https://www.datadoghq.com/). -// Copyright 2016-present Datadog, Inc. - -package checkconfig - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_oidConfig_addScalarOids(t *testing.T) { - conf := OidConfig{} - - assert.ElementsMatch(t, []string{}, conf.ScalarOids) - - conf.addScalarOids([]string{"1.1"}) - conf.addScalarOids([]string{"1.1"}) - conf.addScalarOids([]string{"1.2"}) - conf.addScalarOids([]string{"1.3"}) - conf.addScalarOids([]string{"1.0"}) - conf.addScalarOids([]string{""}) - assert.ElementsMatch(t, []string{"1.1", "1.2", "1.3", "1.0"}, conf.ScalarOids) -} - -func Test_oidConfig_addColumnOids(t *testing.T) { - conf := OidConfig{} - - assert.ElementsMatch(t, []string{}, conf.ColumnOids) - - conf.addColumnOids([]string{"1.1"}) - conf.addColumnOids([]string{"1.1"}) - conf.addColumnOids([]string{"1.2"}) - conf.addColumnOids([]string{"1.3"}) - conf.addColumnOids([]string{"1.0"}) - conf.addColumnOids([]string{""}) - assert.ElementsMatch(t, []string{"1.1", "1.2", "1.3", "1.0"}, conf.ColumnOids) -} diff --git a/pkg/collector/corechecks/snmp/internal/checkconfig/config_test.go b/pkg/collector/corechecks/snmp/internal/checkconfig/config_test.go index ef9b8628da93a..34653446818ec 100644 --- a/pkg/collector/corechecks/snmp/internal/checkconfig/config_test.go +++ b/pkg/collector/corechecks/snmp/internal/checkconfig/config_test.go @@ -6,6 +6,7 @@ package checkconfig import ( + "github.com/stretchr/testify/require" "regexp" "testing" "time" @@ -155,106 +156,112 @@ bulk_max_repetitions: 20 assert.Equal(t, "my-privKey", config.PrivKey) assert.Equal(t, "my-contextName", config.ContextName) assert.Equal(t, []string{"device_namespace:default", "snmp_device:1.2.3.4", "device_ip:1.2.3.4", "device_id:default:1.2.3.4"}, config.GetStaticTags()) - expectedMetrics := []profiledefinition.MetricsConfig{ - {Symbol: profiledefinition.SymbolConfig{OID: "1.3.6.1.2.1.2.1", Name: "ifNumber"}}, - {Symbol: profiledefinition.SymbolConfig{OID: "1.3.6.1.2.1.2.2", Name: "ifNumber2"}, MetricTags: profiledefinition.MetricTagConfigList{ - {SymbolTag: "mytag1"}, - {SymbolTag: "mytag2"}, - }}, - {Symbol: profiledefinition.SymbolConfig{OID: "1.3.6.1.4.1.318.1.1.1.11.1.1.0", Name: "upsBasicStateOutputState", ScaleFactor: 10}, MetricType: profiledefinition.ProfileMetricTypeFlagStream, Options: profiledefinition.MetricsConfigOption{Placement: 5, MetricSuffix: "ReplaceBattery"}}, - { - Table: profiledefinition.SymbolConfig{ - OID: "1.3.6.1.2.1.2.2", - Name: "ifTable", - }, - Symbols: []profiledefinition.SymbolConfig{ - // ifInErrors defined in instance config with a different set of metric tags from the one defined - // in the imported profile - {OID: "1.3.6.1.2.1.2.2.1.14", Name: "ifInErrors"}, - {OID: "1.3.6.1.2.1.2.2.1.20", Name: "ifOutErrors", ScaleFactor: 3}, - }, - MetricTags: []profiledefinition.MetricTagConfig{ - {Tag: "if_index", Index: 1}, - {Tag: "if_desc", Symbol: profiledefinition.SymbolConfigCompat{OID: "1.3.6.1.2.1.2.2.1.2", Name: "ifDescr"}, - IndexTransform: []profiledefinition.MetricIndexTransform{ - { - Start: 1, - End: 3, - }, - { - Start: 4, - End: 6, - }, - }, + assert.True(t, config.ProfileProvider.HasProfile("f5-big-ip")) + assert.Equal(t, "default:1.2.3.4", config.DeviceID) + assert.Equal(t, []string{"device_namespace:default", "snmp_device:1.2.3.4"}, config.DeviceIDTags) + assert.Equal(t, "127.0.0.0/30", config.ResolvedSubnetName) + assert.Equal(t, "f5-big-ip", config.ProfileName) + + t.Run("BuildProfile", func(t *testing.T) { + expectedMetrics := []profiledefinition.MetricsConfig{ + {Symbol: profiledefinition.SymbolConfig{OID: "1.3.6.1.2.1.2.1", Name: "ifNumber"}}, + {Symbol: profiledefinition.SymbolConfig{OID: "1.3.6.1.2.1.2.2", Name: "ifNumber2"}, MetricTags: profiledefinition.MetricTagConfigList{ + {SymbolTag: "mytag1"}, + {SymbolTag: "mytag2"}, + }}, + {Symbol: profiledefinition.SymbolConfig{OID: "1.3.6.1.4.1.318.1.1.1.11.1.1.0", Name: "upsBasicStateOutputState", ScaleFactor: 10}, MetricType: profiledefinition.ProfileMetricTypeFlagStream, Options: profiledefinition.MetricsConfigOption{Placement: 5, MetricSuffix: "ReplaceBattery"}}, + { + Table: profiledefinition.SymbolConfig{ + OID: "1.3.6.1.2.1.2.2", + Name: "ifTable", }, - {Tag: "ipversion", Index: 1, Mapping: map[string]string{ - "0": "unknown", - "1": "ipv4", - "2": "ipv6", - "3": "ipv4z", - "4": "ipv6z", - "16": "dns", - }}, - {Tag: "if_type", - Symbol: profiledefinition.SymbolConfigCompat{OID: "1.3.6.1.2.1.2.2.1.3", Name: "ifType"}, - Mapping: map[string]string{ - "1": "other", - "2": "regular1822", - "3": "hdh1822", - "4": "ddn-x25", - "29": "ultra", - }}, - { - Symbol: profiledefinition.SymbolConfigCompat{ - Name: "cpiPduName", - OID: "1.2.3.4.8.1.2", + Symbols: []profiledefinition.SymbolConfig{ + // ifInErrors defined in instance config with a different set of metric tags from the one defined + // in the imported profile + {OID: "1.3.6.1.2.1.2.2.1.14", Name: "ifInErrors"}, + {OID: "1.3.6.1.2.1.2.2.1.20", Name: "ifOutErrors", ScaleFactor: 3}, + }, + MetricTags: []profiledefinition.MetricTagConfig{ + {Tag: "if_index", Index: 1}, + {Tag: "if_desc", Symbol: profiledefinition.SymbolConfigCompat{OID: "1.3.6.1.2.1.2.2.1.2", Name: "ifDescr"}, + IndexTransform: []profiledefinition.MetricIndexTransform{ + { + Start: 1, + End: 3, + }, + { + Start: 4, + End: 6, + }, + }, }, - Match: "(\\w)(\\w+)", - Pattern: regexp.MustCompile(`(\w)(\w+)`), - Tags: map[string]string{ - "prefix": "\\1", - "suffix": "\\2", + {Tag: "ipversion", Index: 1, Mapping: map[string]string{ + "0": "unknown", + "1": "ipv4", + "2": "ipv6", + "3": "ipv4z", + "4": "ipv6z", + "16": "dns", }}, + {Tag: "if_type", + Symbol: profiledefinition.SymbolConfigCompat{OID: "1.3.6.1.2.1.2.2.1.3", Name: "ifType"}, + Mapping: map[string]string{ + "1": "other", + "2": "regular1822", + "3": "hdh1822", + "4": "ddn-x25", + "29": "ultra", + }}, + { + Symbol: profiledefinition.SymbolConfigCompat{ + Name: "cpiPduName", + OID: "1.2.3.4.8.1.2", + }, + Match: "(\\w)(\\w+)", + Pattern: regexp.MustCompile(`(\w)(\w+)`), + Tags: map[string]string{ + "prefix": "\\1", + "suffix": "\\2", + }}, + }, }, - }, - {Symbol: profiledefinition.SymbolConfig{OID: "1.2.3.4", Name: "aGlobalMetric"}}, - } - expectedMetrics = append(expectedMetrics, profiledefinition.MetricsConfig{Symbol: profiledefinition.SymbolConfig{OID: "1.3.6.1.2.1.1.3.0", Name: "sysUpTimeInstance"}}) - expectedMetrics = append(expectedMetrics, profile.FixtureProfileDefinitionMap()["f5-big-ip"].Definition.Metrics...) + {Symbol: profiledefinition.SymbolConfig{OID: "1.2.3.4", Name: "aGlobalMetric"}}, + } + expectedMetrics = append(expectedMetrics, profiledefinition.MetricsConfig{Symbol: profiledefinition.SymbolConfig{OID: "1.3.6.1.2.1.1.3.0", Name: "sysUpTimeInstance"}}) + expectedMetrics = append(expectedMetrics, profile.FixtureProfileDefinitionMap()["f5-big-ip"].Definition.Metrics...) - expectedMetricTags := []profiledefinition.MetricTagConfig{ - {Tag: "my_symbol", Symbol: profiledefinition.SymbolConfigCompat{OID: "1.2.3", Name: "mySymbol"}}, - {Tag: "my_symbol_mapped", Symbol: profiledefinition.SymbolConfigCompat{OID: "1.2.3", Name: "mySymbol"}, Mapping: map[string]string{"1": "one", "2": "two"}}, - { - Symbol: profiledefinition.SymbolConfigCompat{OID: "1.2.3", Name: "mySymbol"}, - Match: "(\\w)(\\w+)", - Pattern: regexp.MustCompile(`(\w)(\w+)`), - Tags: map[string]string{ - "prefix": "\\1", - "suffix": "\\2", + expectedMetricTags := []profiledefinition.MetricTagConfig{ + {Tag: "my_symbol", Symbol: profiledefinition.SymbolConfigCompat{OID: "1.2.3", Name: "mySymbol"}}, + {Tag: "my_symbol_mapped", Symbol: profiledefinition.SymbolConfigCompat{OID: "1.2.3", Name: "mySymbol"}, Mapping: map[string]string{"1": "one", "2": "two"}}, + { + Symbol: profiledefinition.SymbolConfigCompat{OID: "1.2.3", Name: "mySymbol"}, + Match: "(\\w)(\\w+)", + Pattern: regexp.MustCompile(`(\w)(\w+)`), + Tags: map[string]string{ + "prefix": "\\1", + "suffix": "\\2", + }, }, - }, - { - Symbol: profiledefinition.SymbolConfigCompat{OID: "1.3.6.1.2.1.1.5.0", Name: "sysName"}, - Match: "(\\w)(\\w+)", - Pattern: regexp.MustCompile(`(\w)(\w+)`), - Tags: map[string]string{ - "some_tag": "some_tag_value", - "prefix": "\\1", - "suffix": "\\2", + { + Symbol: profiledefinition.SymbolConfigCompat{OID: "1.3.6.1.2.1.1.5.0", Name: "sysName"}, + Match: "(\\w)(\\w+)", + Pattern: regexp.MustCompile(`(\w)(\w+)`), + Tags: map[string]string{ + "some_tag": "some_tag_value", + "prefix": "\\1", + "suffix": "\\2", + }, }, - }, - {Tag: "snmp_host", Symbol: profiledefinition.SymbolConfigCompat{OID: "1.3.6.1.2.1.1.5.0", Name: "sysName"}}, - } + {Tag: "snmp_host", Symbol: profiledefinition.SymbolConfigCompat{OID: "1.3.6.1.2.1.1.5.0", Name: "sysName"}}, + } - assert.Equal(t, expectedMetrics, config.Metrics) - assert.Equal(t, expectedMetricTags, config.MetricTags) - assert.Equal(t, []string{"snmp_profile:f5-big-ip", "device_vendor:f5", "static_tag:from_profile_root", "static_tag:from_base_profile"}, config.ProfileTags) - assert.True(t, config.ProfileProvider.HasProfile("f5-big-ip")) - assert.Equal(t, "default:1.2.3.4", config.DeviceID) - assert.Equal(t, []string{"device_namespace:default", "snmp_device:1.2.3.4"}, config.DeviceIDTags) - assert.Equal(t, "127.0.0.0/30", config.ResolvedSubnetName) - assert.Equal(t, false, config.AutodetectProfile) + profile, err := config.BuildProfile("") + require.NoError(t, err) + + assert.Equal(t, expectedMetrics, profile.Metrics) + assert.Equal(t, expectedMetricTags, profile.MetricTags) + assert.Equal(t, []string{"snmp_profile:f5-big-ip", "device_vendor:f5", "static_tag:from_profile_root", "static_tag:from_base_profile"}, profile.StaticTags) + }) } func TestDiscoveryConfigurations(t *testing.T) { @@ -310,6 +317,10 @@ profiles: assert.Nil(t, err) assert.Equal(t, []string{"device_namespace:default", "snmp_device:172.26.0.2", "device_ip:172.26.0.2", "device_id:default:172.26.0.2"}, config.GetStaticTags()) + + profile, err := config.BuildProfile("") + require.NoError(t, err) + metrics := []profiledefinition.MetricsConfig{ {Symbol: profiledefinition.SymbolConfig{OID: "1.3.6.1.2.1.1.3.0", Name: "sysUpTimeInstance"}}, {Symbol: profiledefinition.SymbolConfig{OID: "1.3.6.1.2.1.7.1.0", Name: "IAmACounter32"}}, @@ -318,10 +329,8 @@ profiles: {Symbol: profiledefinition.SymbolConfig{OID: "1.3.6.1.2.1.88.1.1.1.0", Name: "IAmAnInteger"}}, } - metricsTags := []profiledefinition.MetricTagConfig(nil) - - assert.Equal(t, metrics, config.Metrics) - assert.Equal(t, metricsTags, config.MetricTags) + assert.Equal(t, metrics, profile.Metrics) + assert.Empty(t, profile.MetricTags) } func TestInlineProfileConfiguration(t *testing.T) { @@ -357,30 +366,31 @@ profiles: name: myMetric `) config, err := NewCheckConfig(rawInstanceConfig, rawInitConfig) + require.NoError(t, err) - assert.Nil(t, err) assert.Equal(t, []string{"device_namespace:default", "snmp_device:1.2.3.4", "device_ip:1.2.3.4", "device_id:default:1.2.3.4"}, config.GetStaticTags()) - metrics := []profiledefinition.MetricsConfig{ - {Symbol: profiledefinition.SymbolConfig{OID: "1.3.6.1.2.1.1.3.0", Name: "sysUpTimeInstance"}}, - {MIB: "MY-PROFILE-MIB", Symbol: profiledefinition.SymbolConfig{OID: "1.4.5", Name: "myMetric"}, MetricType: profiledefinition.ProfileMetricTypeGauge}, - } - - metricsTags := []profiledefinition.MetricTagConfig{ - {Tag: "snmp_host", Symbol: profiledefinition.SymbolConfigCompat{OID: "1.3.6.1.2.1.1.5.0", Name: "sysName"}}, - } - assert.Equal(t, "123", config.CommunityString) - assert.Equal(t, metrics, config.Metrics) - assert.Equal(t, metricsTags, config.MetricTags) assert.True(t, config.ProfileProvider.HasProfile("f5-big-ip")) assert.True(t, config.ProfileProvider.HasProfile("inline-profile")) assert.Equal(t, "default:1.2.3.4", config.DeviceID) assert.Equal(t, []string{"device_namespace:default", "snmp_device:1.2.3.4"}, config.DeviceIDTags) - assert.Equal(t, false, config.AutodetectProfile) assert.Equal(t, 3600, config.DiscoveryInterval) assert.Equal(t, 3, config.DiscoveryAllowedFailures) assert.Equal(t, 5, config.DiscoveryWorkers) assert.Equal(t, 5, config.Workers) + + metrics := []profiledefinition.MetricsConfig{ + {Symbol: profiledefinition.SymbolConfig{OID: "1.3.6.1.2.1.1.3.0", Name: "sysUpTimeInstance"}}, + {MIB: "MY-PROFILE-MIB", Symbol: profiledefinition.SymbolConfig{OID: "1.4.5", Name: "myMetric"}, MetricType: profiledefinition.ProfileMetricTypeGauge}, + } + + metricsTags := []profiledefinition.MetricTagConfig{ + {Tag: "snmp_host", Symbol: profiledefinition.SymbolConfigCompat{OID: "1.3.6.1.2.1.1.5.0", Name: "sysName"}}, + } + profile, err := config.BuildProfile("") + require.NoError(t, err) + assert.Equal(t, metrics, profile.Metrics) + assert.Equal(t, metricsTags, profile.MetricTags) } func TestDefaultConfigurations(t *testing.T) { @@ -401,16 +411,17 @@ community_string: abc assert.Equal(t, uint16(161), config.Port) assert.Equal(t, 2, config.Timeout) assert.Equal(t, 3, config.Retries) - metrics := []profiledefinition.MetricsConfig{{Symbol: profiledefinition.SymbolConfig{OID: "1.3.6.1.2.1.1.3.0", Name: "sysUpTimeInstance"}}} - - var metricsTags []profiledefinition.MetricTagConfig - assert.Equal(t, metrics, config.Metrics) - assert.Equal(t, metricsTags, config.MetricTags) - // assert.Equal(t, 2, len(config.Profiles)) assert.True(t, config.ProfileProvider.HasProfile("f5-big-ip")) assert.True(t, config.ProfileProvider.HasProfile("another_profile")) assert.Equal(t, profile.FixtureProfileDefinitionMap()["f5-big-ip"].Definition.Metrics, config.ProfileProvider.GetProfile("f5-big-ip").Definition.Metrics) + + profile, err := config.BuildProfile("") + require.NoError(t, err) + + metrics := []profiledefinition.MetricsConfig{{Symbol: profiledefinition.SymbolConfig{OID: "1.3.6.1.2.1.1.3.0", Name: "sysUpTimeInstance"}}} + assert.Equal(t, metrics, profile.Metrics) + assert.Empty(t, profile.MetricTags) } func TestPortConfiguration(t *testing.T) { @@ -575,14 +586,17 @@ global_metrics: name: aGlobalMetric `) config, err := NewCheckConfig(rawInstanceConfig, rawInitConfig) - assert.Nil(t, err) + require.NoError(t, err) + + profile, err := config.BuildProfile("") + require.NoError(t, err) metrics := []profiledefinition.MetricsConfig{ {Symbol: profiledefinition.SymbolConfig{OID: "1.3.6.1.2.1.2.1", Name: "ifNumber"}}, {Symbol: profiledefinition.SymbolConfig{OID: "1.2.3.4", Name: "aGlobalMetric"}}, {Symbol: profiledefinition.SymbolConfig{OID: "1.3.6.1.2.1.1.3.0", Name: "sysUpTimeInstance"}}, } - assert.Equal(t, metrics, config.Metrics) + assert.Equal(t, metrics, profile.Metrics) } func TestUseGlobalMetricsFalse(t *testing.T) { @@ -606,13 +620,16 @@ global_metrics: name: aGlobalMetric `) config, err := NewCheckConfig(rawInstanceConfig, rawInitConfig) - assert.Nil(t, err) + require.NoError(t, err) + + profile, err := config.BuildProfile("") + require.NoError(t, err) metrics := []profiledefinition.MetricsConfig{ {Symbol: profiledefinition.SymbolConfig{OID: "1.3.6.1.2.1.2.1", Name: "aInstanceMetric"}}, {Symbol: profiledefinition.SymbolConfig{OID: "1.3.6.1.2.1.1.3.0", Name: "sysUpTimeInstance"}}, } - assert.Equal(t, metrics, config.Metrics) + assert.Equal(t, metrics, profile.Metrics) } func Test_NewCheckConfig_errors(t *testing.T) { @@ -624,23 +641,6 @@ func Test_NewCheckConfig_errors(t *testing.T) { rawInitConfig []byte expectedErrors []string }{ - { - name: "unknown profile", - // language=yaml - rawInstanceConfig: []byte(` -ip_address: 1.2.3.4 -profile: does-not-exist -`), - // language=yaml - rawInitConfig: []byte(` -profiles: - f5-big-ip: - definition_file: f5-big-ip.yaml -`), - expectedErrors: []string{ - "failed to refresh with profile `does-not-exist`: unknown profile `does-not-exist`", - }, - }, { name: "validation errors", // language=yaml @@ -699,6 +699,7 @@ network_address: 10.0.0.0/xx t.Run(tt.name, func(t *testing.T) { _, err := NewCheckConfig(tt.rawInstanceConfig, tt.rawInitConfig) for _, errStr := range tt.expectedErrors { + require.NotNil(t, err, "expected error %q", errStr) assert.Contains(t, err.Error(), errStr) } }) @@ -806,254 +807,6 @@ func Test_snmpConfig_getDeviceIDTags(t *testing.T) { assert.Equal(t, expectedTags, actualTags) } -func Test_snmpConfig_setProfile(t *testing.T) { - metrics := []profiledefinition.MetricsConfig{ - {Symbol: profiledefinition.SymbolConfig{OID: "1.2.3.4.5", Name: "someMetric"}}, - { - Symbols: []profiledefinition.SymbolConfig{ - { - OID: "1.2.3.4.6", - Name: "abc", - }, - }, - MetricTags: profiledefinition.MetricTagConfigList{ - profiledefinition.MetricTagConfig{ - Symbol: profiledefinition.SymbolConfigCompat{ - OID: "1.2.3.4.7", - }, - }, - }, - }, - } - profile1 := profiledefinition.ProfileDefinition{ - Device: profiledefinition.DeviceMeta{ - Vendor: "a-vendor", - }, - Metrics: metrics, - MetricTags: []profiledefinition.MetricTagConfig{ - {Tag: "location", Symbol: profiledefinition.SymbolConfigCompat{OID: "1.3.6.1.2.1.1.6.0", Name: "sysLocation"}}, - }, - Metadata: profiledefinition.MetadataConfig{ - "device": { - Fields: map[string]profiledefinition.MetadataField{ - "description": { - Symbol: profiledefinition.SymbolConfig{ - OID: "1.3.6.1.2.1.1.99.3.0", - Name: "sysDescr", - }, - }, - "name": { - Symbols: []profiledefinition.SymbolConfig{ - { - OID: "1.3.6.1.2.1.1.99.1.0", - Name: "symbol1", - }, - { - OID: "1.3.6.1.2.1.1.99.2.0", - Name: "symbol2", - }, - }, - }, - }, - }, - "interface": { - Fields: map[string]profiledefinition.MetadataField{ - "oper_status": { - Symbol: profiledefinition.SymbolConfig{ - OID: "1.3.6.1.2.1.2.2.1.99", - Name: "someIfSymbol", - }, - }, - }, - IDTags: profiledefinition.MetricTagConfigList{ - { - Tag: "interface", - Symbol: profiledefinition.SymbolConfigCompat{ - OID: "1.3.6.1.2.1.31.1.1.1.1", - Name: "ifName", - }, - }, - }, - }, - }, - SysObjectIDs: profiledefinition.StringArray{"1.3.6.1.4.1.3375.2.1.3.4.*"}, - } - profile2 := profiledefinition.ProfileDefinition{ - Device: profiledefinition.DeviceMeta{Vendor: "b-vendor"}, - Metrics: []profiledefinition.MetricsConfig{{Symbol: profiledefinition.SymbolConfig{OID: "2.3.4.5.6.1", Name: "b-metric"}}}, - MetricTags: []profiledefinition.MetricTagConfig{ - {Tag: "btag", Symbol: profiledefinition.SymbolConfigCompat{OID: "2.3.4.5.6.2", Name: "b-tag-name"}}, - }, - Metadata: profiledefinition.MetadataConfig{ - "device": { - Fields: map[string]profiledefinition.MetadataField{ - "b-description": { - Symbol: profiledefinition.SymbolConfig{ - OID: "2.3.4.5.6.3", - Name: "sysDescr", - }, - }, - "b-name": { - Symbols: []profiledefinition.SymbolConfig{ - { - OID: "2.3.4.5.6.4", - Name: "b-symbol1", - }, - { - OID: "2.3.4.5.6.5", - Name: "b-symbol2", - }, - }, - }, - }, - }, - "interface": { - Fields: map[string]profiledefinition.MetadataField{ - "oper_status": { - Symbol: profiledefinition.SymbolConfig{ - OID: "2.3.4.5.6.6", - Name: "b-someIfSymbol", - }, - }, - }, - IDTags: profiledefinition.MetricTagConfigList{ - { - Tag: "b-interface", - Symbol: profiledefinition.SymbolConfigCompat{ - OID: "2.3.4.5.6.7", - Name: "b-ifName", - }, - }, - }, - }, - }, - SysObjectIDs: profiledefinition.StringArray{"1.3.6.1.4.1.3375.2.1.3.4.*"}, - } - - mockProfiles := profile.StaticProvider(profile.ProfileConfigMap{ - "profile1": profile.ProfileConfig{ - Definition: profile1, - }, - "profile2": profile.ProfileConfig{ - Definition: profile2, - }, - }) - c := &CheckConfig{ - IPAddress: "1.2.3.4", - ProfileProvider: mockProfiles, - } - err := c.SetProfile("f5") - assert.EqualError(t, err, "unknown profile `f5`") - - err = c.SetProfile("profile1") - assert.NoError(t, err) - - assert.Equal(t, "profile1", c.ProfileName) - assert.Equal(t, &profile1, c.GetProfileDef()) - assert.Equal(t, metrics, c.Metrics) - assert.Equal(t, []profiledefinition.MetricTagConfig{ - {Tag: "location", Symbol: profiledefinition.SymbolConfigCompat{OID: "1.3.6.1.2.1.1.6.0", Name: "sysLocation"}}, - }, c.MetricTags) - assert.Equal(t, OidConfig{ - ScalarOids: []string{"1.2.3.4.5", "1.3.6.1.2.1.1.6.0"}, - ColumnOids: []string{"1.2.3.4.6", "1.2.3.4.7"}, - }, c.OidConfig) - assert.Equal(t, []string{"snmp_profile:profile1", "device_vendor:a-vendor"}, c.ProfileTags) - - c = &CheckConfig{ - IPAddress: "1.2.3.4", - ProfileProvider: mockProfiles, - CollectDeviceMetadata: true, - CollectTopology: false, - } - err = c.SetProfile("profile1") - assert.NoError(t, err) - assert.Equal(t, OidConfig{ - ScalarOids: []string{ - "1.2.3.4.5", - "1.3.6.1.2.1.1.6.0", - "1.3.6.1.2.1.1.99.1.0", - "1.3.6.1.2.1.1.99.2.0", - "1.3.6.1.2.1.1.99.3.0", - }, - ColumnOids: []string{ - "1.2.3.4.6", - "1.2.3.4.7", - "1.3.6.1.2.1.2.2.1.99", - "1.3.6.1.2.1.31.1.1.1.1", - "1.3.6.1.2.1.4.20.1.2", - "1.3.6.1.2.1.4.20.1.3", - }, - }, c.OidConfig) - - // With metadata disabled - c.CollectDeviceMetadata = false - err = c.SetProfile("profile1") - assert.NoError(t, err) - assert.Equal(t, OidConfig{ - ScalarOids: []string{ - "1.2.3.4.5", - "1.3.6.1.2.1.1.6.0", - }, - ColumnOids: []string{ - "1.2.3.4.6", - "1.2.3.4.7", - }, - }, c.OidConfig) - - c = &CheckConfig{ - IPAddress: "1.2.3.4", - ProfileProvider: mockProfiles, - CollectDeviceMetadata: true, - CollectTopology: false, - } - c.RequestedMetrics = append(c.RequestedMetrics, - profiledefinition.MetricsConfig{Symbol: profiledefinition.SymbolConfig{OID: "3.1", Name: "global-metric"}}) - c.RequestedMetricTags = append(c.RequestedMetricTags, - profiledefinition.MetricTagConfig{Tag: "global-tag", Symbol: profiledefinition.SymbolConfigCompat{OID: "3.2", Name: "globalSymbol"}}) - err = c.SetProfile("profile1") - assert.NoError(t, err) - assert.Equal(t, OidConfig{ - ScalarOids: []string{ - "1.2.3.4.5", - "1.3.6.1.2.1.1.6.0", - "1.3.6.1.2.1.1.99.1.0", - "1.3.6.1.2.1.1.99.2.0", - "1.3.6.1.2.1.1.99.3.0", - "3.1", - "3.2", - }, - ColumnOids: []string{ - "1.2.3.4.6", - "1.2.3.4.7", - "1.3.6.1.2.1.2.2.1.99", - "1.3.6.1.2.1.31.1.1.1.1", - "1.3.6.1.2.1.4.20.1.2", - "1.3.6.1.2.1.4.20.1.3", - }, - }, c.OidConfig) - err = c.SetProfile("profile2") - assert.NoError(t, err) - assert.Equal(t, OidConfig{ - ScalarOids: []string{ - "2.3.4.5.6.1", - "2.3.4.5.6.2", - "2.3.4.5.6.3", - "2.3.4.5.6.4", - "2.3.4.5.6.5", - "3.1", - "3.2", - }, - ColumnOids: []string{ - "1.3.6.1.2.1.4.20.1.2", - "1.3.6.1.2.1.4.20.1.3", - "2.3.4.5.6.6", - "2.3.4.5.6.7", - }, - }, c.OidConfig) - -} - func Test_getSubnetFromTags(t *testing.T) { subnet, err := getSubnetFromTags([]string{"aa", "bb"}) assert.Equal(t, "", subnet) @@ -1913,10 +1666,6 @@ func TestCheckConfig_Copy(t *testing.T) { PrivProtocol: "des", PrivKey: "123", ContextName: "", - OidConfig: OidConfig{ - ScalarOids: []string{"1.2.3"}, - ColumnOids: []string{"1.2.3", "2.3.4"}, - }, RequestedMetrics: []profiledefinition.MetricsConfig{ { Symbol: profiledefinition.SymbolConfig{ @@ -1928,17 +1677,6 @@ func TestCheckConfig_Copy(t *testing.T) { RequestedMetricTags: []profiledefinition.MetricTagConfig{ {Tag: "my_symbol", Symbol: profiledefinition.SymbolConfigCompat{OID: "1.2.3", Name: "mySymbol"}}, }, - Metrics: []profiledefinition.MetricsConfig{ - { - Symbol: profiledefinition.SymbolConfig{ - OID: "1.2", - Name: "abc", - }, - }, - }, - MetricTags: []profiledefinition.MetricTagConfig{ - {Tag: "my_symbol", Symbol: profiledefinition.SymbolConfigCompat{OID: "1.2.3", Name: "mySymbol"}}, - }, OidBatchSize: 10, BulkMaxRepetitions: 10, ProfileProvider: profile.StaticProvider(profile.ProfileConfigMap{"f5-big-ip": profile.ProfileConfig{ @@ -1946,7 +1684,6 @@ func TestCheckConfig_Copy(t *testing.T) { Device: profiledefinition.DeviceMeta{Vendor: "f5"}, }, }}), - ProfileTags: []string{"profile_tag:atag"}, ProfileName: "f5", ExtraTags: []string{"ExtraTags:tag"}, InstanceTags: []string{"InstanceTags:tag"}, @@ -1956,7 +1693,6 @@ func TestCheckConfig_Copy(t *testing.T) { DeviceID: "123", DeviceIDTags: []string{"DeviceIDTags:tag"}, ResolvedSubnetName: "1.2.3.4/28", - AutodetectProfile: true, MinCollectionInterval: 120, } configCopy := config.Copy() @@ -1965,9 +1701,6 @@ func TestCheckConfig_Copy(t *testing.T) { assert.NotSame(t, &config.RequestedMetrics, &configCopy.RequestedMetrics) assert.NotSame(t, &config.RequestedMetricTags, &configCopy.RequestedMetricTags) - assert.NotSame(t, &config.Metrics, &configCopy.Metrics) - assert.NotSame(t, &config.MetricTags, &configCopy.MetricTags) - assert.NotSame(t, &config.ProfileTags, &configCopy.ProfileTags) assert.NotSame(t, &config.ExtraTags, &configCopy.ExtraTags) assert.NotSame(t, &config.InstanceTags, &configCopy.InstanceTags) assert.NotSame(t, &config.DeviceIDTags, &configCopy.DeviceIDTags) From 2eac8db007d9f45b1a74d4530c472fe168165b05 Mon Sep 17 00:00:00 2001 From: Daniel Lepage Date: Fri, 13 Dec 2024 16:58:29 -0500 Subject: [PATCH 2/5] Only pass fields we need into Fetch. --- .../corechecks/snmp/internal/fetch/fetch.go | 13 ++--- .../snmp/internal/fetch/fetch_test.go | 54 +++++++------------ 2 files changed, 27 insertions(+), 40 deletions(-) diff --git a/pkg/collector/corechecks/snmp/internal/fetch/fetch.go b/pkg/collector/corechecks/snmp/internal/fetch/fetch.go index 54987adef0ed2..b55d5cbf602d5 100644 --- a/pkg/collector/corechecks/snmp/internal/fetch/fetch.go +++ b/pkg/collector/corechecks/snmp/internal/fetch/fetch.go @@ -12,7 +12,6 @@ import ( "github.com/DataDog/datadog-agent/pkg/util/log" - "github.com/DataDog/datadog-agent/pkg/collector/corechecks/snmp/internal/checkconfig" "github.com/DataDog/datadog-agent/pkg/collector/corechecks/snmp/internal/session" "github.com/DataDog/datadog-agent/pkg/collector/corechecks/snmp/internal/valuestore" ) @@ -36,19 +35,21 @@ func (c columnFetchStrategy) String() string { } // Fetch oid values from device -// TODO: pass only specific configs instead of the whole CheckConfig -func Fetch(sess session.Session, config *checkconfig.CheckConfig) (*valuestore.ResultValueStore, error) { +func Fetch(sess session.Session, scalarOIDs, columnOIDs []string, batchSize int, + bulkMaxRepetitions uint32) (*valuestore.ResultValueStore, error) { // fetch scalar values - scalarResults, err := fetchScalarOidsWithBatching(sess, config.OidConfig.ScalarOids, config.OidBatchSize) + scalarResults, err := fetchScalarOidsWithBatching(sess, scalarOIDs, batchSize) if err != nil { return nil, fmt.Errorf("failed to fetch scalar oids with batching: %v", err) } - columnResults, err := fetchColumnOidsWithBatching(sess, config.OidConfig.ColumnOids, config.OidBatchSize, config.BulkMaxRepetitions, useGetBulk) + columnResults, err := fetchColumnOidsWithBatching(sess, columnOIDs, batchSize, + bulkMaxRepetitions, useGetBulk) if err != nil { log.Debugf("failed to fetch oids with GetBulk batching: %v", err) - columnResults, err = fetchColumnOidsWithBatching(sess, config.OidConfig.ColumnOids, config.OidBatchSize, config.BulkMaxRepetitions, useGetNext) + columnResults, err = fetchColumnOidsWithBatching(sess, columnOIDs, batchSize, bulkMaxRepetitions, + useGetNext) if err != nil { return nil, fmt.Errorf("failed to fetch oids with GetNext batching: %v", err) } diff --git a/pkg/collector/corechecks/snmp/internal/fetch/fetch_test.go b/pkg/collector/corechecks/snmp/internal/fetch/fetch_test.go index 63c2c4ce937f3..e219144b768b8 100644 --- a/pkg/collector/corechecks/snmp/internal/fetch/fetch_test.go +++ b/pkg/collector/corechecks/snmp/internal/fetch/fetch_test.go @@ -370,14 +370,9 @@ func Test_fetchColumnOidsBatch_usingGetBulkAndGetNextFallback(t *testing.T) { sess.On("GetNext", []string{"1.1.3"}).Return(&secondBatchPacket1, nil) sess.On("GetNext", []string{"1.1.3.1"}).Return(&secondBatchPacket2, nil) - config := &checkconfig.CheckConfig{ - BulkMaxRepetitions: checkconfig.DefaultBulkMaxRepetitions, - OidBatchSize: 2, - OidConfig: checkconfig.OidConfig{ - ColumnOids: []string{"1.1.1", "1.1.2", "1.1.3"}, - }, - } - columnValues, err := Fetch(sess, config) + columnOIDs := []string{"1.1.1", "1.1.2", "1.1.3"} + + columnValues, err := Fetch(sess, nil, columnOIDs, 2, checkconfig.DefaultBulkMaxRepetitions) assert.Nil(t, err) expectedColumnValues := &valuestore.ResultValueStore{ @@ -719,41 +714,32 @@ func Test_fetchScalarOids_v1NoSuchName_errorIndexTooLow(t *testing.T) { func Test_fetchValues_errors(t *testing.T) { tests := []struct { name string - config checkconfig.CheckConfig + maxReps uint32 + batchSize int + ScalarOIDs []string + ColumnOIDs []string bulkPacket gosnmp.SnmpPacket expectedError error }{ { - name: "invalid batch size", - config: checkconfig.CheckConfig{ - BulkMaxRepetitions: checkconfig.DefaultBulkMaxRepetitions, - OidConfig: checkconfig.OidConfig{ - ScalarOids: []string{"1.1", "1.2"}, - }, - }, + name: "invalid batch size", + maxReps: checkconfig.DefaultBulkMaxRepetitions, + ScalarOIDs: []string{"1.1", "1.2"}, expectedError: fmt.Errorf("failed to fetch scalar oids with batching: failed to create oid batches: batch size must be positive. invalid size: 0"), }, { - name: "get fetch error", - config: checkconfig.CheckConfig{ - BulkMaxRepetitions: checkconfig.DefaultBulkMaxRepetitions, - OidBatchSize: 10, - OidConfig: checkconfig.OidConfig{ - ScalarOids: []string{"1.1", "2.2"}, - }, - }, + name: "get fetch error", + maxReps: checkconfig.DefaultBulkMaxRepetitions, + batchSize: 10, + ScalarOIDs: []string{"1.1", "2.2"}, expectedError: fmt.Errorf("failed to fetch scalar oids with batching: failed to fetch scalar oids: fetch scalar: error getting oids `[1.1 2.2]`: get error"), }, { - name: "bulk fetch error", - config: checkconfig.CheckConfig{ - BulkMaxRepetitions: checkconfig.DefaultBulkMaxRepetitions, - OidBatchSize: 10, - OidConfig: checkconfig.OidConfig{ - ScalarOids: []string{}, - ColumnOids: []string{"1.1", "2.2"}, - }, - }, + name: "bulk fetch error", + maxReps: checkconfig.DefaultBulkMaxRepetitions, + batchSize: 10, + ScalarOIDs: []string{}, + ColumnOIDs: []string{"1.1", "2.2"}, expectedError: fmt.Errorf("failed to fetch oids with GetNext batching: failed to fetch column oids: fetch column: failed getting oids `[1.1 2.2]` using GetNext: getnext error"), }, } @@ -764,7 +750,7 @@ func Test_fetchValues_errors(t *testing.T) { sess.On("GetBulk", []string{"1.1", "2.2"}, checkconfig.DefaultBulkMaxRepetitions).Return(&gosnmp.SnmpPacket{}, fmt.Errorf("bulk error")) sess.On("GetNext", []string{"1.1", "2.2"}).Return(&gosnmp.SnmpPacket{}, fmt.Errorf("getnext error")) - _, err := Fetch(sess, &tt.config) + _, err := Fetch(sess, tt.ScalarOIDs, tt.ColumnOIDs, tt.batchSize, tt.maxReps) assert.Equal(t, tt.expectedError, err) }) From 5c5eaea3bf3c0e83dbff3e0d6261ccdef4d2ecc7 Mon Sep 17 00:00:00 2001 From: Daniel Lepage Date: Fri, 13 Dec 2024 17:11:32 -0500 Subject: [PATCH 3/5] Accept profile in report methods. --- .../internal/report/report_device_metadata.go | 34 ++-- .../report/report_device_metadata_test.go | 180 ++++++++---------- 2 files changed, 95 insertions(+), 119 deletions(-) diff --git a/pkg/collector/corechecks/snmp/internal/report/report_device_metadata.go b/pkg/collector/corechecks/snmp/internal/report/report_device_metadata.go index 6bdcec852a1d8..e9a66db578a3a 100644 --- a/pkg/collector/corechecks/snmp/internal/report/report_device_metadata.go +++ b/pkg/collector/corechecks/snmp/internal/report/report_device_metadata.go @@ -51,13 +51,13 @@ var supportedDeviceTypes = map[string]bool{ } // ReportNetworkDeviceMetadata reports device metadata -func (ms *MetricSender) ReportNetworkDeviceMetadata(config *checkconfig.CheckConfig, store *valuestore.ResultValueStore, origTags []string, collectTime time.Time, deviceStatus devicemetadata.DeviceStatus, pingStatus devicemetadata.DeviceStatus, diagnoses []devicemetadata.DiagnosisMetadata) { +func (ms *MetricSender) ReportNetworkDeviceMetadata(config *checkconfig.CheckConfig, profile profiledefinition.ProfileDefinition, store *valuestore.ResultValueStore, origTags []string, collectTime time.Time, deviceStatus devicemetadata.DeviceStatus, pingStatus devicemetadata.DeviceStatus, diagnoses []devicemetadata.DiagnosisMetadata) { tags := utils.CopyStrings(origTags) tags = util.SortUniqInPlace(tags) - metadataStore := buildMetadataStore(config.Metadata, store) + metadataStore := buildMetadataStore(profile.Metadata, store) - devices := []devicemetadata.DeviceMetadata{buildNetworkDeviceMetadata(config.DeviceID, config.DeviceIDTags, config, metadataStore, tags, deviceStatus, pingStatus)} + devices := []devicemetadata.DeviceMetadata{buildNetworkDeviceMetadata(config.DeviceID, config.DeviceIDTags, config, profile, metadataStore, tags, deviceStatus, pingStatus)} interfaces := buildNetworkInterfacesMetadata(config.DeviceID, metadataStore) ipAddresses := buildNetworkIPAddressesMetadata(config.DeviceID, metadataStore) @@ -191,8 +191,9 @@ func buildMetadataStore(metadataConfigs profiledefinition.MetadataConfig, values return metadataStore } -func buildNetworkDeviceMetadata(deviceID string, idTags []string, config *checkconfig.CheckConfig, store *metadata.Store, tags []string, deviceStatus devicemetadata.DeviceStatus, pingStatus devicemetadata.DeviceStatus) devicemetadata.DeviceMetadata { - var vendor, sysName, sysDescr, sysObjectID, location, serialNumber, version, productName, model, osName, osVersion, osHostname, deviceType string +func buildNetworkDeviceMetadata(deviceID string, idTags []string, config *checkconfig.CheckConfig, profile profiledefinition.ProfileDefinition, store *metadata.Store, tags []string, deviceStatus devicemetadata.DeviceStatus, pingStatus devicemetadata.DeviceStatus) devicemetadata.DeviceMetadata { + var vendor, sysName, sysDescr, sysObjectID, location, serialNumber, version, productName, model, osName, osVersion, osHostname, deviceType, profileName string + var profileVersion uint64 if store != nil { sysName = store.GetScalarAsString("device.name") sysDescr = store.GetScalarAsString("device.description") @@ -209,10 +210,12 @@ func buildNetworkDeviceMetadata(deviceID string, idTags []string, config *checkc deviceType = getDeviceType(store) } - // fallback to Device.Vendor for backward compatibility - profileDef := config.GetProfileDef() - if profileDef != nil && vendor == "" { - vendor = profileDef.Device.Vendor + profileName = profile.Name + profileVersion = profile.Version + // TODO(ndm-core) I don't think this can ever happen. + // If the profile provides a static vendor then it should have been populated in the store no matter what. + if vendor == "" { + vendor = profile.GetVendor() } return devicemetadata.DeviceMetadata{ @@ -223,8 +226,8 @@ func buildNetworkDeviceMetadata(deviceID string, idTags []string, config *checkc IPAddress: config.IPAddress, SysObjectID: sysObjectID, Location: location, - Profile: config.ProfileName, - ProfileVersion: getProfileVersion(config), + Profile: profileName, + ProfileVersion: profileVersion, Vendor: vendor, Tags: tags, Subnet: config.ResolvedSubnetName, @@ -242,15 +245,6 @@ func buildNetworkDeviceMetadata(deviceID string, idTags []string, config *checkc } } -func getProfileVersion(config *checkconfig.CheckConfig) uint64 { - var profileVersion uint64 - profileDef := config.GetProfileDef() - if profileDef != nil { - profileVersion = profileDef.Version - } - return profileVersion -} - func getDeviceType(store *metadata.Store) string { deviceType := strings.ToLower(store.GetScalarAsString("device.type")) if deviceType == "" { diff --git a/pkg/collector/corechecks/snmp/internal/report/report_device_metadata_test.go b/pkg/collector/corechecks/snmp/internal/report/report_device_metadata_test.go index 22d58e9530216..642cace14d0dd 100644 --- a/pkg/collector/corechecks/snmp/internal/report/report_device_metadata_test.go +++ b/pkg/collector/corechecks/snmp/internal/report/report_device_metadata_test.go @@ -9,6 +9,8 @@ import ( "bufio" "bytes" "encoding/json" + "github.com/DataDog/datadog-agent/pkg/collector/corechecks/snmp/internal/profile" + "github.com/stretchr/testify/require" "testing" "time" @@ -23,7 +25,6 @@ import ( "github.com/DataDog/datadog-agent/pkg/snmp/snmpintegration" "github.com/DataDog/datadog-agent/pkg/collector/corechecks/snmp/internal/checkconfig" - "github.com/DataDog/datadog-agent/pkg/collector/corechecks/snmp/internal/profile" "github.com/DataDog/datadog-agent/pkg/collector/corechecks/snmp/internal/valuestore" ) @@ -67,72 +68,74 @@ func Test_metricSender_reportNetworkDeviceMetadata_withoutInterfaces(t *testing. Definition: profiledefinition.ProfileDefinition{ Name: "my-profile", Version: 10, - }, - }, - }), - Metadata: profiledefinition.MetadataConfig{ - "device": { - Fields: map[string]profiledefinition.MetadataField{ - "name": { - // Should use value from Symbol `1.3.6.1.2.1.1.5.0` - Symbol: profiledefinition.SymbolConfig{ - OID: "1.3.6.1.2.1.1.5.0", - Name: "sysName", - }, - Symbols: []profiledefinition.SymbolConfig{ - { - OID: "1.2.99", - Name: "doesNotExist", + Metadata: profiledefinition.MetadataConfig{ + "device": { + Fields: map[string]profiledefinition.MetadataField{ + "name": { + // Should use value from Symbol `1.3.6.1.2.1.1.5.0` + Symbol: profiledefinition.SymbolConfig{ + OID: "1.3.6.1.2.1.1.5.0", + Name: "sysName", + }, + Symbols: []profiledefinition.SymbolConfig{ + { + OID: "1.2.99", + Name: "doesNotExist", + }, + }, + }, + "description": { + // Should use value from first element in Symbols `1.3.6.1.2.1.1.1.0` + Symbol: profiledefinition.SymbolConfig{ + OID: "1.9999", + Name: "doesNotExist", + }, + Symbols: []profiledefinition.SymbolConfig{ + { + OID: "1.3.6.1.2.1.1.1.0", + Name: "sysDescr", + }, + }, + }, + "location": { + // Should use value from first element in Symbols `1.3.6.1.2.1.1.1.0` + Symbol: profiledefinition.SymbolConfig{ + OID: "1.9999", + Name: "doesNotExist", + }, + Symbols: []profiledefinition.SymbolConfig{ + { + OID: "1.888", + Name: "doesNotExist2", + }, + { + OID: "1.3.6.1.2.1.1.6.0", + Name: "sysLocation", + }, + { + OID: "1.7777", + Name: "doesNotExist2", + }, + }, + }, + "type": { + Value: "router", + }, }, }, }, - "description": { - // Should use value from first element in Symbols `1.3.6.1.2.1.1.1.0` - Symbol: profiledefinition.SymbolConfig{ - OID: "1.9999", - Name: "doesNotExist", - }, - Symbols: []profiledefinition.SymbolConfig{ - { - OID: "1.3.6.1.2.1.1.1.0", - Name: "sysDescr", - }, - }, - }, - "location": { - // Should use value from first element in Symbols `1.3.6.1.2.1.1.1.0` - Symbol: profiledefinition.SymbolConfig{ - OID: "1.9999", - Name: "doesNotExist", - }, - Symbols: []profiledefinition.SymbolConfig{ - { - OID: "1.888", - Name: "doesNotExist2", - }, - { - OID: "1.3.6.1.2.1.1.6.0", - Name: "sysLocation", - }, - { - OID: "1.7777", - Name: "doesNotExist2", - }, - }, - }, - "type": { - Value: "router", - }, }, }, - }, + }), } layout := "2006-01-02 15:04:05" str := "2014-11-12 11:45:26" collectTime, err := time.Parse(layout, str) - assert.NoError(t, err) + require.NoError(t, err) + profile, err := config.BuildProfile("") + require.NoError(t, err) - ms.ReportNetworkDeviceMetadata(config, storeWithoutIfName, []string{"tag1", "tag2"}, collectTime, metadata.DeviceStatusReachable, metadata.DeviceStatusReachable, nil) + ms.ReportNetworkDeviceMetadata(config, profile, storeWithoutIfName, []string{"tag1", "tag2"}, collectTime, metadata.DeviceStatusReachable, metadata.DeviceStatusReachable, nil) // language=json event := []byte(` @@ -207,14 +210,17 @@ profiles: `) config, err := checkconfig.NewCheckConfig(rawInstanceConfig, rawInitConfig) - assert.Nil(t, err) + require.Nil(t, err) layout := "2006-01-02 15:04:05" str := "2014-11-12 11:45:26" collectTime, err := time.Parse(layout, str) - assert.NoError(t, err) + require.NoError(t, err) + profile, err := config.BuildProfile("") + require.NoError(t, err) - ms.ReportNetworkDeviceMetadata(config, storeWithoutIfName, []string{"tag1", "tag2"}, collectTime, metadata.DeviceStatusReachable, metadata.DeviceStatusReachable, nil) + ms.ReportNetworkDeviceMetadata(config, profile, storeWithoutIfName, []string{"tag1", "tag2"}, collectTime, + metadata.DeviceStatusReachable, metadata.DeviceStatusReachable, nil) // language=json event := []byte(` @@ -296,6 +302,8 @@ func Test_metricSender_reportNetworkDeviceMetadata_withDeviceInterfacesAndDiagno DeviceIDTags: []string{"device_name:127.0.0.1"}, ResolvedSubnetName: "127.0.0.0/29", Namespace: "my-ns", + } + profile := profiledefinition.ProfileDefinition{ Metadata: profiledefinition.MetadataConfig{ "device": { Fields: map[string]profiledefinition.MetadataField{ @@ -354,7 +362,7 @@ func Test_metricSender_reportNetworkDeviceMetadata_withDeviceInterfacesAndDiagno str := "2014-11-12 11:45:26" collectTime, err := time.Parse(layout, str) assert.NoError(t, err) - ms.ReportNetworkDeviceMetadata(config, storeWithIfName, []string{"tag1", "tag2"}, collectTime, metadata.DeviceStatusReachable, metadata.DeviceStatusUnreachable, diagnosis) + ms.ReportNetworkDeviceMetadata(config, profile, storeWithIfName, []string{"tag1", "tag2"}, collectTime, metadata.DeviceStatusReachable, metadata.DeviceStatusUnreachable, diagnosis) ifTags1 := []string{"tag1", "tag2", "status:down", "interface:21", "interface_alias:ifAlias1", "interface_index:1", "oper_status:up", "admin_status:down"} ifTags2 := []string{"tag1", "tag2", "status:off", "interface:22", "interface_index:2", "oper_status:down", "admin_status:down", "muted", "someKey:someValue"} @@ -447,6 +455,8 @@ func Test_metricSender_reportNetworkDeviceMetadata_fallbackOnFieldValue(t *testi DeviceIDTags: []string{"device_name:127.0.0.1"}, ResolvedSubnetName: "127.0.0.0/29", Namespace: "my-ns", + } + profile := profiledefinition.ProfileDefinition{ Metadata: profiledefinition.MetadataConfig{ "device": { Fields: map[string]profiledefinition.MetadataField{ @@ -469,7 +479,7 @@ func Test_metricSender_reportNetworkDeviceMetadata_fallbackOnFieldValue(t *testi collectTime, err := time.Parse(layout, str) assert.NoError(t, err) - ms.ReportNetworkDeviceMetadata(config, emptyMetadataStore, []string{"tag1", "tag2"}, collectTime, metadata.DeviceStatusReachable, metadata.DeviceStatusUnreachable, nil) + ms.ReportNetworkDeviceMetadata(config, profile, emptyMetadataStore, []string{"tag1", "tag2"}, collectTime, metadata.DeviceStatusReachable, metadata.DeviceStatusUnreachable, nil) // language=json event := []byte(` @@ -522,6 +532,8 @@ func Test_metricSender_reportNetworkDeviceMetadata_pingCanConnect_Nil(t *testing DeviceIDTags: []string{"device_name:127.0.0.1"}, ResolvedSubnetName: "127.0.0.0/29", Namespace: "my-ns", + } + profile := profiledefinition.ProfileDefinition{ Metadata: profiledefinition.MetadataConfig{ "device": { Fields: map[string]profiledefinition.MetadataField{ @@ -541,7 +553,7 @@ func Test_metricSender_reportNetworkDeviceMetadata_pingCanConnect_Nil(t *testing collectTime, err := time.Parse(layout, str) assert.NoError(t, err) - ms.ReportNetworkDeviceMetadata(config, emptyMetadataStore, []string{"tag1", "tag2"}, collectTime, metadata.DeviceStatusReachable, 0, nil) + ms.ReportNetworkDeviceMetadata(config, profile, emptyMetadataStore, []string{"tag1", "tag2"}, collectTime, metadata.DeviceStatusReachable, 0, nil) // language=json event := []byte(` @@ -593,6 +605,8 @@ func Test_metricSender_reportNetworkDeviceMetadata_pingCanConnect_True(t *testin DeviceIDTags: []string{"device_name:127.0.0.1"}, ResolvedSubnetName: "127.0.0.0/29", Namespace: "my-ns", + } + profile := profiledefinition.ProfileDefinition{ Metadata: profiledefinition.MetadataConfig{ "device": { Fields: map[string]profiledefinition.MetadataField{ @@ -612,7 +626,7 @@ func Test_metricSender_reportNetworkDeviceMetadata_pingCanConnect_True(t *testin collectTime, err := time.Parse(layout, str) assert.NoError(t, err) - ms.ReportNetworkDeviceMetadata(config, emptyMetadataStore, []string{"tag1", "tag2"}, collectTime, metadata.DeviceStatusReachable, metadata.DeviceStatusUnreachable, nil) + ms.ReportNetworkDeviceMetadata(config, profile, emptyMetadataStore, []string{"tag1", "tag2"}, collectTime, metadata.DeviceStatusReachable, metadata.DeviceStatusUnreachable, nil) // language=json event := []byte(` @@ -665,6 +679,8 @@ func Test_metricSender_reportNetworkDeviceMetadata_pingCanConnect_False(t *testi DeviceIDTags: []string{"device_name:127.0.0.1"}, ResolvedSubnetName: "127.0.0.0/29", Namespace: "my-ns", + } + profile := profiledefinition.ProfileDefinition{ Metadata: profiledefinition.MetadataConfig{ "device": { Fields: map[string]profiledefinition.MetadataField{ @@ -684,7 +700,7 @@ func Test_metricSender_reportNetworkDeviceMetadata_pingCanConnect_False(t *testi collectTime, err := time.Parse(layout, str) assert.NoError(t, err) - ms.ReportNetworkDeviceMetadata(config, emptyMetadataStore, []string{"tag1", "tag2"}, collectTime, metadata.DeviceStatusReachable, metadata.DeviceStatusUnreachable, nil) + ms.ReportNetworkDeviceMetadata(config, profile, emptyMetadataStore, []string{"tag1", "tag2"}, collectTime, metadata.DeviceStatusReachable, metadata.DeviceStatusUnreachable, nil) // language=json event := []byte(` @@ -964,37 +980,3 @@ func Test_buildInterfaceIndexByIDType(t *testing.T) { } assert.Equal(t, expectedInterfaceIndexByIDType, interfaceIndexByIDType) } - -func Test_getProfileVersion(t *testing.T) { - tests := []struct { - name string - config checkconfig.CheckConfig - expectedProfileVersion uint64 - }{ - { - name: "profile definition is present", - config: checkconfig.CheckConfig{ - ProfileName: "my-profile", - ProfileProvider: profile.StaticProvider(profile.ProfileConfigMap{ - "my-profile": profile.ProfileConfig{ - Definition: profiledefinition.ProfileDefinition{ - Name: "my-profile", - Version: 42, - }, - }, - }), - }, - expectedProfileVersion: 42, - }, - { - name: "profile definition not present", - config: checkconfig.CheckConfig{}, - expectedProfileVersion: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert.Equal(t, tt.expectedProfileVersion, getProfileVersion(&tt.config)) - }) - } -} From f9e107b72b01d63ebb7947b5130a301efc824627 Mon Sep 17 00:00:00 2001 From: Daniel Lepage Date: Sat, 14 Dec 2024 12:41:46 -0500 Subject: [PATCH 4/5] Cache the latest profile in devicecheck. --- .../snmp/internal/devicecheck/devicecheck.go | 120 ++++++++++++++---- .../internal/devicecheck/devicecheck_test.go | 28 ++-- 2 files changed, 108 insertions(+), 40 deletions(-) diff --git a/pkg/collector/corechecks/snmp/internal/devicecheck/devicecheck.go b/pkg/collector/corechecks/snmp/internal/devicecheck/devicecheck.go index d23d5642a2470..12df975fa8812 100644 --- a/pkg/collector/corechecks/snmp/internal/devicecheck/devicecheck.go +++ b/pkg/collector/corechecks/snmp/internal/devicecheck/devicecheck.go @@ -10,6 +10,7 @@ import ( "encoding/json" "errors" "fmt" + "github.com/DataDog/datadog-agent/pkg/networkdevice/profile/profiledefinition" "reflect" "runtime" "strings" @@ -55,6 +56,60 @@ const ( checkDurationThreshold = 30 // Thirty seconds ) +type profileCache struct { + sysObjectID string + timestamp time.Time + profile *profiledefinition.ProfileDefinition + err error + scalarOIDs []string + columnOIDs []string +} + +// GetProfile returns the cached profile, or an empty profile if the cache is empty. +// Use this when you need to make sure you have *some* profile. +func (pc *profileCache) GetProfile() profiledefinition.ProfileDefinition { + if pc.profile == nil { + return profiledefinition.ProfileDefinition{ + Metadata: make(profiledefinition.MetadataConfig), + } + } + return *pc.profile +} + +func (pc *profileCache) Update(sysObjectID string, now time.Time, config *checkconfig.CheckConfig) (profiledefinition.ProfileDefinition, error) { + if pc.IsOutdated(sysObjectID, config.ProfileName, config.ProfileProvider.LastUpdated()) { + // we cache the value even if there's an error, because an error indicates that + // the ProfileProvider couldn't find a match for either config.ProfileName or + // the given sysObjectID, and we're going to have the same error if we call this + // again without either the sysObjectID or the ProfileProvider changing. + pc.sysObjectID = sysObjectID + pc.timestamp = now + profile, err := config.BuildProfile(sysObjectID) + pc.profile = &profile + pc.err = err + pc.scalarOIDs, pc.columnOIDs = pc.profile.SplitOIDs(config.CollectDeviceMetadata) + } + return pc.GetProfile(), pc.err +} + +func (pc *profileCache) IsOutdated(sysObjectID string, profileName string, lastUpdate time.Time) bool { + if pc.profile == nil { + return true + } + if profileName == checkconfig.ProfileNameInline { + // inline profiles never change, so if we have a profile it's up-to-date. + return false + } + if profileName == checkconfig.ProfileNameAuto && pc.sysObjectID != sysObjectID { + // If we're auto-detecting profiles and the sysObjectID has changed, we're out of date. + return true + } + // If we get here then either we're auto-detecting but the sysobjectid hasn't + // changed, or we have a static name; either way we're out of date if and only + // if the profile provider has updated. + return pc.timestamp.Before(lastUpdate) +} + // DeviceCheck hold info necessary to collect info for a single device type DeviceCheck struct { config *checkconfig.CheckConfig @@ -68,6 +123,7 @@ type DeviceCheck struct { interfaceBandwidthState report.InterfaceBandwidthState cacheKey string agentConfig config.Component + profileCache profileCache } const cacheKeyPrefix = "snmp-tags" @@ -100,6 +156,10 @@ func NewDeviceCheck(config *checkconfig.CheckConfig, ipAddress string, sessionFa } d.readTagsFromCache() + if _, err := d.profileCache.Update("", time.Now(), d.config); err != nil { + // This could happen e.g. if the config references a profile that hasn't been loaded yet. + _ = log.Warnf("failed to refresh profile cache: %s", err) + } return &d, nil } @@ -163,7 +223,7 @@ func (d *DeviceCheck) Run(collectionTime time.Time) error { var deviceStatus metadata.DeviceStatus var pingStatus metadata.DeviceStatus - deviceReachable, dynamicTags, values, checkErr := d.getValuesAndTags() + deviceReachable, profile, dynamicTags, values, checkErr := d.getValuesAndTags() tags := utils.CopyStrings(staticTags) if checkErr != nil { @@ -183,7 +243,7 @@ func (d *DeviceCheck) Run(collectionTime time.Time) error { d.sender.Gauge(deviceReachableMetric, utils.BoolToFloat64(deviceReachable), metricTags) d.sender.Gauge(deviceUnreachableMetric, utils.BoolToFloat64(!deviceReachable), metricTags) if values != nil { - d.sender.ReportMetrics(d.config.Metrics, values, metricTags, d.config.DeviceID) + d.sender.ReportMetrics(profile.Metrics, values, metricTags, d.config.DeviceID) } // Get a system appropriate ping check @@ -232,7 +292,8 @@ func (d *DeviceCheck) Run(collectionTime time.Time) error { deviceDiagnosis := d.diagnoses.Report() - d.sender.ReportNetworkDeviceMetadata(d.config, values, deviceMetadataTags, collectionTime, deviceStatus, pingStatus, deviceDiagnosis) + d.sender.ReportNetworkDeviceMetadata(d.config, profile, values, deviceMetadataTags, collectionTime, + deviceStatus, pingStatus, deviceDiagnosis) } d.submitTelemetryMetrics(startTime, metricTags) @@ -260,7 +321,11 @@ func (d *DeviceCheck) buildExternalTags() []string { return agentTags } -func (d *DeviceCheck) getValuesAndTags() (bool, []string, *valuestore.ResultValueStore, error) { +// getValuesAndTags build (or fetches from cache) a profile describing all the +// metrics, tags, etc. to be fetched for this device, fetches the resulting +// values, and returns (reachable, profile, tags, values, error). In the event +// of an error, the returned profile will be the last cached profile. +func (d *DeviceCheck) getValuesAndTags() (bool, profiledefinition.ProfileDefinition, []string, *valuestore.ResultValueStore, error) { var deviceReachable bool var checkErrors []string var tags []string @@ -269,7 +334,8 @@ func (d *DeviceCheck) getValuesAndTags() (bool, []string, *valuestore.ResultValu connErr := d.session.Connect() if connErr != nil { d.diagnoses.Add("error", "SNMP_FAILED_TO_OPEN_CONNECTION", "Agent failed to open connection.") - return false, tags, nil, fmt.Errorf("snmp connection error: %s", connErr) + // cannot connect -> use cached profile + return false, d.profileCache.GetProfile(), tags, nil, fmt.Errorf("snmp connection error: %s", connErr) } defer func() { err := d.session.Close() @@ -292,15 +358,16 @@ func (d *DeviceCheck) getValuesAndTags() (bool, []string, *valuestore.ResultValu } } - err = d.detectMetricsToMonitor(d.session) + profile, err := d.detectMetricsToMonitor(d.session) if err != nil { d.diagnoses.Add("error", "SNMP_FAILED_TO_DETECT_PROFILE", "Agent failed to detect a profile for this network device.") checkErrors = append(checkErrors, fmt.Sprintf("failed to autodetect profile: %s", err)) } - tags = append(tags, d.config.ProfileTags...) + tags = append(tags, profile.StaticTags...) - valuesStore, err := fetch.Fetch(d.session, d.config) + valuesStore, err := fetch.Fetch(d.session, d.profileCache.scalarOIDs, d.profileCache.columnOIDs, d.config.OidBatchSize, + d.config.BulkMaxRepetitions) if log.ShouldLog(log.DebugLvl) { log.Debugf("fetched values: %v", valuestore.ResultValueStoreAsString(valuesStore)) } @@ -308,37 +375,38 @@ func (d *DeviceCheck) getValuesAndTags() (bool, []string, *valuestore.ResultValu if err != nil { checkErrors = append(checkErrors, fmt.Sprintf("failed to fetch values: %s", err)) } else { - tags = append(tags, d.sender.GetCheckInstanceMetricTags(d.config.MetricTags, valuesStore)...) + tags = append(tags, d.sender.GetCheckInstanceMetricTags(profile.MetricTags, valuesStore)...) } var joinedError error if len(checkErrors) > 0 { joinedError = errors.New(strings.Join(checkErrors, "; ")) } - return deviceReachable, tags, valuesStore, joinedError + return deviceReachable, profile, tags, valuesStore, joinedError } -func (d *DeviceCheck) detectMetricsToMonitor(sess session.Session) error { - if d.config.AutodetectProfile { +func (d *DeviceCheck) getSysObjectID(sess session.Session) (string, error) { + if d.config.ProfileName == checkconfig.ProfileNameAuto { // detect using sysObjectID sysObjectID, err := session.FetchSysObjectID(sess) if err != nil { - return fmt.Errorf("failed to fetch sysobjectid: %s", err) - } - profile, err := d.config.ProfileProvider.GetProfileNameForSysObjectID(sysObjectID) - if err != nil { - return fmt.Errorf("failed to get profile sys object id for `%s`: %s", sysObjectID, err) - } - if profile != d.config.ProfileName { - log.Debugf("detected profile change: %s -> %s", d.config.ProfileName, profile) - err = d.config.SetProfile(profile) - if err != nil { - // Should not happen since the profile is one of those we matched in GetProfileNameForSysObjectID - return fmt.Errorf("failed to refresh with profile `%s` detected using sysObjectID `%s`: %s", profile, sysObjectID, err) - } + return "", fmt.Errorf("failed to fetch sysobjectid: %w", err) } + return sysObjectID, nil + } + return "", nil +} + +func (d *DeviceCheck) detectMetricsToMonitor(sess session.Session) (profiledefinition.ProfileDefinition, error) { + sysObjectID, err := d.getSysObjectID(sess) + if err != nil { + return d.profileCache.GetProfile(), err + } + profile, err := d.profileCache.Update(sysObjectID, time.Now(), d.config) + if err != nil { + return profile, fmt.Errorf("failed to refresh profile cache: %w", err) } - return nil + return profile, nil } func (d *DeviceCheck) submitTelemetryMetrics(startTime time.Time, tags []string) { diff --git a/pkg/collector/corechecks/snmp/internal/devicecheck/devicecheck_test.go b/pkg/collector/corechecks/snmp/internal/devicecheck/devicecheck_test.go index 1e7ad7fc7a001..27fe5f81951e0 100644 --- a/pkg/collector/corechecks/snmp/internal/devicecheck/devicecheck_test.go +++ b/pkg/collector/corechecks/snmp/internal/devicecheck/devicecheck_test.go @@ -70,7 +70,7 @@ profiles: deviceCk.SetSender(report.NewMetricSender(sender, "", nil, report.MakeInterfaceBandwidthState())) - (sess. + sess. SetStr("1.3.6.1.2.1.1.1.0", "my_desc"). SetObj("1.3.6.1.2.1.1.2.0", "1.3.6.1.4.1.3375.2.1.3.4.1"). SetTime("1.3.6.1.2.1.1.3.0", 20). @@ -96,7 +96,7 @@ profiles: // f5-specific sysStatMemoryTotal SetInt("1.3.6.1.4.1.3375.2.1.1.2.1.44.0", 30). // Fake metric specific to another_profile - SetInt("1.3.6.1.2.1.1.999.0", 100)) + SetInt("1.3.6.1.2.1.1.999.0", 100) err = deviceCk.Run(time.Now()) assert.Nil(t, err) @@ -133,8 +133,8 @@ profiles: sender.AssertMetricNotTaggedWith(t, "Gauge", "snmp.sysStatMemoryTotal", []string{"unknown_symbol:100"}) // f5 has 5 metrics, 2 tags - assert.Len(t, deviceCk.config.Metrics, 5) - assert.Len(t, deviceCk.config.MetricTags, 2) + assert.Len(t, deviceCk.profileCache.profile.Metrics, 5) + assert.Len(t, deviceCk.profileCache.profile.MetricTags, 2) sender.ResetCalls() @@ -164,8 +164,8 @@ profiles: sender.AssertMetricNotTaggedWith(t, "Gauge", "snmp.anotherMetric", []string{"some_tag:some_tag_value"}) // Check that we replaced the metrics, instead of just adding to them - assert.Len(t, deviceCk.config.Metrics, 2) - assert.Len(t, deviceCk.config.MetricTags, 2) + assert.Len(t, deviceCk.profileCache.profile.Metrics, 2) + assert.Len(t, deviceCk.profileCache.profile.MetricTags, 2) } func TestProfileDetectionPreservesGlobals(t *testing.T) { @@ -779,8 +779,8 @@ profiles: sender.AssertMetricNotTaggedWith(t, "Gauge", "snmp.sysStatMemoryTotal", []string{"unknown_symbol:100"}) // f5 has 5 metrics, 2 tags - assert.Len(t, deviceCk.config.Metrics, 5) - assert.Len(t, deviceCk.config.MetricTags, 2) + assert.Len(t, deviceCk.profileCache.profile.Metrics, 5) + assert.Len(t, deviceCk.profileCache.profile.MetricTags, 2) sender.ResetCalls() @@ -810,8 +810,8 @@ profiles: sender.AssertMetricNotTaggedWith(t, "Gauge", "snmp.anotherMetric", []string{"some_tag:some_tag_value"}) // Check that we replaced the metrics, instead of just adding to them - assert.Len(t, deviceCk.config.Metrics, 2) - assert.Len(t, deviceCk.config.MetricTags, 2) + assert.Len(t, deviceCk.profileCache.profile.Metrics, 2) + assert.Len(t, deviceCk.profileCache.profile.MetricTags, 2) // Assert Ping Metrics sender.AssertMetric(t, "Gauge", pingReachableMetric, float64(1), "", snmpTags) @@ -926,8 +926,8 @@ profiles: sender.AssertMetricNotTaggedWith(t, "Gauge", "snmp.sysStatMemoryTotal", []string{"unknown_symbol:100"}) // f5 has 5 metrics, 2 tags - assert.Len(t, deviceCk.config.Metrics, 5) - assert.Len(t, deviceCk.config.MetricTags, 2) + assert.Len(t, deviceCk.profileCache.profile.Metrics, 5) + assert.Len(t, deviceCk.profileCache.profile.MetricTags, 2) sender.ResetCalls() @@ -957,8 +957,8 @@ profiles: sender.AssertMetricNotTaggedWith(t, "Gauge", "snmp.anotherMetric", []string{"some_tag:some_tag_value"}) // Check that we replaced the metrics, instead of just adding to them - assert.Len(t, deviceCk.config.Metrics, 2) - assert.Len(t, deviceCk.config.MetricTags, 2) + assert.Len(t, deviceCk.profileCache.profile.Metrics, 2) + assert.Len(t, deviceCk.profileCache.profile.MetricTags, 2) // Assert Ping reachability metrics are sent sender.AssertMetric(t, "Gauge", pingReachableMetric, float64(0), "", snmpTags) From 1995d92bf571e68c1236a1dd504928b9931c65a8 Mon Sep 17 00:00:00 2001 From: Daniel Lepage Date: Sat, 14 Dec 2024 15:52:21 -0500 Subject: [PATCH 5/5] Provide empty ProfileProviders in discovery tests. --- .../corechecks/snmp/internal/discovery/discovery_test.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pkg/collector/corechecks/snmp/internal/discovery/discovery_test.go b/pkg/collector/corechecks/snmp/internal/discovery/discovery_test.go index 4ca8ccc302bf2..c4aa83a01a663 100644 --- a/pkg/collector/corechecks/snmp/internal/discovery/discovery_test.go +++ b/pkg/collector/corechecks/snmp/internal/discovery/discovery_test.go @@ -7,6 +7,7 @@ package discovery import ( "fmt" + "github.com/DataDog/datadog-agent/pkg/collector/corechecks/snmp/internal/profile" "net" "testing" "time" @@ -57,6 +58,7 @@ func TestDiscovery(t *testing.T) { DiscoveryInterval: 3600, DiscoveryWorkers: 1, IgnoredIPAddresses: map[string]bool{"192.168.0.5": true}, + ProfileProvider: profile.StaticProvider(nil), } discovery := NewDiscovery(checkConfig, sessionFactory, config) discovery.Start() @@ -107,6 +109,7 @@ func TestDiscoveryCache(t *testing.T) { CommunityString: "public", DiscoveryInterval: 3600, DiscoveryWorkers: 1, + ProfileProvider: profile.StaticProvider(nil), } discovery := NewDiscovery(checkConfig, sessionFactory, config) discovery.Start() @@ -139,6 +142,7 @@ func TestDiscoveryCache(t *testing.T) { CommunityString: "public", DiscoveryInterval: 3600, DiscoveryWorkers: 0, // no workers, the devices will be loaded from cache + ProfileProvider: profile.StaticProvider(nil), } discovery2 := NewDiscovery(checkConfig, sessionFactory, config) discovery2.Start() @@ -181,6 +185,7 @@ func TestDiscoveryTicker(t *testing.T) { CommunityString: "public", DiscoveryInterval: 1, DiscoveryWorkers: 1, + ProfileProvider: profile.StaticProvider(nil), } discovery := NewDiscovery(checkConfig, sessionFactory, config) discovery.Start() @@ -200,6 +205,7 @@ func TestDiscovery_checkDevice(t *testing.T) { CommunityString: "public", DiscoveryInterval: 1, DiscoveryWorkers: 1, + ProfileProvider: profile.StaticProvider(nil), } ipAddr, ipNet, err := net.ParseCIDR(checkConfig.Network) assert.Nil(t, err) @@ -319,6 +325,7 @@ func TestDiscovery_createDevice(t *testing.T) { DiscoveryWorkers: 1, DiscoveryAllowedFailures: 3, Namespace: "default", + ProfileProvider: profile.StaticProvider(nil), } discovery := NewDiscovery(checkConfig, session.NewMockSession, config) ipAddr, ipNet, err := net.ParseCIDR(checkConfig.Network)