5
5
"errors"
6
6
"fmt"
7
7
"io"
8
+ "maps"
8
9
"os"
9
10
"strings"
10
11
@@ -24,7 +25,6 @@ import (
24
25
"github.com/crowdsecurity/crowdsec/pkg/cwversion/component"
25
26
"github.com/crowdsecurity/crowdsec/pkg/exprhelpers"
26
27
"github.com/crowdsecurity/crowdsec/pkg/types"
27
- "maps"
28
28
)
29
29
30
30
type DataSourceUnavailableError struct {
@@ -42,18 +42,18 @@ func (e *DataSourceUnavailableError) Unwrap() error {
42
42
43
43
// The interface each datasource must implement
44
44
type DataSource interface {
45
- GetMetrics () []prometheus.Collector // Returns pointers to metrics that are managed by the module
46
- GetAggregMetrics () []prometheus.Collector // Returns pointers to metrics that are managed by the module (aggregated mode, limits cardinality)
47
- UnmarshalConfig (yamlConfig []byte ) error // Decode and pre-validate the YAML datasource - anything that can be checked before runtime
48
- Configure (yamlConfig []byte , logger * log.Entry , metricsLevel int ) error // Complete the YAML datasource configuration and perform runtime checks.
49
- ConfigureByDSN (dsn string , labels map [string ]string , logger * log.Entry , uniqueID string ) error // Configure the datasource
50
- GetMode () string // Get the mode (TAIL, CAT or SERVER)
51
- GetName () string // Get the name of the module
52
- OneShotAcquisition (ctx context.Context , out chan types.Event , acquisTomb * tomb.Tomb ) error // Start one shot acquisition(eg, cat a file)
53
- StreamingAcquisition (ctx context.Context , out chan types.Event , acquisTomb * tomb.Tomb ) error // Start live acquisition (eg, tail a file)
54
- CanRun () error // Whether the datasource can run or not (eg, journalctl on BSD is a non-sense)
55
- GetUuid () string // Get the unique identifier of the datasource
56
- Dump () interface {}
45
+ GetMetrics () []prometheus.Collector // Returns pointers to metrics that are managed by the module
46
+ GetAggregMetrics () []prometheus.Collector // Returns pointers to metrics that are managed by the module (aggregated mode, limits cardinality)
47
+ UnmarshalConfig (yamlConfig []byte ) error // Decode and pre-validate the YAML datasource - anything that can be checked before runtime
48
+ Configure (yamlConfig []byte , logger * log.Entry , metricsLevel int ) error // Complete the YAML datasource configuration and perform runtime checks.
49
+ ConfigureByDSN (dsn string , labels map [string ]string , logger * log.Entry , uniqueID string ) error // Configure the datasource
50
+ GetMode () string // Get the mode (TAIL, CAT or SERVER)
51
+ GetName () string // Get the name of the module
52
+ OneShotAcquisition (ctx context.Context , out chan types.Event , acquisTomb * tomb.Tomb ) error // Start one shot acquisition(eg, cat a file)
53
+ StreamingAcquisition (ctx context.Context , out chan types.Event , acquisTomb * tomb.Tomb ) error // Start live acquisition (eg, tail a file)
54
+ CanRun () error // Whether the datasource can run or not (eg, journalctl on BSD is a non-sense)
55
+ GetUuid () string // Get the unique identifier of the datasource
56
+ Dump () any
57
57
}
58
58
59
59
var (
@@ -180,7 +180,7 @@ func LoadAcquisitionFromDSN(dsn string, labels map[string]string, transformExpr
180
180
uniqueId := uuid .NewString ()
181
181
182
182
if transformExpr != "" {
183
- vm , err := expr .Compile (transformExpr , exprhelpers .GetExprOptions (map [string ]interface {} {"evt" : & types.Event {}})... )
183
+ vm , err := expr .Compile (transformExpr , exprhelpers .GetExprOptions (map [string ]any {"evt" : & types.Event {}})... )
184
184
if err != nil {
185
185
return nil , fmt .Errorf ("while compiling transform expression '%s': %w" , transformExpr , err )
186
186
}
@@ -216,113 +216,127 @@ func GetMetricsLevelFromPromCfg(prom *csconfig.PrometheusCfg) int {
216
216
return configuration .METRICS_FULL
217
217
}
218
218
219
- // LoadAcquisitionFromFile unmarshals the configuration item and checks its availability
220
- func LoadAcquisitionFromFile ( config * csconfig. CrowdsecServiceCfg , prom * csconfig. PrometheusCfg ) ([]DataSource , error ) {
219
+ // sourcesFromFile reads and parses one acquisition file into DataSources.
220
+ func sourcesFromFile ( acquisFile string , metrics_level int ) ([]DataSource , error ) {
221
221
var sources []DataSource
222
222
223
- metrics_level := GetMetricsLevelFromPromCfg (prom )
224
-
225
- for _ , acquisFile := range config .AcquisitionFiles {
226
- log .Infof ("loading acquisition file : %s" , acquisFile )
227
-
228
- yamlFile , err := os .Open (acquisFile )
229
- if err != nil {
230
- return nil , err
231
- }
232
-
233
- defer yamlFile .Close ()
223
+ log .Infof ("loading acquisition file : %s" , acquisFile )
234
224
235
- acquisContent , err := io . ReadAll ( yamlFile )
236
- if err != nil {
237
- return nil , fmt . Errorf ( "failed to read %s: %w" , acquisFile , err )
238
- }
225
+ yamlFile , err := os . Open ( acquisFile )
226
+ if err != nil {
227
+ return nil , err
228
+ }
239
229
240
- expandedAcquis := csstring . StrictExpand ( string ( acquisContent ), os . LookupEnv )
230
+ defer yamlFile . Close ( )
241
231
242
- dec := yaml .NewDecoder (strings .NewReader (expandedAcquis ))
243
- dec .SetStrict (true )
232
+ acquisContent , err := io .ReadAll (yamlFile )
233
+ if err != nil {
234
+ return nil , fmt .Errorf ("failed to read %s: %w" , acquisFile , err )
235
+ }
244
236
245
- idx := - 1
237
+ expandedAcquis := csstring . StrictExpand ( string ( acquisContent ), os . LookupEnv )
246
238
247
- for {
248
- var sub configuration. DataSourceCommonCfg
239
+ dec := yaml . NewDecoder ( strings . NewReader ( expandedAcquis ))
240
+ dec . SetStrict ( true )
249
241
250
- idx += 1
242
+ idx := - 1
251
243
252
- err = dec .Decode (& sub )
253
- if err != nil {
254
- if ! errors .Is (err , io .EOF ) {
255
- return nil , fmt .Errorf ("failed to parse %s: %w" , acquisFile , err )
256
- }
244
+ for {
245
+ var sub configuration.DataSourceCommonCfg
257
246
258
- log . Tracef ( "End of yaml file" )
247
+ idx += 1
259
248
260
- break
249
+ err = dec .Decode (& sub )
250
+ if err != nil {
251
+ if ! errors .Is (err , io .EOF ) {
252
+ return nil , fmt .Errorf ("failed to parse %s: %w" , acquisFile , err )
261
253
}
262
254
263
- // for backward compat ('type' was not mandatory, detect it)
264
- if guessType := detectBackwardCompatAcquis (sub ); guessType != "" {
265
- log .Debugf ("datasource type missing in %s (position %d): detected 'source=%s'" , acquisFile , idx , guessType )
255
+ log .Tracef ("End of yaml file" )
266
256
267
- if sub .Source != "" && sub .Source != guessType {
268
- log .Warnf ("datasource type mismatch in %s (position %d): found '%s' but should probably be '%s'" , acquisFile , idx , sub .Source , guessType )
269
- }
257
+ break
258
+ }
270
259
271
- sub .Source = guessType
272
- }
273
- // it's an empty item, skip it
274
- if len (sub .Labels ) == 0 {
275
- if sub .Source == "" {
276
- log .Debugf ("skipping empty item in %s" , acquisFile )
277
- continue
278
- }
260
+ // for backward compat ('type' was not mandatory, detect it)
261
+ if guessType := detectBackwardCompatAcquis (sub ); guessType != "" {
262
+ log .Debugf ("datasource type missing in %s (position %d): detected 'source=%s'" , acquisFile , idx , guessType )
279
263
280
- if sub .Source != "docker" {
281
- // docker is the only source that can be empty
282
- return nil , fmt .Errorf ("missing labels in %s (position %d)" , acquisFile , idx )
283
- }
264
+ if sub .Source != "" && sub .Source != guessType {
265
+ log .Warnf ("datasource type mismatch in %s (position %d): found '%s' but should probably be '%s'" , acquisFile , idx , sub .Source , guessType )
284
266
}
285
267
268
+ sub .Source = guessType
269
+ }
270
+ // it's an empty item, skip it
271
+ if len (sub .Labels ) == 0 {
286
272
if sub .Source == "" {
287
- return nil , fmt .Errorf ("data source type is empty ('source') in %s (position %d)" , acquisFile , idx )
273
+ log .Debugf ("skipping empty item in %s" , acquisFile )
274
+ continue
288
275
}
289
276
290
- // pre-check that the source is valid
291
- _ , err := GetDataSourceIface (sub .Source )
292
- if err != nil {
293
- return nil , fmt .Errorf ("in file %s (position %d) - %w" , acquisFile , idx , err )
277
+ if sub .Source != "docker" {
278
+ // docker is the only source that can be empty
279
+ return nil , fmt .Errorf ("missing labels in %s (position %d)" , acquisFile , idx )
294
280
}
281
+ }
295
282
296
- uniqueId := uuid .NewString ()
297
- sub .UniqueId = uniqueId
283
+ if sub .Source == "" {
284
+ return nil , fmt .Errorf ("data source type is empty ('source') in %s (position %d)" , acquisFile , idx )
285
+ }
298
286
299
- src , err := DataSourceConfigure (sub , metrics_level )
300
- if err != nil {
301
- var dserr * DataSourceUnavailableError
302
- if errors .As (err , & dserr ) {
303
- log .Error (err )
304
- continue
305
- }
287
+ // pre-check that the source is valid
288
+ _ , err := GetDataSourceIface (sub .Source )
289
+ if err != nil {
290
+ return nil , fmt .Errorf ("in file %s (position %d) - %w" , acquisFile , idx , err )
291
+ }
306
292
307
- return nil , fmt .Errorf ("while configuring datasource of type %s from %s (position %d): %w" , sub .Source , acquisFile , idx , err )
293
+ uniqueId := uuid .NewString ()
294
+ sub .UniqueId = uniqueId
295
+
296
+ src , err := DataSourceConfigure (sub , metrics_level )
297
+ if err != nil {
298
+ var dserr * DataSourceUnavailableError
299
+ if errors .As (err , & dserr ) {
300
+ log .Error (err )
301
+ continue
308
302
}
309
303
310
- if sub .TransformExpr != "" {
311
- vm , err := expr .Compile (sub .TransformExpr , exprhelpers .GetExprOptions (map [string ]interface {}{"evt" : & types.Event {}})... )
312
- if err != nil {
313
- return nil , fmt .Errorf ("while compiling transform expression '%s' for datasource %s in %s (position %d): %w" , sub .TransformExpr , sub .Source , acquisFile , idx , err )
314
- }
304
+ return nil , fmt .Errorf ("while configuring datasource of type %s from %s (position %d): %w" , sub .Source , acquisFile , idx , err )
305
+ }
315
306
316
- transformRuntimes [uniqueId ] = vm
307
+ if sub .TransformExpr != "" {
308
+ vm , err := expr .Compile (sub .TransformExpr , exprhelpers .GetExprOptions (map [string ]any {"evt" : & types.Event {}})... )
309
+ if err != nil {
310
+ return nil , fmt .Errorf ("while compiling transform expression '%s' for datasource %s in %s (position %d): %w" , sub .TransformExpr , sub .Source , acquisFile , idx , err )
317
311
}
318
312
319
- sources = append ( sources , src )
313
+ transformRuntimes [ uniqueId ] = vm
320
314
}
315
+
316
+ sources = append (sources , src )
321
317
}
322
318
323
319
return sources , nil
324
320
}
325
321
322
+ // LoadAcquisitionFromFiles unmarshals the configuration item and checks its availability
323
+ func LoadAcquisitionFromFiles (config * csconfig.CrowdsecServiceCfg , prom * csconfig.PrometheusCfg ) ([]DataSource , error ) {
324
+ var allSources []DataSource
325
+
326
+ metrics_level := GetMetricsLevelFromPromCfg (prom )
327
+
328
+ for _ , acquisFile := range config .AcquisitionFiles {
329
+ sources , err := sourcesFromFile (acquisFile , metrics_level )
330
+ if err != nil {
331
+ return nil , err
332
+ }
333
+
334
+ allSources = append (allSources , sources ... )
335
+ }
336
+
337
+ return allSources , nil
338
+ }
339
+
326
340
func GetMetrics (sources []DataSource , aggregated bool ) error {
327
341
var metrics []prometheus.Collector
328
342
@@ -362,6 +376,7 @@ func copyEvent(evt types.Event, line string) types.Event {
362
376
363
377
func transform (transformChan chan types.Event , output chan types.Event , acquisTomb * tomb.Tomb , transformRuntime * vm.Program , logger * log.Entry ) {
364
378
defer trace .CatchPanic ("crowdsec/acquis" )
379
+
365
380
logger .Infof ("transformer started" )
366
381
367
382
for {
@@ -372,7 +387,7 @@ func transform(transformChan chan types.Event, output chan types.Event, acquisTo
372
387
case evt := <- transformChan :
373
388
logger .Tracef ("Received event %s" , evt .Line .Raw )
374
389
375
- out , err := expr .Run (transformRuntime , map [string ]interface {} {"evt" : & evt })
390
+ out , err := expr .Run (transformRuntime , map [string ]any {"evt" : & evt })
376
391
if err != nil {
377
392
logger .Errorf ("while running transform expression: %s, sending event as-is" , err )
378
393
output <- evt
0 commit comments