-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
870d467
commit ec49b99
Showing
13 changed files
with
689 additions
and
843 deletions.
There are no files selected for viewing
74 changes: 74 additions & 0 deletions
74
pkg/collector/corechecks/snmp/internal/checkconfig/buildprofile.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 rootProfile *profiledefinition.ProfileDefinition | ||
var profileErr error | ||
|
||
switch c.ProfileName { | ||
case ProfileNameInline: // inline profile -> no parent | ||
rootProfile = 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 { | ||
rootProfile = &profileConfig.Definition | ||
log.Debugf("detected profile %q for sysobjectid %q", rootProfile.Name, sysObjectID) | ||
} | ||
} | ||
default: | ||
if profile := c.ProfileProvider.GetProfile(c.ProfileName); profile == nil { | ||
profileErr = fmt.Errorf("unknown profile %q", c.ProfileName) | ||
} else { | ||
rootProfile = &profile.Definition | ||
} | ||
} | ||
|
||
profile := *profiledefinition.NewProfileDefinition() | ||
profile.Metrics = slices.Clone(c.RequestedMetrics) | ||
profile.MetricTags = slices.Clone(c.RequestedMetricTags) | ||
if rootProfile != nil { | ||
profile.Name = rootProfile.Name | ||
profile.Version = rootProfile.Version | ||
profile.StaticTags = append(profile.StaticTags, "snmp_profile:"+rootProfile.Name) | ||
vendor := rootProfile.GetVendor() | ||
if vendor != "" { | ||
profile.StaticTags = append(profile.StaticTags, "device_vendor:"+vendor) | ||
} | ||
profile.StaticTags = append(profile.StaticTags, rootProfile.StaticTags...) | ||
profile.Metadata = rootProfile.Metadata | ||
profile.Metrics = append(profile.Metrics, rootProfile.Metrics...) | ||
profile.MetricTags = append(profile.MetricTags, rootProfile.MetricTags...) | ||
} | ||
profile.Metadata = updateMetadataDefinitionWithDefaults(profile.Metadata, c.CollectTopology) | ||
|
||
return profile, profileErr | ||
} |
226 changes: 226 additions & 0 deletions
226
pkg/collector/corechecks/snmp/internal/checkconfig/buildprofile_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
} | ||
} | ||
} | ||
}) | ||
} | ||
} |
Oops, something went wrong.