diff --git a/cmd/crowdsec-cli/main.go b/cmd/crowdsec-cli/main.go index a0805c853..d8d45b5a2 100644 --- a/cmd/crowdsec-cli/main.go +++ b/cmd/crowdsec-cli/main.go @@ -54,7 +54,7 @@ func initConfig() { } if !inSlice(os.Args[1], NoNeedConfig) { - csConfig, err = csconfig.NewConfig(ConfigFilePath, false, false) + csConfig, err = csconfig.NewConfig(ConfigFilePath, false, false, true) if err != nil { log.Fatal(err) } diff --git a/cmd/crowdsec/main.go b/cmd/crowdsec/main.go index 1aec6b211..3544857ba 100644 --- a/cmd/crowdsec/main.go +++ b/cmd/crowdsec/main.go @@ -185,7 +185,7 @@ func newLogLevel(curLevelPtr *log.Level, f *Flags) *log.Level { default: } - if ret == *curLevelPtr { + if curLevelPtr != nil && ret == *curLevelPtr { // avoid returning a new ptr to the same value return curLevelPtr } @@ -194,6 +194,10 @@ func newLogLevel(curLevelPtr *log.Level, f *Flags) *log.Level { // LoadConfig returns a configuration parsed from configuration file func LoadConfig(cConfig *csconfig.Config) error { + if (cConfig.Common == nil || *cConfig.Common == csconfig.CommonCfg{}) { + return fmt.Errorf("unable to load configuration: common section is empty") + } + cConfig.Common.LogLevel = newLogLevel(cConfig.Common.LogLevel, flags) if dumpFolder != "" { diff --git a/cmd/crowdsec/run_in_svc.go b/cmd/crowdsec/run_in_svc.go index b6035e5df..810a6edf3 100644 --- a/cmd/crowdsec/run_in_svc.go +++ b/cmd/crowdsec/run_in_svc.go @@ -30,7 +30,7 @@ func StartRunSvc() error { }, }) - cConfig, err = csconfig.NewConfig(flags.ConfigFile, flags.DisableAgent, flags.DisableAPI) + cConfig, err = csconfig.NewConfig(flags.ConfigFile, flags.DisableAgent, flags.DisableAPI, false) if err != nil { return err } diff --git a/cmd/crowdsec/run_in_svc_windows.go b/cmd/crowdsec/run_in_svc_windows.go index 40e19dfe5..33e4ce7f8 100644 --- a/cmd/crowdsec/run_in_svc_windows.go +++ b/cmd/crowdsec/run_in_svc_windows.go @@ -58,7 +58,7 @@ func WindowsRun() error { err error ) - cConfig, err = csconfig.NewConfig(flags.ConfigFile, flags.DisableAgent, flags.DisableAPI) + cConfig, err = csconfig.NewConfig(flags.ConfigFile, flags.DisableAgent, flags.DisableAPI, false) if err != nil { return err } diff --git a/cmd/crowdsec/serve.go b/cmd/crowdsec/serve.go index 8b9486d28..bec3e05db 100644 --- a/cmd/crowdsec/serve.go +++ b/cmd/crowdsec/serve.go @@ -54,7 +54,7 @@ func reloadHandler(sig os.Signal) (*csconfig.Config, error) { crowdsecTomb = tomb.Tomb{} pluginTomb = tomb.Tomb{} - cConfig, err := csconfig.NewConfig(flags.ConfigFile, flags.DisableAgent, flags.DisableAPI) + cConfig, err := csconfig.NewConfig(flags.ConfigFile, flags.DisableAgent, flags.DisableAPI, false) if err != nil { return nil, err } diff --git a/cmd/crowdsec/win_service.go b/cmd/crowdsec/win_service.go index b5c59ca45..b4cfc3ab0 100644 --- a/cmd/crowdsec/win_service.go +++ b/cmd/crowdsec/win_service.go @@ -97,7 +97,7 @@ func runService(name string) error { log.Warnf("Failed to open event log: %s", err) } - cConfig, err := csconfig.NewConfig(flags.ConfigFile, flags.DisableAgent, flags.DisableAPI) + cConfig, err := csconfig.NewConfig(flags.ConfigFile, flags.DisableAgent, flags.DisableAPI, false) if err != nil { return err } diff --git a/pkg/csconfig/config.go b/pkg/csconfig/config.go index 68b84b945..c89f59fa0 100644 --- a/pkg/csconfig/config.go +++ b/pkg/csconfig/config.go @@ -46,8 +46,9 @@ func (c *Config) Dump() error { return nil } -func NewConfig(configFile string, disableAgent bool, disableAPI bool) (*Config, error) { +func NewConfig(configFile string, disableAgent bool, disableAPI bool, quiet bool) (*Config, error) { patcher := yamlpatch.NewPatcher(configFile, ".local") + patcher.SetQuiet(quiet) fcontent, err := patcher.MergedPatchContent() if err != nil { return nil, err diff --git a/pkg/csconfig/config_test.go b/pkg/csconfig/config_test.go index 7c3da496c..6f556245f 100644 --- a/pkg/csconfig/config_test.go +++ b/pkg/csconfig/config_test.go @@ -10,13 +10,13 @@ import ( ) func TestNormalLoad(t *testing.T) { - _, err := NewConfig("./tests/config.yaml", false, false) + _, err := NewConfig("./tests/config.yaml", false, false, false) require.NoError(t, err) - _, err = NewConfig("./tests/xxx.yaml", false, false) + _, err = NewConfig("./tests/xxx.yaml", false, false, false) assert.EqualError(t, err, "while reading yaml file: open ./tests/xxx.yaml: "+cstest.FileNotFoundMessage) - _, err = NewConfig("./tests/simulation.yaml", false, false) + _, err = NewConfig("./tests/simulation.yaml", false, false, false) assert.EqualError(t, err, "./tests/simulation.yaml: yaml: unmarshal errors:\n line 1: field simulation not found in type csconfig.Config") } diff --git a/pkg/yamlpatch/patcher.go b/pkg/yamlpatch/patcher.go index fb76b92e7..43a2a0cb8 100644 --- a/pkg/yamlpatch/patcher.go +++ b/pkg/yamlpatch/patcher.go @@ -13,15 +13,24 @@ import ( type Patcher struct { BaseFilePath string PatchFilePath string + quiet bool } func NewPatcher(filePath string, suffix string) *Patcher { return &Patcher{ BaseFilePath: filePath, PatchFilePath: filePath + suffix, + quiet: false, } } + +// SetQuiet sets the quiet flag, which will log as DEBUG_LEVEL instead of INFO +func (p *Patcher) SetQuiet(quiet bool) { + p.quiet = quiet +} + + // read a single YAML file, check for errors (the merge package doesn't) then return the content as bytes. func readYAML(filePath string) ([]byte, error) { var content []byte @@ -55,13 +64,19 @@ func (p *Patcher) MergedPatchContent() ([]byte, error) { var over []byte over, err = readYAML(p.PatchFilePath) - // optional file, ignore if it does not exist - if err != nil && !errors.Is(err, os.ErrNotExist) { + if errors.Is(err, os.ErrNotExist) { + return base, nil + } + + if err != nil { return nil, err } - if err == nil { - log.Debugf("Patching yaml: '%s' with '%s'", p.BaseFilePath, p.PatchFilePath) + + logf := log.Infof + if p.quiet { + logf = log.Debugf } + logf("Patching yaml: '%s' with '%s'", p.BaseFilePath, p.PatchFilePath) var patched *bytes.Buffer @@ -138,7 +153,11 @@ func (p *Patcher) PrependedPatchContent() ([]byte, error) { if err = decodeDocuments(patchFile, &result, true); err != nil { return nil, err } - log.Infof("Prepending yaml: '%s' with '%s'", p.BaseFilePath, p.PatchFilePath) + logf := log.Infof + if p.quiet { + logf = log.Debugf + } + logf("Prepending yaml: '%s' with '%s'", p.BaseFilePath, p.PatchFilePath) } baseFile, err = os.Open(p.BaseFilePath) diff --git a/tests/bats/01_crowdsec.bats b/tests/bats/01_crowdsec.bats index a60b576dd..756dd8eac 100644 --- a/tests/bats/01_crowdsec.bats +++ b/tests/bats/01_crowdsec.bats @@ -52,10 +52,21 @@ teardown() { # errors that cause program termination are printed to stderr, not only logs config_set '.db_config.type="meh"' run -1 --separate-stderr "${CROWDSEC}" - refute_output assert_stderr --partial "unable to create database client: unknown database type 'meh'" } +@test "crowdsec - bad configuration (empty/missing common section)" { + config_set '.common={}' + run -1 --separate-stderr "${CROWDSEC}" + refute_output + assert_stderr --partial "unable to load configuration: common section is empty" + + config_set 'del(.common)' + run -1 --separate-stderr "${CROWDSEC}" + refute_output + assert_stderr --partial "unable to load configuration: common section is empty" +} + @test "CS_LAPI_SECRET not strong enough" { CS_LAPI_SECRET=foo run -1 --separate-stderr timeout 2s "${CROWDSEC}" assert_stderr --partial "api server init: unable to run local API: controller init: CS_LAPI_SECRET not strong enough"