From 9acd23d0acfeeff0bb04691f740c766d930b1df2 Mon Sep 17 00:00:00 2001 From: marco Date: Thu, 25 Apr 2024 23:45:30 +0200 Subject: [PATCH] cscli: cleaner output --- cmd/crowdsec-cli/capi.go | 6 +++--- cmd/crowdsec-cli/lapi.go | 6 +++--- cmd/crowdsec-cli/main.go | 4 +++- test/bats/01_cscli.bats | 21 +++++++++------------ test/bats/03_noagent.bats | 2 +- test/bats/04_capi.bats | 10 +++++----- test/bats/04_nocapi.bats | 2 +- test/bats/08_metrics.bats | 2 +- test/bats/09_socket.bats | 12 ++++++------ test/bats/10_bouncers.bats | 7 ++----- test/bats/20_hub_items.bats | 6 ++---- test/bats/30_machines.bats | 5 ++--- test/bats/90_decisions.bats | 16 +++++++--------- 13 files changed, 45 insertions(+), 54 deletions(-) diff --git a/cmd/crowdsec-cli/capi.go b/cmd/crowdsec-cli/capi.go index b5180d050..edf1fdef9 100644 --- a/cmd/crowdsec-cli/capi.go +++ b/cmd/crowdsec-cli/capi.go @@ -194,15 +194,15 @@ func (cli *cliCapi) status() error { Scenarios: scenarios, } - log.Infof("Loaded credentials from %s", cfg.API.Server.OnlineClient.CredentialsFilePath) - log.Infof("Trying to authenticate with username %s on %s", cfg.API.Server.OnlineClient.Credentials.Login, apiurl) + fmt.Printf("Loaded credentials from %s\n", cfg.API.Server.OnlineClient.CredentialsFilePath) + fmt.Printf("Trying to authenticate with username %s on %s\n", cfg.API.Server.OnlineClient.Credentials.Login, apiurl) _, _, err = Client.Auth.AuthenticateWatcher(context.Background(), t) if err != nil { return fmt.Errorf("failed to authenticate to Central API (CAPI): %w", err) } - log.Info("You can successfully interact with Central API (CAPI)") + fmt.Println("You can successfully interact with Central API (CAPI)") return nil } diff --git a/cmd/crowdsec-cli/lapi.go b/cmd/crowdsec-cli/lapi.go index 369de5b42..e417fe9c5 100644 --- a/cmd/crowdsec-cli/lapi.go +++ b/cmd/crowdsec-cli/lapi.go @@ -75,16 +75,16 @@ func (cli *cliLapi) status() error { Scenarios: scenarios, } - log.Infof("Loaded credentials from %s", cfg.API.Client.CredentialsFilePath) + fmt.Printf("Loaded credentials from %s\n", cfg.API.Client.CredentialsFilePath) // use the original string because apiURL would print 'http://unix/' - log.Infof("Trying to authenticate with username %s on %s", login, origURL) + fmt.Printf("Trying to authenticate with username %s on %s\n", login, origURL) _, _, err = Client.Auth.AuthenticateWatcher(context.Background(), t) if err != nil { return fmt.Errorf("failed to authenticate to Local API (LAPI): %w", err) } - log.Infof("You can successfully interact with Local API (LAPI)") + fmt.Println("You can successfully interact with Local API (LAPI)") return nil } diff --git a/cmd/crowdsec-cli/main.go b/cmd/crowdsec-cli/main.go index 0705faa40..3c26daa9f 100644 --- a/cmd/crowdsec-cli/main.go +++ b/cmd/crowdsec-cli/main.go @@ -278,6 +278,8 @@ It is meant to allow you to manage bans, parsers/scenarios/etc, api and generall func main() { cmd := newCliRoot().NewCommand() if err := cmd.Execute(); err != nil { - log.Fatal(err) + color.New(color.FgRed).Fprint(os.Stderr, "Error: ") + fmt.Fprintln(os.Stderr, err) + os.Exit(1) } } diff --git a/test/bats/01_cscli.bats b/test/bats/01_cscli.bats index 4c7ce7fbc..7562b24df 100644 --- a/test/bats/01_cscli.bats +++ b/test/bats/01_cscli.bats @@ -34,8 +34,7 @@ teardown() { # no "usage" output after every error rune -1 cscli blahblah # error is displayed as log entry, not with print - assert_stderr --partial 'level=fatal msg="unknown command \"blahblah\" for \"cscli\""' - refute_stderr --partial 'unknown command "blahblah" for "cscli"' + assert_stderr --partial 'Error: unknown command "blahblah" for "cscli"' } @test "cscli version" { @@ -214,9 +213,9 @@ teardown() { rune -0 ./instance-crowdsec start rune -0 cscli lapi status - assert_stderr --partial "Loaded credentials from" - assert_stderr --partial "Trying to authenticate with username" - assert_stderr --partial "You can successfully interact with Local API (LAPI)" + assert_output --partial "Loaded credentials from" + assert_output --partial "Trying to authenticate with username" + assert_output --partial "You can successfully interact with Local API (LAPI)" } @test "cscli - missing LAPI credentials file" { @@ -261,9 +260,8 @@ teardown() { LOCAL_API_CREDENTIALS=$(config_get '.api.client.credentials_path') config_set "${LOCAL_API_CREDENTIALS}" '.url="http://127.0.0.1:-80"' - rune -1 cscli lapi status -o json - rune -0 jq -r '.msg' <(stderr) - assert_output 'parsing api url: parse "http://127.0.0.1:-80/": invalid port ":-80" after host' + rune -1 cscli lapi status + assert_stderr 'Error: parsing api url: parse "http://127.0.0.1:-80/": invalid port ":-80" after host' } @test "cscli - bad LAPI password" { @@ -271,9 +269,8 @@ teardown() { LOCAL_API_CREDENTIALS=$(config_get '.api.client.credentials_path') config_set "${LOCAL_API_CREDENTIALS}" '.password="meh"' - rune -1 cscli lapi status -o json - rune -0 jq -r '.msg' <(stderr) - assert_output 'failed to authenticate to Local API (LAPI): API error: incorrect Username or Password' + rune -1 cscli lapi status + assert_stderr 'Error: failed to authenticate to Local API (LAPI): API error: incorrect Username or Password' } @test "'cscli completion' with or without configuration file" { @@ -355,7 +352,7 @@ teardown() { # it is possible to enable subcommands with feature flags defined in feature.yaml rune -1 cscli setup - assert_stderr --partial 'unknown command \"setup\" for \"cscli\"' + assert_stderr 'Error: unknown command "setup" for "cscli"' CONFIG_DIR=$(dirname "$CONFIG_YAML") echo ' - cscli_setup' >> "$CONFIG_DIR"/feature.yaml rune -0 cscli setup diff --git a/test/bats/03_noagent.bats b/test/bats/03_noagent.bats index e75e375ad..afd3fce2e 100644 --- a/test/bats/03_noagent.bats +++ b/test/bats/03_noagent.bats @@ -76,7 +76,7 @@ teardown() { config_disable_agent ./instance-crowdsec start rune -0 cscli lapi status - assert_stderr --partial "You can successfully interact with Local API (LAPI)" + assert_line "You can successfully interact with Local API (LAPI)" } @test "cscli metrics" { diff --git a/test/bats/04_capi.bats b/test/bats/04_capi.bats index d5154c1a0..7a76a4ccd 100644 --- a/test/bats/04_capi.bats +++ b/test/bats/04_capi.bats @@ -55,10 +55,10 @@ setup() { rune -0 cscli scenarios install crowdsecurity/ssh-bf rune -0 cscli capi status - assert_stderr --partial "Loaded credentials from" - assert_stderr --partial "Trying to authenticate with username" - assert_stderr --partial " on https://api.crowdsec.net/" - assert_stderr --partial "You can successfully interact with Central API (CAPI)" + assert_output --partial "Loaded credentials from" + assert_output --partial "Trying to authenticate with username" + assert_output --partial " on https://api.crowdsec.net/" + assert_output --partial "You can successfully interact with Central API (CAPI)" } @test "cscli alerts list: receive a community pull when capi is enabled" { @@ -85,7 +85,7 @@ setup() { config_disable_agent ./instance-crowdsec start rune -0 cscli capi status - assert_stderr --partial "You can successfully interact with Central API (CAPI)" + assert_line "You can successfully interact with Central API (CAPI)" } @test "capi register must be run from lapi" { diff --git a/test/bats/04_nocapi.bats b/test/bats/04_nocapi.bats index 234db182a..ce50386ec 100644 --- a/test/bats/04_nocapi.bats +++ b/test/bats/04_nocapi.bats @@ -66,7 +66,7 @@ teardown() { config_disable_capi ./instance-crowdsec start rune -0 cscli lapi status - assert_stderr --partial "You can successfully interact with Local API (LAPI)" + assert_line "You can successfully interact with Local API (LAPI)" } @test "cscli metrics" { diff --git a/test/bats/08_metrics.bats b/test/bats/08_metrics.bats index 8bf30812c..fcbbc758f 100644 --- a/test/bats/08_metrics.bats +++ b/test/bats/08_metrics.bats @@ -25,7 +25,7 @@ teardown() { @test "cscli metrics (crowdsec not running)" { rune -1 cscli metrics # crowdsec is down - assert_stderr --partial 'failed to fetch metrics: executing GET request for URL \"http://127.0.0.1:6060/metrics\" failed: Get \"http://127.0.0.1:6060/metrics\": dial tcp 127.0.0.1:6060: connect: connection refused' + assert_stderr --partial 'Error: failed to fetch metrics: executing GET request for URL "http://127.0.0.1:6060/metrics" failed: Get "http://127.0.0.1:6060/metrics": dial tcp 127.0.0.1:6060: connect: connection refused' } @test "cscli metrics (bad configuration)" { diff --git a/test/bats/09_socket.bats b/test/bats/09_socket.bats index f770abaad..7fbc941a6 100644 --- a/test/bats/09_socket.bats +++ b/test/bats/09_socket.bats @@ -37,22 +37,22 @@ teardown() { ./instance-crowdsec start rune -0 cscli lapi status - assert_stderr --regexp "Trying to authenticate with username .* on $socket" - assert_stderr --partial "You can successfully interact with Local API (LAPI)" + assert_output --regexp "Trying to authenticate with username .* on $socket" + assert_line "You can successfully interact with Local API (LAPI)" } @test "crowdsec - listen on both socket and TCP" { ./instance-crowdsec start rune -0 cscli lapi status - assert_stderr --regexp "Trying to authenticate with username .* on http://127.0.0.1:8080/" - assert_stderr --partial "You can successfully interact with Local API (LAPI)" + assert_output --regexp "Trying to authenticate with username .* on http://127.0.0.1:8080/" + assert_line "You can successfully interact with Local API (LAPI)" config_set "$LOCAL_API_CREDENTIALS" ".url=strenv(socket)" rune -0 cscli lapi status - assert_stderr --regexp "Trying to authenticate with username .* on $socket" - assert_stderr --partial "You can successfully interact with Local API (LAPI)" + assert_output --regexp "Trying to authenticate with username .* on $socket" + assert_line "You can successfully interact with Local API (LAPI)" } @test "cscli - authenticate new machine with socket" { diff --git a/test/bats/10_bouncers.bats b/test/bats/10_bouncers.bats index 1ef39ceb0..99f839486 100644 --- a/test/bats/10_bouncers.bats +++ b/test/bats/10_bouncers.bats @@ -56,12 +56,9 @@ teardown() { @test "we can't add the same bouncer twice" { rune -0 cscli bouncers add ciTestBouncer - rune -1 cscli bouncers add ciTestBouncer -o json + rune -1 cscli bouncers add ciTestBouncer - # XXX temporary hack to filter out unwanted log lines that may appear before - # log configuration (= not json) - rune -0 jq -c '[.level,.msg]' <(stderr | grep "^{") - assert_output '["fatal","unable to create bouncer: bouncer ciTestBouncer already exists"]' + assert_stderr 'Error: unable to create bouncer: bouncer ciTestBouncer already exists' rune -0 cscli bouncers list -o json rune -0 jq '. | length' <(output) diff --git a/test/bats/20_hub_items.bats b/test/bats/20_hub_items.bats index 72e09dfa2..e71b05dc4 100644 --- a/test/bats/20_hub_items.bats +++ b/test/bats/20_hub_items.bats @@ -80,10 +80,8 @@ teardown() { echo "$new_hub" >"$INDEX_PATH" rune -0 cscli collections install crowdsecurity/sshd - rune -1 cscli collections inspect crowdsecurity/sshd --no-metrics -o json - # XXX: we are on the verbose side here... - rune -0 jq -r ".msg" <(stderr) - assert_output --regexp "failed to read Hub index: failed to sync items: failed to scan .*: while syncing collections sshd.yaml: 1.2.3.4: Invalid Semantic Version. Run 'sudo cscli hub update' to download the index again" + rune -1 cscli collections inspect crowdsecurity/sshd --no-metrics + assert_stderr --regexp "Error: failed to read Hub index: failed to sync items: failed to scan .*: while syncing collections sshd.yaml: 1.2.3.4: Invalid Semantic Version. Run 'sudo cscli hub update' to download the index again" } @test "removing or purging an item already removed by hand" { diff --git a/test/bats/30_machines.bats b/test/bats/30_machines.bats index 2a04cc9bc..b805c38dd 100644 --- a/test/bats/30_machines.bats +++ b/test/bats/30_machines.bats @@ -30,9 +30,8 @@ teardown() { } @test "don't overwrite local credentials by default" { - rune -1 cscli machines add local -a -o json - rune -0 jq -r '.msg' <(stderr) - assert_output --partial 'already exists: please remove it, use "--force" or specify a different file with "-f"' + rune -1 cscli machines add local -a + assert_stderr --regexp 'Error: credentials file '.*' already exists: please remove it, use "--force" or specify a different file with "-f"' rune -0 cscli machines add local -a --force assert_stderr --partial "Machine 'local' successfully added to the local API." } diff --git a/test/bats/90_decisions.bats b/test/bats/90_decisions.bats index 8a2b9d3ae..afa42b72f 100644 --- a/test/bats/90_decisions.bats +++ b/test/bats/90_decisions.bats @@ -34,9 +34,8 @@ teardown() { assert_line "Usage:" assert_stderr --partial "missing arguments, a value is required (--ip, --range or --scope and --value)" - rune -1 cscli decisions add -o json - rune -0 jq -c '[ .level, .msg]' <(stderr | grep "^{") - assert_output '["fatal","missing arguments, a value is required (--ip, --range or --scope and --value)"]' + rune -1 cscli decisions add + assert_stderr 'Error: missing arguments, a value is required (--ip, --range or --scope and --value)' } @test "cscli decisions list, with and without --machine" { @@ -62,20 +61,19 @@ teardown() { @test "cscli decisions list, incorrect parameters" { rune -1 cscli decisions list --until toto - assert_stderr --partial 'unable to retrieve decisions: performing request: API error: while parsing duration: time: invalid duration \"toto\"' - rune -1 cscli decisions list --until toto -o json - rune -0 jq -c '[.level, .msg]' <(stderr | grep "^{") - assert_output '["fatal","unable to retrieve decisions: performing request: API error: while parsing duration: time: invalid duration \"toto\""]' + assert_stderr 'Error: unable to retrieve decisions: performing request: API error: while parsing duration: time: invalid duration "toto"' + rune -1 cscli decisions list --until toto + assert_stderr 'Error: unable to retrieve decisions: performing request: API error: while parsing duration: time: invalid duration "toto"' } @test "cscli decisions import" { # required input rune -1 cscli decisions import - assert_stderr --partial 'required flag(s) \"input\" not set"' + assert_stderr --partial 'Error: required flag(s) "input" not set' # unsupported format rune -1 cscli decisions import -i - <<<'value\n5.6.7.8' --format xml - assert_stderr --partial "invalid format 'xml', expected one of 'json', 'csv', 'values'" + assert_stderr "Error: invalid format 'xml', expected one of 'json', 'csv', 'values'" # invalid defaults rune -1 cscli decisions import --duration "" -i - <<<'value\n5.6.7.8' --format csv