Skip to content

Commit

Permalink
cscli tests + fix bouncer/machine prune (#2883)
Browse files Browse the repository at this point in the history
* func tests: "cscli config feature-flags"
* func tests: "cscli bouncers list"
* func tests + fix: "cscli bouncers/machines prune"
* lint
  • Loading branch information
mmetc authored Mar 11, 2024
1 parent 6daaab1 commit 49e0735
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 20 deletions.
2 changes: 1 addition & 1 deletion cmd/crowdsec-cli/bouncers.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ func (cli *cliBouncers) prune(duration time.Duration, force bool) error {
}
}

bouncers, err := cli.db.QueryBouncersLastPulltimeLT(time.Now().UTC().Add(duration))
bouncers, err := cli.db.QueryBouncersLastPulltimeLT(time.Now().UTC().Add(-duration))
if err != nil {
return fmt.Errorf("unable to query bouncers: %w", err)
}
Expand Down
37 changes: 19 additions & 18 deletions cmd/crowdsec-cli/machines.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
saferand "crypto/rand"
"encoding/csv"
"encoding/json"
"errors"
"fmt"
"math/big"
"os"
Expand Down Expand Up @@ -134,7 +135,7 @@ Note: This command requires database direct access, so is intended to be run on
}
cli.db, err = database.NewClient(cli.cfg().DbConfig)
if err != nil {
return fmt.Errorf("unable to create new database client: %s", err)
return fmt.Errorf("unable to create new database client: %w", err)
}

return nil
Expand All @@ -155,7 +156,7 @@ func (cli *cliMachines) list() error {

machines, err := cli.db.ListMachines()
if err != nil {
return fmt.Errorf("unable to list machines: %s", err)
return fmt.Errorf("unable to list machines: %w", err)
}

switch cli.cfg().Cscli.Output {
Expand All @@ -166,7 +167,7 @@ func (cli *cliMachines) list() error {
enc.SetIndent("", " ")

if err := enc.Encode(machines); err != nil {
return fmt.Errorf("failed to marshal")
return errors.New("failed to marshal")
}

return nil
Expand All @@ -175,7 +176,7 @@ func (cli *cliMachines) list() error {

err := csvwriter.Write([]string{"machine_id", "ip_address", "updated_at", "validated", "version", "auth_type", "last_heartbeat"})
if err != nil {
return fmt.Errorf("failed to write header: %s", err)
return fmt.Errorf("failed to write header: %w", err)
}

for _, m := range machines {
Expand Down Expand Up @@ -257,12 +258,12 @@ func (cli *cliMachines) add(args []string, machinePassword string, dumpFile stri
// create machineID if not specified by user
if len(args) == 0 {
if !autoAdd {
return fmt.Errorf("please specify a machine name to add, or use --auto")
return errors.New("please specify a machine name to add, or use --auto")
}

machineID, err = generateID("")
if err != nil {
return fmt.Errorf("unable to generate machine id: %s", err)
return fmt.Errorf("unable to generate machine id: %w", err)
}
} else {
machineID = args[0]
Expand All @@ -281,20 +282,20 @@ func (cli *cliMachines) add(args []string, machinePassword string, dumpFile stri
case os.IsNotExist(err) || force:
dumpFile = credFile
case err != nil:
return fmt.Errorf("unable to stat '%s': %s", credFile, err)
return fmt.Errorf("unable to stat '%s': %w", credFile, err)
default:
return fmt.Errorf(`credentials file '%s' already exists: please remove it, use "--force" or specify a different file with "-f" ("-f -" for standard output)`, credFile)
}
}

if dumpFile == "" {
return fmt.Errorf(`please specify a file to dump credentials to, with -f ("-f -" for standard output)`)
return errors.New(`please specify a file to dump credentials to, with -f ("-f -" for standard output)`)
}

// create a password if it's not specified by user
if machinePassword == "" && !interactive {
if !autoAdd {
return fmt.Errorf("please specify a password with --password or use --auto")
return errors.New("please specify a password with --password or use --auto")
}

machinePassword = generatePassword(passwordLength)
Expand All @@ -309,7 +310,7 @@ func (cli *cliMachines) add(args []string, machinePassword string, dumpFile stri

_, err = cli.db.CreateMachine(&machineID, &password, "", true, force, types.PasswordAuthType)
if err != nil {
return fmt.Errorf("unable to create machine: %s", err)
return fmt.Errorf("unable to create machine: %w", err)
}

fmt.Fprintf(os.Stderr, "Machine '%s' successfully added to the local API.\n", machineID)
Expand All @@ -320,7 +321,7 @@ func (cli *cliMachines) add(args []string, machinePassword string, dumpFile stri
} else if serverCfg != nil && serverCfg.ListenURI != "" {
apiURL = "http://" + serverCfg.ListenURI
} else {
return fmt.Errorf("unable to dump an api URL. Please provide it in your configuration or with the -u parameter")
return errors.New("unable to dump an api URL. Please provide it in your configuration or with the -u parameter")
}
}

Expand All @@ -332,12 +333,12 @@ func (cli *cliMachines) add(args []string, machinePassword string, dumpFile stri

apiConfigDump, err := yaml.Marshal(apiCfg)
if err != nil {
return fmt.Errorf("unable to marshal api credentials: %s", err)
return fmt.Errorf("unable to marshal api credentials: %w", err)
}

if dumpFile != "" && dumpFile != "-" {
if err = os.WriteFile(dumpFile, apiConfigDump, 0o600); err != nil {
return fmt.Errorf("write api credentials in '%s' failed: %s", dumpFile, err)
return fmt.Errorf("write api credentials in '%s' failed: %w", dumpFile, err)
}

fmt.Fprintf(os.Stderr, "API credentials written to '%s'.\n", dumpFile)
Expand Down Expand Up @@ -413,13 +414,13 @@ func (cli *cliMachines) prune(duration time.Duration, notValidOnly bool, force b
}

if !notValidOnly {
if pending, err := cli.db.QueryLastValidatedHeartbeatLT(time.Now().UTC().Add(duration)); err == nil {
if pending, err := cli.db.QueryLastValidatedHeartbeatLT(time.Now().UTC().Add(-duration)); err == nil {
machines = append(machines, pending...)
}
}

if len(machines) == 0 {
fmt.Println("no machines to prune")
fmt.Println("No machines to prune.")
return nil
}

Expand All @@ -438,7 +439,7 @@ func (cli *cliMachines) prune(duration time.Duration, notValidOnly bool, force b

deleted, err := cli.db.BulkDeleteWatchers(machines)
if err != nil {
return fmt.Errorf("unable to prune machines: %s", err)
return fmt.Errorf("unable to prune machines: %w", err)
}

fmt.Fprintf(os.Stderr, "successfully delete %d machines\n", deleted)
Expand Down Expand Up @@ -479,7 +480,7 @@ cscli machines prune --not-validated-only --force`,

func (cli *cliMachines) validate(machineID string) error {
if err := cli.db.ValidateMachine(machineID); err != nil {
return fmt.Errorf("unable to validate machine '%s': %s", machineID, err)
return fmt.Errorf("unable to validate machine '%s': %w", machineID, err)
}

log.Infof("machine '%s' validated successfully", machineID)
Expand All @@ -495,7 +496,7 @@ func (cli *cliMachines) newValidateCmd() *cobra.Command {
Example: `cscli machines validate "machine_name"`,
Args: cobra.ExactArgs(1),
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, args []string) error {
return cli.validate(args[0])
},
}
Expand Down
21 changes: 21 additions & 0 deletions test/bats/01_cscli.bats
Original file line number Diff line number Diff line change
Expand Up @@ -358,3 +358,24 @@ teardown() {
rune -0 cscli setup
assert_output --partial 'cscli setup [command]'
}

@test "cscli config feature-flags" {
# disabled
rune -0 cscli config feature-flags
assert_line '✗ cscli_setup: Enable cscli setup command (service detection)'

# enabled in feature.yaml
CONFIG_DIR=$(dirname "$CONFIG_YAML")
echo ' - cscli_setup' >> "$CONFIG_DIR"/feature.yaml
rune -0 cscli config feature-flags
assert_line '✓ cscli_setup: Enable cscli setup command (service detection)'

# enabled in environment
# shellcheck disable=SC2031
export CROWDSEC_FEATURE_CSCLI_SETUP="true"
rune -0 cscli config feature-flags
assert_line '✓ cscli_setup: Enable cscli setup command (service detection)'

# there are no retired features
rune -0 cscli config feature-flags --retired
}
18 changes: 17 additions & 1 deletion test/bats/10_bouncers.bats
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,13 @@ teardown() {

@test "there are 0 bouncers" {
rune -0 cscli bouncers list -o json
assert_output "[]"
assert_json '[]'

rune -0 cscli bouncers list -o human
assert_output --partial "Name"

rune -0 cscli bouncers list -o raw
assert_output --partial 'name'
}

@test "we can add one bouncer, and delete it" {
Expand Down Expand Up @@ -68,3 +74,13 @@ teardown() {
rune -1 cscli bouncers delete ciTestBouncer
rune -1 cscli bouncers delete foobarbaz
}

@test "cscli bouncers prune" {
rune -0 cscli bouncers prune
assert_output 'No bouncers to prune.'
rune -0 cscli bouncers add ciTestBouncer

rune -0 cscli bouncers prune
assert_output 'No bouncers to prune.'
}

14 changes: 14 additions & 0 deletions test/bats/30_machines.bats
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,17 @@ teardown() {
rune -0 jq '. | length' <(output)
assert_output 1
}

@test "cscli machines prune" {
rune -0 cscli metrics

rune -0 cscli machines prune
assert_output 'No machines to prune.'

rune -0 cscli machines list -o json
rune -0 jq -r '.[-1].machineId' <(output)
rune -0 cscli machines delete "$output"

rune -0 cscli machines prune
assert_output 'No machines to prune.'
}

0 comments on commit 49e0735

Please sign in to comment.