improve(go.d/snmp-profiles): metrics deduplication (#20520)
Ilya Mashchenko committed
Jun 18, 2025 at 23:36 UTC
479a3f92ba06596c75206492c3fc3ec2692e5694
2 files changed
+855
src/go/plugin/go.d/collector/snmp/ddsnmp/profile.go
+84
@@ -4,10 +4,12 @@ package ddsnmp
4
5
import (
6
"errors"
7
+ "fmt"
8
"io/fs"
9
"os"
10
"path/filepath"
11
"slices"
12
+ "sort"
13
"strings"
14
"sync"
15
@@ -65,6 +67,7 @@ func FindProfiles(sysObjId string) []*Profile {
67
}
68
69
enrichProfiles(profiles)
70
+ deduplicateMetricsAcrossProfiles(profiles)
71
72
return profiles
73
}
@@ -272,6 +275,7 @@ func loadProfileExtensions(profile *Profile, dir string, processedExtends map[st
275
}
276
277
func getProfilesDir() string {
278
+ //return "/Users/ilyam/Projects/github/ilyam8/netdata/src/go/plugin/go.d/config/go.d/snmp.profiles/default"
279
if executable.Name == "test" {
280
dir, _ := filepath.Abs("../../../config/go.d/snmp.profiles/default")
281
return dir
@@ -305,3 +309,83 @@ func enrichProfiles(profiles []*Profile) {
309
}
310
}
311
}
312
+
313
+func deduplicateMetricsAcrossProfiles(profiles []*Profile) {
314
+ if len(profiles) < 2 {
315
+ return
316
+ }
317
+
318
+ // Create a slice of indices sorted by priority (non-generic first)
319
+ type indexedProfile struct {
320
+ idx int
321
+ isGeneric bool
322
+ }
323
+
324
+ indexed := make([]indexedProfile, len(profiles))
325
+ for i, prof := range profiles {
326
+ indexed[i] = indexedProfile{
327
+ idx: i,
328
+ isGeneric: strings.Contains(strings.ToLower(prof.SourceFile), "generic-"),
329
+ }
330
+ }
331
+
332
+ slices.SortFunc(indexed, func(a, b indexedProfile) int {
333
+ if a.isGeneric && !b.isGeneric {
334
+ return 1 // a comes after b
335
+ }
336
+ if !a.isGeneric && b.isGeneric {
337
+ return -1 // a comes before b
338
+ }
339
+ // If both are generic or both are non-generic, maintain original order
340
+ return a.idx - b.idx
341
+ })
342
+
343
+ // Reorder profiles slice according to deduplication priority
344
+ sortedProfiles := make([]*Profile, len(profiles))
345
+ for i, ip := range indexed {
346
+ sortedProfiles[i] = profiles[ip.idx]
347
+ }
348
+ copy(profiles, sortedProfiles)
349
+
350
+ seenMetrics := make(map[string]bool)
351
+
352
+ for _, prof := range profiles {
353
+ if prof.Definition == nil {
354
+ continue
355
+ }
356
+
357
+ prof.Definition.Metrics = slices.DeleteFunc(prof.Definition.Metrics, func(metric ddprofiledefinition.MetricsConfig) bool {
358
+ key := generateMetricKey(metric)
359
+ if seenMetrics[key] {
360
+ return true
361
+ }
362
+ seenMetrics[key] = true
363
+ return false
364
+ })
365
+ }
366
+}
367
+
368
+func generateMetricKey(metric ddprofiledefinition.MetricsConfig) string {
369
+ var parts []string
370
+
371
+ if metric.IsScalar() {
372
+ parts = append(parts, "scalar")
373
+ parts = append(parts, metric.Symbol.OID)
374
+ parts = append(parts, metric.Symbol.Name)
375
+ return strings.Join(parts, "|")
376
+ }
377
+
378
+ parts = append(parts, "table")
379
+ parts = append(parts, metric.Table.OID)
380
+ parts = append(parts, metric.Table.Name)
381
+
382
+ symbolKeys := make([]string, 0, len(metric.Symbols))
383
+ for _, sym := range metric.Symbols {
384
+ symbolKey := fmt.Sprintf("%s:%s", sym.OID, sym.Name)
385
+ symbolKeys = append(symbolKeys, symbolKey)
386
+ }
387
+ sort.Strings(symbolKeys)
388
+ parts = append(parts, symbolKeys...)
389
+
390
+ return strings.Join(parts, "|")
391
+}
src/go/plugin/go.d/collector/snmp/ddsnmp/profile_test.go
+771
@@ -11,6 +11,8 @@ import (
11
12
"github.com/stretchr/testify/assert"
13
"github.com/stretchr/testify/require"
14
+
15
+ "github.com/netdata/netdata/go/plugins/plugin/go.d/collector/snmp/ddsnmp/ddprofiledefinition"
16
)
17
18
func Test_loadDDSnmpProfiles(t *testing.T) {
@@ -72,3 +74,772 @@ func Test_Profile_merge(t *testing.T) {
74
}
75
}
76
}
77
+
78
+func TestDeduplicateMetricsAcrossProfiles(t *testing.T) {
79
+ tests := map[string]struct {
80
+ profiles []*Profile
81
+ expected []*Profile
82
+ }{
83
+ "no profiles": {
84
+ profiles: []*Profile{},
85
+ expected: []*Profile{},
86
+ },
87
+ "single profile no duplicates": {
88
+ profiles: []*Profile{
89
+ {
90
+ SourceFile: "profile1.yaml",
91
+ Definition: &ddprofiledefinition.ProfileDefinition{
92
+ Metrics: []ddprofiledefinition.MetricsConfig{
93
+ {
94
+ Symbol: ddprofiledefinition.SymbolConfig{
95
+ OID: "1.3.6.1.2.1.1.3.0",
96
+ Name: "sysUpTime",
97
+ },
98
+ },
99
+ {
100
+ Symbol: ddprofiledefinition.SymbolConfig{
101
+ OID: "1.3.6.1.2.1.1.5.0",
102
+ Name: "sysName",
103
+ },
104
+ },
105
+ },
106
+ },
107
+ },
108
+ },
109
+ expected: []*Profile{
110
+ {
111
+ SourceFile: "profile1.yaml",
112
+ Definition: &ddprofiledefinition.ProfileDefinition{
113
+ Metrics: []ddprofiledefinition.MetricsConfig{
114
+ {
115
+ Symbol: ddprofiledefinition.SymbolConfig{
116
+ OID: "1.3.6.1.2.1.1.3.0",
117
+ Name: "sysUpTime",
118
+ },
119
+ },
120
+ {
121
+ Symbol: ddprofiledefinition.SymbolConfig{
122
+ OID: "1.3.6.1.2.1.1.5.0",
123
+ Name: "sysName",
124
+ },
125
+ },
126
+ },
127
+ },
128
+ },
129
+ },
130
+ },
131
+ "duplicate scalar metrics across profiles": {
132
+ profiles: []*Profile{
133
+ {
134
+ SourceFile: "profile1.yaml",
135
+ Definition: &ddprofiledefinition.ProfileDefinition{
136
+ Metrics: []ddprofiledefinition.MetricsConfig{
137
+ {
138
+ Symbol: ddprofiledefinition.SymbolConfig{
139
+ OID: "1.3.6.1.2.1.1.3.0",
140
+ Name: "sysUpTime",
141
+ },
142
+ },
143
+ },
144
+ },
145
+ },
146
+ {
147
+ SourceFile: "profile2.yaml",
148
+ Definition: &ddprofiledefinition.ProfileDefinition{
149
+ Metrics: []ddprofiledefinition.MetricsConfig{
150
+ {
151
+ Symbol: ddprofiledefinition.SymbolConfig{
152
+ OID: "1.3.6.1.2.1.1.3.0",
153
+ Name: "sysUpTime",
154
+ },
155
+ },
156
+ {
157
+ Symbol: ddprofiledefinition.SymbolConfig{
158
+ OID: "1.3.6.1.2.1.1.5.0",
159
+ Name: "sysName",
160
+ },
161
+ },
162
+ },
163
+ },
164
+ },
165
+ },
166
+ expected: []*Profile{
167
+ {
168
+ SourceFile: "profile1.yaml",
169
+ Definition: &ddprofiledefinition.ProfileDefinition{
170
+ Metrics: []ddprofiledefinition.MetricsConfig{
171
+ {
172
+ Symbol: ddprofiledefinition.SymbolConfig{
173
+ OID: "1.3.6.1.2.1.1.3.0",
174
+ Name: "sysUpTime",
175
+ },
176
+ },
177
+ },
178
+ },
179
+ },
180
+ {
181
+ SourceFile: "profile2.yaml",
182
+ Definition: &ddprofiledefinition.ProfileDefinition{
183
+ Metrics: []ddprofiledefinition.MetricsConfig{
184
+ {
185
+ Symbol: ddprofiledefinition.SymbolConfig{
186
+ OID: "1.3.6.1.2.1.1.5.0",
187
+ Name: "sysName",
188
+ },
189
+ },
190
+ },
191
+ },
192
+ },
193
+ },
194
+ },
195
+ "duplicate table metrics - exact same symbols": {
196
+ profiles: []*Profile{
197
+ {
198
+ SourceFile: "profile1.yaml",
199
+ Definition: &ddprofiledefinition.ProfileDefinition{
200
+ Metrics: []ddprofiledefinition.MetricsConfig{
201
+ {
202
+ Table: ddprofiledefinition.SymbolConfig{
203
+ OID: "1.3.6.1.2.1.2.2",
204
+ Name: "ifTable",
205
+ },
206
+ Symbols: []ddprofiledefinition.SymbolConfig{
207
+ {
208
+ OID: "1.3.6.1.2.1.2.2.1.10",
209
+ Name: "ifInOctets",
210
+ },
211
+ {
212
+ OID: "1.3.6.1.2.1.2.2.1.16",
213
+ Name: "ifOutOctets",
214
+ },
215
+ },
216
+ MetricTags: []ddprofiledefinition.MetricTagConfig{
217
+ {
218
+ Tag: "interface",
219
+ Symbol: ddprofiledefinition.SymbolConfigCompat{
220
+ OID: "1.3.6.1.2.1.2.2.1.2",
221
+ Name: "ifDescr",
222
+ },
223
+ },
224
+ },
225
+ },
226
+ },
227
+ },
228
+ },
229
+ {
230
+ SourceFile: "profile2.yaml",
231
+ Definition: &ddprofiledefinition.ProfileDefinition{
232
+ Metrics: []ddprofiledefinition.MetricsConfig{
233
+ {
234
+ Table: ddprofiledefinition.SymbolConfig{
235
+ OID: "1.3.6.1.2.1.2.2",
236
+ Name: "ifTable",
237
+ },
238
+ Symbols: []ddprofiledefinition.SymbolConfig{
239
+ {
240
+ OID: "1.3.6.1.2.1.2.2.1.10",
241
+ Name: "ifInOctets",
242
+ },
243
+ {
244
+ OID: "1.3.6.1.2.1.2.2.1.16",
245
+ Name: "ifOutOctets",
246
+ },
247
+ },
248
+ MetricTags: []ddprofiledefinition.MetricTagConfig{
249
+ {
250
+ Tag: "if_name", // Different tag, but ignored in key
251
+ Symbol: ddprofiledefinition.SymbolConfigCompat{
252
+ OID: "1.3.6.1.2.1.31.1.1.1.1",
253
+ Name: "ifName",
254
+ },
255
+ Table: "ifXTable",
256
+ },
257
+ },
258
+ },
259
+ },
260
+ },
261
+ },
262
+ },
263
+ expected: []*Profile{
264
+ {
265
+ SourceFile: "profile1.yaml",
266
+ Definition: &ddprofiledefinition.ProfileDefinition{
267
+ Metrics: []ddprofiledefinition.MetricsConfig{
268
+ {
269
+ Table: ddprofiledefinition.SymbolConfig{
270
+ OID: "1.3.6.1.2.1.2.2",
271
+ Name: "ifTable",
272
+ },
273
+ Symbols: []ddprofiledefinition.SymbolConfig{
274
+ {
275
+ OID: "1.3.6.1.2.1.2.2.1.10",
276
+ Name: "ifInOctets",
277
+ },
278
+ {
279
+ OID: "1.3.6.1.2.1.2.2.1.16",
280
+ Name: "ifOutOctets",
281
+ },
282
+ },
283
+ MetricTags: []ddprofiledefinition.MetricTagConfig{
284
+ {
285
+ Tag: "interface",
286
+ Symbol: ddprofiledefinition.SymbolConfigCompat{
287
+ OID: "1.3.6.1.2.1.2.2.1.2",
288
+ Name: "ifDescr",
289
+ },
290
+ },
291
+ },
292
+ },
293
+ },
294
+ },
295
+ },
296
+ {
297
+ SourceFile: "profile2.yaml",
298
+ Definition: &ddprofiledefinition.ProfileDefinition{
299
+ Metrics: []ddprofiledefinition.MetricsConfig{}, // Empty because it's a duplicate
300
+ },
301
+ },
302
+ },
303
+ },
304
+ "same table different symbols - keep both": {
305
+ profiles: []*Profile{
306
+ {
307
+ SourceFile: "profile1.yaml",
308
+ Definition: &ddprofiledefinition.ProfileDefinition{
309
+ Metrics: []ddprofiledefinition.MetricsConfig{
310
+ {
311
+ Table: ddprofiledefinition.SymbolConfig{
312
+ OID: "1.3.6.1.2.1.2.2",
313
+ Name: "ifTable",
314
+ },
315
+ Symbols: []ddprofiledefinition.SymbolConfig{
316
+ {
317
+ OID: "1.3.6.1.2.1.2.2.1.10",
318
+ Name: "ifInOctets",
319
+ },
320
+ },
321
+ },
322
+ },
323
+ },
324
+ },
325
+ {
326
+ SourceFile: "profile2.yaml",
327
+ Definition: &ddprofiledefinition.ProfileDefinition{
328
+ Metrics: []ddprofiledefinition.MetricsConfig{
329
+ {
330
+ Table: ddprofiledefinition.SymbolConfig{
331
+ OID: "1.3.6.1.2.1.2.2",
332
+ Name: "ifTable",
333
+ },
334
+ Symbols: []ddprofiledefinition.SymbolConfig{
335
+ {
336
+ OID: "1.3.6.1.2.1.2.2.1.16",
337
+ Name: "ifOutOctets",
338
+ },
339
+ },
340
+ },
341
+ },
342
+ },
343
+ },
344
+ },
345
+ expected: []*Profile{
346
+ {
347
+ SourceFile: "profile1.yaml",
348
+ Definition: &ddprofiledefinition.ProfileDefinition{
349
+ Metrics: []ddprofiledefinition.MetricsConfig{
350
+ {
351
+ Table: ddprofiledefinition.SymbolConfig{
352
+ OID: "1.3.6.1.2.1.2.2",
353
+ Name: "ifTable",
354
+ },
355
+ Symbols: []ddprofiledefinition.SymbolConfig{
356
+ {
357
+ OID: "1.3.6.1.2.1.2.2.1.10",
358
+ Name: "ifInOctets",
359
+ },
360
+ },
361
+ },
362
+ },
363
+ },
364
+ },
365
+ {
366
+ SourceFile: "profile2.yaml",
367
+ Definition: &ddprofiledefinition.ProfileDefinition{
368
+ Metrics: []ddprofiledefinition.MetricsConfig{
369
+ {
370
+ Table: ddprofiledefinition.SymbolConfig{
371
+ OID: "1.3.6.1.2.1.2.2",
372
+ Name: "ifTable",
373
+ },
374
+ Symbols: []ddprofiledefinition.SymbolConfig{
375
+ {
376
+ OID: "1.3.6.1.2.1.2.2.1.16",
377
+ Name: "ifOutOctets",
378
+ },
379
+ },
380
+ },
381
+ },
382
+ },
383
+ },
384
+ },
385
+ },
386
+ "symbols in different order - still duplicate": {
387
+ profiles: []*Profile{
388
+ {
389
+ SourceFile: "profile1.yaml",
390
+ Definition: &ddprofiledefinition.ProfileDefinition{
391
+ Metrics: []ddprofiledefinition.MetricsConfig{
392
+ {
393
+ Table: ddprofiledefinition.SymbolConfig{
394
+ OID: "1.3.6.1.2.1.2.2",
395
+ Name: "ifTable",
396
+ },
397
+ Symbols: []ddprofiledefinition.SymbolConfig{
398
+ {
399
+ OID: "1.3.6.1.2.1.2.2.1.10",
400
+ Name: "ifInOctets",
401
+ },
402
+ {
403
+ OID: "1.3.6.1.2.1.2.2.1.16",
404
+ Name: "ifOutOctets",
405
+ },
406
+ },
407
+ },
408
+ },
409
+ },
410
+ },
411
+ {
412
+ SourceFile: "profile2.yaml",
413
+ Definition: &ddprofiledefinition.ProfileDefinition{
414
+ Metrics: []ddprofiledefinition.MetricsConfig{
415
+ {
416
+ Table: ddprofiledefinition.SymbolConfig{
417
+ OID: "1.3.6.1.2.1.2.2",
418
+ Name: "ifTable",
419
+ },
420
+ Symbols: []ddprofiledefinition.SymbolConfig{
421
+ {
422
+ OID: "1.3.6.1.2.1.2.2.1.16",
423
+ Name: "ifOutOctets",
424
+ },
425
+ {
426
+ OID: "1.3.6.1.2.1.2.2.1.10",
427
+ Name: "ifInOctets",
428
+ },
429
+ },
430
+ },
431
+ },
432
+ },
433
+ },
434
+ },
435
+ expected: []*Profile{
436
+ {
437
+ SourceFile: "profile1.yaml",
438
+ Definition: &ddprofiledefinition.ProfileDefinition{
439
+ Metrics: []ddprofiledefinition.MetricsConfig{
440
+ {
441
+ Table: ddprofiledefinition.SymbolConfig{
442
+ OID: "1.3.6.1.2.1.2.2",
443
+ Name: "ifTable",
444
+ },
445
+ Symbols: []ddprofiledefinition.SymbolConfig{
446
+ {
447
+ OID: "1.3.6.1.2.1.2.2.1.10",
448
+ Name: "ifInOctets",
449
+ },
450
+ {
451
+ OID: "1.3.6.1.2.1.2.2.1.16",
452
+ Name: "ifOutOctets",
453
+ },
454
+ },
455
+ },
456
+ },
457
+ },
458
+ },
459
+ {
460
+ SourceFile: "profile2.yaml",
461
+ Definition: &ddprofiledefinition.ProfileDefinition{
462
+ Metrics: []ddprofiledefinition.MetricsConfig{}, // Empty because symbols are sorted in key
463
+ },
464
+ },
465
+ },
466
+ },
467
+ "multiple duplicates across three profiles": {
468
+ profiles: []*Profile{
469
+ {
470
+ SourceFile: "generic-device.yaml",
471
+ Definition: &ddprofiledefinition.ProfileDefinition{
472
+ Metrics: []ddprofiledefinition.MetricsConfig{
473
+ {
474
+ Symbol: ddprofiledefinition.SymbolConfig{
475
+ OID: "1.3.6.1.2.1.1.3.0",
476
+ Name: "sysUpTime",
477
+ },
478
+ },
479
+ {
480
+ Table: ddprofiledefinition.SymbolConfig{
481
+ OID: "1.3.6.1.2.1.2.2",
482
+ Name: "ifTable",
483
+ },
484
+ Symbols: []ddprofiledefinition.SymbolConfig{
485
+ {
486
+ OID: "1.3.6.1.2.1.2.2.1.10",
487
+ Name: "ifInOctets",
488
+ },
489
+ },
490
+ },
491
+ },
492
+ },
493
+ },
494
+ {
495
+ SourceFile: "vendor-specific.yaml",
496
+ Definition: &ddprofiledefinition.ProfileDefinition{
497
+ Metrics: []ddprofiledefinition.MetricsConfig{
498
+ {
499
+ Symbol: ddprofiledefinition.SymbolConfig{
500
+ OID: "1.3.6.1.2.1.1.3.0",
501
+ Name: "sysUpTime",
502
+ },
503
+ },
504
+ {
505
+ Symbol: ddprofiledefinition.SymbolConfig{
506
+ OID: "1.3.6.1.4.1.9.9.109.1.1.1.1.7",
507
+ Name: "cpmCPUTotal5minRev",
508
+ },
509
+ },
510
+ },
511
+ },
512
+ },
513
+ {
514
+ SourceFile: "extended.yaml",
515
+ Definition: &ddprofiledefinition.ProfileDefinition{
516
+ Metrics: []ddprofiledefinition.MetricsConfig{
517
+ {
518
+ Table: ddprofiledefinition.SymbolConfig{
519
+ OID: "1.3.6.1.2.1.2.2",
520
+ Name: "ifTable",
521
+ },
522
+ Symbols: []ddprofiledefinition.SymbolConfig{
523
+ {
524
+ OID: "1.3.6.1.2.1.2.2.1.10",
525
+ Name: "ifInOctets",
526
+ },
527
+ },
528
+ },
529
+ },
530
+ },
531
+ },
532
+ },
533
+ expected: []*Profile{
534
+ {
535
+ SourceFile: "vendor-specific.yaml",
536
+ Definition: &ddprofiledefinition.ProfileDefinition{
537
+ Metrics: []ddprofiledefinition.MetricsConfig{
538
+ {
539
+ Symbol: ddprofiledefinition.SymbolConfig{
540
+ OID: "1.3.6.1.2.1.1.3.0",
541
+ Name: "sysUpTime",
542
+ },
543
+ },
544
+ {
545
+ Symbol: ddprofiledefinition.SymbolConfig{
546
+ OID: "1.3.6.1.4.1.9.9.109.1.1.1.1.7",
547
+ Name: "cpmCPUTotal5minRev",
548
+ },
549
+ },
550
+ },
551
+ },
552
+ },
553
+ {
554
+ SourceFile: "extended.yaml",
555
+ Definition: &ddprofiledefinition.ProfileDefinition{
556
+ Metrics: []ddprofiledefinition.MetricsConfig{
557
+ {
558
+ Table: ddprofiledefinition.SymbolConfig{
559
+ OID: "1.3.6.1.2.1.2.2",
560
+ Name: "ifTable",
561
+ },
562
+ Symbols: []ddprofiledefinition.SymbolConfig{
563
+ {
564
+ OID: "1.3.6.1.2.1.2.2.1.10",
565
+ Name: "ifInOctets",
566
+ },
567
+ },
568
+ },
569
+ },
570
+ },
571
+ },
572
+ {
573
+ SourceFile: "generic-device.yaml",
574
+ Definition: &ddprofiledefinition.ProfileDefinition{
575
+ Metrics: []ddprofiledefinition.MetricsConfig{}, // All removed as duplicates
576
+ },
577
+ },
578
+ },
579
+ },
580
+ "empty metrics in some profiles": {
581
+ profiles: []*Profile{
582
+ {
583
+ SourceFile: "profile1.yaml",
584
+ Definition: &ddprofiledefinition.ProfileDefinition{
585
+ Metrics: []ddprofiledefinition.MetricsConfig{
586
+ {
587
+ Symbol: ddprofiledefinition.SymbolConfig{
588
+ OID: "1.3.6.1.2.1.1.3.0",
589
+ Name: "sysUpTime",
590
+ },
591
+ },
592
+ },
593
+ },
594
+ },
595
+ {
596
+ SourceFile: "profile2.yaml",
597
+ Definition: &ddprofiledefinition.ProfileDefinition{
598
+ Metrics: []ddprofiledefinition.MetricsConfig{},
599
+ },
600
+ },
601
+ {
602
+ SourceFile: "profile3.yaml",
603
+ Definition: &ddprofiledefinition.ProfileDefinition{
604
+ Metrics: []ddprofiledefinition.MetricsConfig{
605
+ {
606
+ Symbol: ddprofiledefinition.SymbolConfig{
607
+ OID: "1.3.6.1.2.1.1.3.0",
608
+ Name: "sysUpTime",
609
+ },
610
+ },
611
+ },
612
+ },
613
+ },
614
+ },
615
+ expected: []*Profile{
616
+ {
617
+ SourceFile: "profile1.yaml",
618
+ Definition: &ddprofiledefinition.ProfileDefinition{
619
+ Metrics: []ddprofiledefinition.MetricsConfig{
620
+ {
621
+ Symbol: ddprofiledefinition.SymbolConfig{
622
+ OID: "1.3.6.1.2.1.1.3.0",
623
+ Name: "sysUpTime",
624
+ },
625
+ },
626
+ },
627
+ },
628
+ },
629
+ {
630
+ SourceFile: "profile2.yaml",
631
+ Definition: &ddprofiledefinition.ProfileDefinition{
632
+ Metrics: []ddprofiledefinition.MetricsConfig{},
633
+ },
634
+ },
635
+ {
636
+ SourceFile: "profile3.yaml",
637
+ Definition: &ddprofiledefinition.ProfileDefinition{
638
+ Metrics: []ddprofiledefinition.MetricsConfig{},
639
+ },
640
+ },
641
+ },
642
+ },
643
+ "generic vs non-generic priority": {
644
+ profiles: []*Profile{
645
+ {
646
+ SourceFile: "generic-device.yaml",
647
+ Definition: &ddprofiledefinition.ProfileDefinition{
648
+ Metrics: []ddprofiledefinition.MetricsConfig{
649
+ {
650
+ Symbol: ddprofiledefinition.SymbolConfig{
651
+ OID: "1.3.6.1.2.1.1.3.0",
652
+ Name: "sysUpTime",
653
+ },
654
+ },
655
+ {
656
+ Table: ddprofiledefinition.SymbolConfig{
657
+ OID: "1.3.6.1.2.1.2.2",
658
+ Name: "ifTable",
659
+ },
660
+ Symbols: []ddprofiledefinition.SymbolConfig{
661
+ {
662
+ OID: "1.3.6.1.2.1.2.2.1.10",
663
+ Name: "ifInOctets",
664
+ },
665
+ {
666
+ OID: "1.3.6.1.2.1.2.2.1.16",
667
+ Name: "ifOutOctets",
668
+ },
669
+ },
670
+ },
671
+ {
672
+ Symbol: ddprofiledefinition.SymbolConfig{
673
+ OID: "1.3.6.1.2.1.1.1.0",
674
+ Name: "sysDescr",
675
+ },
676
+ },
677
+ },
678
+ },
679
+ },
680
+ {
681
+ SourceFile: "mikrotik-router.yaml",
682
+ Definition: &ddprofiledefinition.ProfileDefinition{
683
+ Metrics: []ddprofiledefinition.MetricsConfig{
684
+ {
685
+ Symbol: ddprofiledefinition.SymbolConfig{
686
+ OID: "1.3.6.1.2.1.1.3.0",
687
+ Name: "sysUpTime",
688
+ },
689
+ },
690
+ {
691
+ Table: ddprofiledefinition.SymbolConfig{
692
+ OID: "1.3.6.1.2.1.2.2",
693
+ Name: "ifTable",
694
+ },
695
+ Symbols: []ddprofiledefinition.SymbolConfig{
696
+ {
697
+ OID: "1.3.6.1.2.1.2.2.1.10",
698
+ Name: "ifInOctets",
699
+ },
700
+ {
701
+ OID: "1.3.6.1.2.1.2.2.1.16",
702
+ Name: "ifOutOctets",
703
+ },
704
+ },
705
+ },
706
+ {
707
+ Symbol: ddprofiledefinition.SymbolConfig{
708
+ OID: "1.3.6.1.4.1.14988.1.1.1.3.0",
709
+ Name: "mtxrHlCpuTemperature",
710
+ },
711
+ },
712
+ },
713
+ },
714
+ },
715
+ {
716
+ SourceFile: "generic-if.yaml",
717
+ Definition: &ddprofiledefinition.ProfileDefinition{
718
+ Metrics: []ddprofiledefinition.MetricsConfig{
719
+ {
720
+ Symbol: ddprofiledefinition.SymbolConfig{
721
+ OID: "1.3.6.1.2.1.1.1.0",
722
+ Name: "sysDescr",
723
+ },
724
+ },
725
+ {
726
+ Table: ddprofiledefinition.SymbolConfig{
727
+ OID: "1.3.6.1.2.1.31.1.1",
728
+ Name: "ifXTable",
729
+ },
730
+ Symbols: []ddprofiledefinition.SymbolConfig{
731
+ {
732
+ OID: "1.3.6.1.2.1.31.1.1.1.6",
733
+ Name: "ifHCInOctets",
734
+ },
735
+ },
736
+ },
737
+ },
738
+ },
739
+ },
740
+ },
741
+ expected: []*Profile{
742
+ {
743
+ SourceFile: "mikrotik-router.yaml",
744
+ Definition: &ddprofiledefinition.ProfileDefinition{
745
+ Metrics: []ddprofiledefinition.MetricsConfig{
746
+ {
747
+ Symbol: ddprofiledefinition.SymbolConfig{
748
+ OID: "1.3.6.1.2.1.1.3.0",
749
+ Name: "sysUpTime",
750
+ },
751
+ },
752
+ {
753
+ Table: ddprofiledefinition.SymbolConfig{
754
+ OID: "1.3.6.1.2.1.2.2",
755
+ Name: "ifTable",
756
+ },
757
+ Symbols: []ddprofiledefinition.SymbolConfig{
758
+ {
759
+ OID: "1.3.6.1.2.1.2.2.1.10",
760
+ Name: "ifInOctets",
761
+ },
762
+ {
763
+ OID: "1.3.6.1.2.1.2.2.1.16",
764
+ Name: "ifOutOctets",
765
+ },
766
+ },
767
+ },
768
+ {
769
+ Symbol: ddprofiledefinition.SymbolConfig{
770
+ OID: "1.3.6.1.4.1.14988.1.1.1.3.0",
771
+ Name: "mtxrHlCpuTemperature",
772
+ },
773
+ },
774
+ },
775
+ },
776
+ },
777
+ {
778
+ SourceFile: "generic-device.yaml",
779
+ Definition: &ddprofiledefinition.ProfileDefinition{
780
+ Metrics: []ddprofiledefinition.MetricsConfig{
781
+ {
782
+ Symbol: ddprofiledefinition.SymbolConfig{
783
+ OID: "1.3.6.1.2.1.1.1.0",
784
+ Name: "sysDescr",
785
+ },
786
+ },
787
+ },
788
+ },
789
+ },
790
+ {
791
+ SourceFile: "generic-if.yaml",
792
+ Definition: &ddprofiledefinition.ProfileDefinition{
793
+ Metrics: []ddprofiledefinition.MetricsConfig{
794
+ {
795
+ Table: ddprofiledefinition.SymbolConfig{
796
+ OID: "1.3.6.1.2.1.31.1.1",
797
+ Name: "ifXTable",
798
+ },
799
+ Symbols: []ddprofiledefinition.SymbolConfig{
800
+ {
801
+ OID: "1.3.6.1.2.1.31.1.1.1.6",
802
+ Name: "ifHCInOctets",
803
+ },
804
+ },
805
+ },
806
+ },
807
+ },
808
+ },
809
+ },
810
+ },
811
+ }
812
+
813
+ for name, tc := range tests {
814
+ t.Run(name, func(t *testing.T) {
815
+ // Make a deep copy of profiles to avoid modifying test data
816
+ profiles := make([]*Profile, len(tc.profiles))
817
+ for i, p := range tc.profiles {
818
+ profiles[i] = p.clone()
819
+ }
820
+
821
+ deduplicateMetricsAcrossProfiles(profiles)
822
+
823
+ require.Equal(t, len(tc.expected), len(profiles))
824
+
825
+ for i, expectedProf := range tc.expected {
826
+ assert.Equal(t, expectedProf.SourceFile, profiles[i].SourceFile)
827
+ assert.Equal(t, len(expectedProf.Definition.Metrics), len(profiles[i].Definition.Metrics))
828
+
829
+ // Compare metrics
830
+ for j, expectedMetric := range expectedProf.Definition.Metrics {
831
+ actualMetric := profiles[i].Definition.Metrics[j]
832
+
833
+ if expectedMetric.IsScalar() {
834
+ assert.Equal(t, expectedMetric.Symbol.OID, actualMetric.Symbol.OID)
835
+ assert.Equal(t, expectedMetric.Symbol.Name, actualMetric.Symbol.Name)
836
+ } else {
837
+ assert.Equal(t, expectedMetric.Table.OID, actualMetric.Table.OID)
838
+ assert.Equal(t, expectedMetric.Table.Name, actualMetric.Table.Name)
839
+ assert.Equal(t, len(expectedMetric.Symbols), len(actualMetric.Symbols))
840
+ }
841
+ }
842
+ }
843
+ })
844
+ }
845
+}