Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cscli tests + fix bouncer/machine prune #2883

Merged
merged 4 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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.'
}