chore(go.d/snmp/ddsnmp): use dd profile definition (#19886)
Ilya Mashchenko committed
Mar 17, 2025 at 15:38 UTC
9e0fa763554486acc19b63f74e393070f552d737
6 files changed
+178
-141
src/go/go.mod
+7
-2
@@ -6,6 +6,7 @@ replace github.com/prometheus/prometheus => github.com/prometheus/prometheus v0.
6
7
require (
8
github.com/DATA-DOG/go-sqlmock v1.5.2
9
+ github.com/DataDog/datadog-agent/pkg/networkdevice/profile v0.65.0-devel.0.20250317105920-ce55f088ab29
10
github.com/Masterminds/sprig/v3 v3.3.0
11
github.com/Wing924/ltsv v0.4.0
12
github.com/apparentlymart/go-cidr v1.1.0
@@ -72,6 +73,8 @@ require (
73
github.com/Masterminds/goutils v1.1.1 // indirect
74
github.com/Masterminds/semver/v3 v3.3.0 // indirect
75
github.com/Microsoft/go-winio v0.6.1 // indirect
76
+ github.com/bahlo/generic-list-go v0.2.0 // indirect
77
+ github.com/buger/jsonparser v1.1.1 // indirect
78
github.com/cespare/xxhash/v2 v2.3.0 // indirect
79
github.com/containerd/log v0.1.0 // indirect
80
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
@@ -99,6 +102,7 @@ require (
102
github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect
103
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect
104
github.com/huandu/xstrings v1.5.0 // indirect
105
+ github.com/invopop/jsonschema v0.12.0 // indirect
106
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
107
github.com/jackc/pgconn v1.14.3 // indirect
108
github.com/jackc/pgio v1.0.0 // indirect
@@ -113,7 +117,7 @@ require (
117
github.com/kamstrup/intmap v0.5.1 // indirect
118
github.com/klauspost/compress v1.17.11 // indirect
119
github.com/likexian/gokit v0.25.15 // indirect
116
- github.com/mailru/easyjson v0.7.7 // indirect
120
+ github.com/mailru/easyjson v0.9.0 // indirect
121
github.com/mdlayher/genetlink v1.3.2 // indirect
122
github.com/mdlayher/netlink v1.7.2 // indirect
123
github.com/mdlayher/socket v0.4.1 // indirect
@@ -133,9 +137,10 @@ require (
137
github.com/shopspring/decimal v1.4.0 // indirect
138
github.com/sirupsen/logrus v1.9.3 // indirect
139
github.com/spf13/cast v1.7.0 // indirect
136
- github.com/spf13/pflag v1.0.5 // indirect
140
+ github.com/spf13/pflag v1.0.6 // indirect
141
github.com/tidwall/match v1.1.1 // indirect
142
github.com/tidwall/pretty v1.2.0 // indirect
143
+ github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
144
github.com/x448/float16 v0.8.4 // indirect
145
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
146
github.com/xdg-go/scram v1.1.2 // indirect
src/go/go.sum
+14
-4
@@ -24,6 +24,8 @@ github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2/go.mod h1:wP83
24
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
25
github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
26
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
27
+github.com/DataDog/datadog-agent/pkg/networkdevice/profile v0.65.0-devel.0.20250317105920-ce55f088ab29 h1:iaMpL007/uujrcE8kQyrmB4rfu+nW8Ugh82CI5Vwbos=
28
+github.com/DataDog/datadog-agent/pkg/networkdevice/profile v0.65.0-devel.0.20250317105920-ce55f088ab29/go.mod h1:BkwwzS9aVK+QQb9E+fF9q9ZYScH3Xvnt2dKcE5ZJbMw=
29
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
30
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
31
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
@@ -47,6 +49,8 @@ github.com/aws/aws-sdk-go v1.55.6 h1:cSg4pvZ3m8dgYcgqB97MrcdjUmZ1BeMYKUxMMB89IPk
49
github.com/aws/aws-sdk-go v1.55.6/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
50
github.com/axiomhq/hyperloglog v0.2.5 h1:Hefy3i8nAs8zAI/tDp+wE7N+Ltr8JnwiW3875pvl0N8=
51
github.com/axiomhq/hyperloglog v0.2.5/go.mod h1:DLUK9yIzpU5B6YFLjxTIcbHu1g4Y1WQb1m5RH3radaM=
52
+github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
53
+github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
54
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
55
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
56
github.com/bitly/go-hostpool v0.1.0 h1:XKmsF6k5el6xHG3WPJ8U0Ku/ye7njX7W81Ng7O2ioR0=
@@ -61,6 +65,8 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
65
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
66
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
67
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
68
+github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
69
+github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
70
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
71
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
72
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
@@ -192,6 +198,8 @@ github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
198
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
199
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
200
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
201
+github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI=
202
+github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
203
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
204
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
205
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
@@ -302,8 +310,8 @@ github.com/likexian/whois-parser v1.24.20 h1:oxEkRi0GxgqWQRLDMJpXU1EhgWmLmkqEFZ2
310
github.com/likexian/whois-parser v1.24.20/go.mod h1:rAtaofg2luol09H+ogDzGIfcG8ig1NtM5R16uQADDz4=
311
github.com/lmittmann/tint v1.0.7 h1:D/0OqWZ0YOGZ6AyC+5Y2kD8PBEzBk6rFHVSfOqCkF9Y=
312
github.com/lmittmann/tint v1.0.7/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
305
-github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
306
-github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
313
+github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
314
+github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
315
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
316
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
317
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
@@ -413,8 +421,8 @@ github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9yS
421
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
422
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
423
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
416
-github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
417
-github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
424
+github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
425
+github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
426
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
427
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
428
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
@@ -442,6 +450,8 @@ github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXV
450
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
451
github.com/vmware/govmomi v0.49.0 h1:M80ExmFq3kOfeMvMJcHnXgA/4w5hUAFfYfc+Qm3lmPg=
452
github.com/vmware/govmomi v0.49.0/go.mod h1:+oZ0tYJw/pXKoeWHLR9Egq5KENVr2hLePRzisFhEWpA=
453
+github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
454
+github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
455
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
456
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
457
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
src/go/plugin/go.d/collector/snmp/ddsnmp/load.go
+20
-24
@@ -9,8 +9,12 @@ import (
9
"strings"
10
11
"gopkg.in/yaml.v2"
12
+
13
+ "github.com/netdata/netdata/go/plugins/logger"
14
)
15
16
+var log = logger.New().With("component", "snmp/ddsnmp")
17
+
18
func load(dirpath string) ([]*Profile, error) {
19
var profiles []*Profile
20
@@ -18,10 +22,18 @@ func load(dirpath string) ([]*Profile, error) {
22
if !(strings.HasSuffix(path, ".yaml") || strings.HasSuffix(path, ".yml")) {
23
return nil
24
}
21
- profile, err := loadYAML(path)
25
+
26
+ profile, err := loadProfile(path)
27
if err != nil {
23
- return err
28
+ log.Warningf("invalid profile '%s': %v", path, err)
29
+ return nil
30
}
31
+
32
+ if err := profile.validate(); err != nil {
33
+ log.Warningf("invalid profile '%s': %v", path, err)
34
+ return nil
35
+ }
36
+
37
profiles = append(profiles, profile)
38
return nil
39
}); err != nil {
@@ -31,14 +43,14 @@ func load(dirpath string) ([]*Profile, error) {
43
return profiles, nil
44
}
45
34
-func loadYAML(filename string) (*Profile, error) {
46
+func loadProfile(filename string) (*Profile, error) {
47
content, err := os.ReadFile(filename)
48
if err != nil {
49
return nil, err
50
}
51
52
var prof Profile
41
- if err := yaml.Unmarshal(content, &prof); err != nil {
53
+ if err := yaml.Unmarshal(content, &prof.Definition); err != nil {
54
return nil, err
55
}
56
@@ -48,30 +60,14 @@ func loadYAML(filename string) (*Profile, error) {
60
61
dir := filepath.Dir(filename)
62
51
- for _, name := range prof.Extends {
52
- baseProf, err := loadYAML(filepath.Join(dir, name))
63
+ for _, name := range prof.Definition.Extends {
64
+ baseProf, err := loadProfile(filepath.Join(dir, name))
65
if err != nil {
66
return nil, err
67
}
56
- mergeProfiles(&prof, baseProf)
68
+
69
+ prof.merge(baseProf)
70
}
71
72
return &prof, nil
73
}
61
-
62
-func mergeProfiles(child, parent *Profile) {
63
- child.Metrics = append(parent.Metrics, child.Metrics...)
64
- //
65
- //if child.Metadata == nil || len(child.Metadata.Device) == 0 {
66
- // return
67
- //}
68
- //if child.Metadata.Device.Fields == nil {
69
- // child.Metadata.Device.Fields = make(map[string]Symbol)
70
- //}
71
- //
72
- //for key, value := range parent.Metadata.Device.Fields {
73
- // if _, exists := child.Metadata.Device.Fields[key]; !exists {
74
- // child.Metadata.Device.Fields[key] = value
75
- // }
76
- //}
77
-}
src/go/plugin/go.d/collector/snmp/ddsnmp/load_test.go
+3
-3
@@ -4,14 +4,14 @@ package ddsnmp
4
5
import (
6
"os"
7
+ "path/filepath"
8
"testing"
9
9
- "github.com/stretchr/testify/assert"
10
"github.com/stretchr/testify/require"
11
)
12
13
func Test_loadDDSnmpProfiles(t *testing.T) {
14
- dir := "../../../config/go.d/snmp.profiles/default"
14
+ dir, _ := filepath.Abs("../../../config/go.d/snmp.profiles/default")
15
16
f, err := os.Open(dir)
17
require.NoError(t, err)
@@ -23,5 +23,5 @@ func Test_loadDDSnmpProfiles(t *testing.T) {
23
names, err := f.Readdirnames(-1)
24
require.NoError(t, err)
25
26
- assert.Equal(t, len(names)-1 /*README.md*/, len(profiles))
26
+ require.Equal(t, len(names)-1 /*README.md*/, len(profiles))
27
}
src/go/plugin/go.d/collector/snmp/ddsnmp/profile.go
+91
-108
@@ -3,131 +3,114 @@
3
package ddsnmp
4
5
import (
6
- "fmt"
7
-)
6
+ "errors"
7
+ "os"
8
+ "path/filepath"
9
+ "sync"
10
+
11
+ "github.com/DataDog/datadog-agent/pkg/networkdevice/profile/profiledefinition"
12
9
-const (
10
- MetricTypeGauge = "gauge"
11
- MetricTypeRate = "rate"
12
- MetricTypePercent = "percent"
13
- MetricTypeMonotonicCount = "monotonic_count"
14
- MetricTypeMonotonicCountAndRate = "monotonic_count_and_rate"
15
- MetricTypeFlagStream = "flag_stream" // https://datadoghq.dev/integrations-core/tutorials/snmp/profile-format/#flag-stream
13
+ "github.com/netdata/netdata/go/plugins/pkg/executable"
14
+ "github.com/netdata/netdata/go/plugins/pkg/matcher"
15
)
16
18
-// Profile is Datadog SNMP profile (format: https://datadoghq.dev/integrations-core/tutorials/snmp/profile-format/)
19
-type Profile struct {
20
- SourceFile string
17
+var once sync.Once
18
+var ddProfiles []*Profile
19
+
20
+func Find(sysObjId string) []*Profile {
21
+ once.Do(func() {
22
+ dir := os.Getenv("NETDATA_STOCK_CONFIG_DIR")
23
+ if dir == "" {
24
+ dir = filepath.Join(executable.Directory, "../../../../usr/lib/netdata/conf.d/go.d/snmp.profiles/default/")
25
+ }
26
+
27
+ profiles, err := load(dir)
28
+ if err != nil {
29
+ log.Errorf("failed to load dd snmp profiles: %v", err)
30
+ return
31
+ }
32
+ if len(profiles) == 0 {
33
+ log.Warningf("no dd snmp profiles found in '%s'", dir)
34
+ return
35
+ }
36
+
37
+ ddProfiles = profiles
38
+ })
39
+
40
+ var profiles []*Profile
41
+
42
+ for _, prof := range ddProfiles {
43
+ for _, id := range prof.Definition.SysObjectIDs {
44
+ m, err := matcher.NewRegExpMatcher(id)
45
+ if err != nil {
46
+ log.Warningf("failed to compile regular expression from '%s': %v", id, err)
47
+ continue
48
+ }
49
+ if m.MatchString(sysObjId) {
50
+ profiles = append(profiles, prof.clone())
51
+ }
52
+ }
53
+ }
54
22
- Extends []string `yaml:"extends"` // +done
23
- SysObjectID SysObjectIDs `yaml:"sysobjectid"` // +done
24
- Metrics []Metric `yaml:"metrics"`
25
- Metadata *Metadata `yaml:"metadata"` // +done
26
- MetricTags []GlobalMetricTag `yaml:"metric_tags"` // +done
55
+ return profiles
56
}
57
29
-type SysObjectIDs []string
58
+type Profile struct {
59
+ SourceFile string `yaml:"-"`
60
+ Definition *profiledefinition.ProfileDefinition `yaml:",inline"`
61
+}
62
31
-type (
32
- // Metric defines which metrics will be collected by the profile.
33
- // Can reference either a single OID (a.k.a symbol), or an SNMP table.
34
- // https://datadoghq.dev/integrations-core/tutorials/snmp/profile-format/#metrics
35
- Metric struct {
36
- Name string `yaml:"name"`
37
- OID string `yaml:"OID"`
63
+func (p *Profile) clone() *Profile {
64
+ return &Profile{
65
+ SourceFile: p.SourceFile,
66
+ Definition: p.Definition.Clone(),
67
+ }
68
+}
69
39
- // Typically a symbol will be inferred from the SNMP type
40
- // https://datadoghq.dev/integrations-core/tutorials/snmp/profile-format/#metric-type-inference
41
- // Can be overwritten using "metric_type"
42
- // https://datadoghq.dev/integrations-core/tutorials/snmp/profile-format/#forced-metric-types
43
- MetricType string `yaml:"metric_type"`
70
+func (p *Profile) merge(base *Profile) {
71
+ p.Definition.Metrics = append(p.Definition.Metrics, base.Definition.Metrics...)
72
+ p.Definition.MetricTags = append(p.Definition.MetricTags, base.Definition.MetricTags...)
73
+ p.Definition.StaticTags = append(p.Definition.StaticTags, base.Definition.StaticTags...)
74
45
- Options map[string]string
75
+ if p.Definition.Metadata == nil {
76
+ p.Definition.Metadata = make(profiledefinition.MetadataConfig)
77
+ }
78
47
- MIB string `yaml:"MIB"`
79
+ for resName, baseRes := range base.Definition.Metadata {
80
+ targetRes, exists := p.Definition.Metadata[resName]
81
+ if !exists {
82
+ targetRes = profiledefinition.NewMetadataResourceConfig()
83
+ }
84
49
- // Symbol metric
50
- // https://datadoghq.dev/integrations-core/tutorials/snmp/profile-format/#symbol-metrics
51
- Symbol *Symbol `yaml:"symbol"`
85
+ targetRes.IDTags = append(targetRes.IDTags, baseRes.IDTags...)
86
53
- // Table metric
54
- // https://datadoghq.dev/integrations-core/tutorials/snmp/profile-format/#table-metrics
55
- Table *MetricTable `yaml:"table"`
56
- Symbols []Symbol `yaml:"symbols"`
87
+ if targetRes.Fields == nil && len(baseRes.Fields) > 0 {
88
+ targetRes.Fields = make(map[string]profiledefinition.MetadataField, len(baseRes.Fields))
89
+ }
90
58
- MetricTags []MetricTag `yaml:"metric_tags"` //TODO check for only name existing in metric tag, as there is some case for that
59
- }
60
- MetricTable struct {
61
- OID string `yaml:"OID"`
62
- Name string `yaml:"name"`
63
- }
64
- // MetricTag used for Table metrics to identify each row's metric.
65
- // https://datadoghq.dev/integrations-core/tutorials/snmp/profile-format/#table-metrics-tagging
66
- MetricTag struct {
67
- MIB string `yaml:"mib"`
68
- Table string `yaml:"table"`
69
- Tag string `yaml:"tag"`
70
- Symbol Symbol `yaml:"symbol"`
71
- IndexTransform []IndexSlice `yaml:"index_transform"`
72
-
73
- Mapping map[int]string `yaml:"mapping"`
74
- Index int `yaml:"index"`
75
- }
76
- Symbol struct {
77
- OID string `yaml:"OID"`
78
- Name string `yaml:"name"`
79
- ExtractValue string `yaml:"extract_value"`
80
- MatchPattern string `yaml:"match_pattern"`
81
- MatchValue string `yaml:"match_value"`
82
- Format string `yaml:"format"`
83
- ScaleFactor float64 `yaml:"scale_factor"`
84
- }
85
- IndexSlice struct {
86
- Start int `yaml:"start"`
87
- End int `yaml:"end"`
88
- }
89
-)
91
+ for field, symbol := range baseRes.Fields {
92
+ if _, ok := targetRes.Fields[field]; !ok {
93
+ targetRes.Fields[field] = symbol
94
+ }
95
+ }
96
91
-type (
92
- // Metadata used to declare where and how metadata should be collected
93
- // https://datadoghq.dev/integrations-core/tutorials/snmp/profile-format/#metadata
94
- Metadata struct {
95
- Device DeviceMetadata `yaml:"device"`
96
- }
97
- DeviceMetadata struct {
98
- Fields map[string]MetadataField `yaml:"fields"`
99
- }
100
- MetadataField struct {
101
- Value *string `yaml:"value"`
102
- Symbol *Symbol `yaml:"symbol"`
103
- Symbols []Symbol `yaml:"symbols"`
97
+ p.Definition.Metadata[resName] = targetRes
98
}
105
-)
106
-
107
-// GlobalMetricTag used to apply tags to all metrics collected by the profile
108
-// https://datadoghq.dev/integrations-core/tutorials/snmp/profile-format/#metric_tags
109
-type GlobalMetricTag struct {
110
- OID string `yaml:"OID"`
111
- Symbol string `yaml:"symbol"`
112
- Tag string `yaml:"tag"`
113
-
114
- Match string `yaml:"match"`
115
- Tags map[string]string `yaml:"tags"`
116
- Mapping map[int]string `yaml:"mapping"`
99
}
100
119
-func (s *SysObjectIDs) UnmarshalYAML(unmarshal func(any) error) error {
120
- var single string
121
- if err := unmarshal(&single); err == nil {
122
- *s = []string{single}
123
- return nil
124
- }
125
-
126
- var multiple []string
127
- if err := unmarshal(&multiple); err == nil {
128
- *s = multiple
129
- return nil
101
+func (p *Profile) validate() error {
102
+ profiledefinition.NormalizeMetrics(p.Definition.Metrics)
103
+
104
+ errs := profiledefinition.ValidateEnrichMetadata(p.Definition.Metadata)
105
+ errs = append(errs, profiledefinition.ValidateEnrichMetrics(p.Definition.Metrics)...)
106
+ errs = append(errs, profiledefinition.ValidateEnrichMetricTags(p.Definition.MetricTags)...)
107
+ if len(errs) > 0 {
108
+ errList := make([]error, 0, len(errs))
109
+ for _, s := range errs {
110
+ errList = append(errList, errors.New(s))
111
+ }
112
+ return errors.Join(errList...)
113
}
114
132
- return fmt.Errorf("invalid sysobjectid format")
115
+ return nil
116
}
src/go/plugin/go.d/collector/snmp/ddsnmp/profile_test.go
new
+43
@@ -0,0 +1,43 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+package ddsnmp
4
+
5
+import (
6
+ "os"
7
+ "path/filepath"
8
+ "testing"
9
+
10
+ "github.com/stretchr/testify/require"
11
+)
12
+
13
+func TestMain(m *testing.M) {
14
+ dir, _ := filepath.Abs("../../../config/go.d/snmp.profiles/default")
15
+ _ = os.Setenv("NETDATA_STOCK_CONFIG_DIR", dir)
16
+ code := m.Run()
17
+ _ = os.Unsetenv("NETDATA_STOCK_CONFIG_DIR")
18
+ os.Exit(code)
19
+}
20
+
21
+func Test_Find(t *testing.T) {
22
+ test := map[string]struct {
23
+ sysObjOId string
24
+ wanProfiles int
25
+ }{
26
+ "mikrotik": {
27
+ sysObjOId: "1.3.6.1.4.1.14988.1",
28
+ wanProfiles: 2,
29
+ },
30
+ "no match": {
31
+ sysObjOId: "0.1.2.3",
32
+ wanProfiles: 0,
33
+ },
34
+ }
35
+
36
+ for name, test := range test {
37
+ t.Run(name, func(t *testing.T) {
38
+ profiles := Find(test.sysObjOId)
39
+
40
+ require.Len(t, profiles, test.wanProfiles)
41
+ })
42
+ }
43
+}