diff --git a/cmd/crowdsec-cli/ask/ask.go b/cmd/crowdsec-cli/ask/ask.go new file mode 100644 index 00000000000..484ccb30c8a --- /dev/null +++ b/cmd/crowdsec-cli/ask/ask.go @@ -0,0 +1,20 @@ +package ask + +import ( + "github.com/AlecAivazis/survey/v2" +) + +func YesNo(message string, defaultAnswer bool) (bool, error) { + var answer bool + + prompt := &survey.Confirm{ + Message: message, + Default: defaultAnswer, + } + + if err := survey.AskOne(prompt, &answer); err != nil { + return defaultAnswer, err + } + + return answer, nil +} diff --git a/cmd/crowdsec-cli/bouncers.go b/cmd/crowdsec-cli/bouncers.go index d3edcea0db9..68ce1a2fa05 100644 --- a/cmd/crowdsec-cli/bouncers.go +++ b/cmd/crowdsec-cli/bouncers.go @@ -11,12 +11,13 @@ import ( "strings" "time" - "github.com/AlecAivazis/survey/v2" "github.com/fatih/color" "github.com/jedib0t/go-pretty/v6/table" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/ask" + "github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/clientinfo" "github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/cstable" "github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require" middlewares "github.com/crowdsecurity/crowdsec/pkg/apiserver/middlewares/v1" @@ -27,55 +28,6 @@ import ( "github.com/crowdsecurity/crowdsec/pkg/types" ) -type featureflagProvider interface { - GetFeatureflags() string -} - -type osProvider interface { - GetOsname() string - GetOsversion() string -} - -func getOSNameAndVersion(o osProvider) string { - ret := o.GetOsname() - if o.GetOsversion() != "" { - if ret != "" { - ret += "/" - } - - ret += o.GetOsversion() - } - - if ret == "" { - return "?" - } - - return ret -} - -func getFeatureFlagList(o featureflagProvider) []string { - if o.GetFeatureflags() == "" { - return nil - } - - return strings.Split(o.GetFeatureflags(), ",") -} - -func askYesNo(message string, defaultAnswer bool) (bool, error) { - var answer bool - - prompt := &survey.Confirm{ - Message: message, - Default: defaultAnswer, - } - - if err := survey.AskOne(prompt, &answer); err != nil { - return defaultAnswer, err - } - - return answer, nil -} - type cliBouncers struct { db *database.Client cfg configGetter @@ -171,8 +123,8 @@ func newBouncerInfo(b *ent.Bouncer) bouncerInfo { Version: b.Version, LastPull: b.LastPull, AuthType: b.AuthType, - OS: getOSNameAndVersion(b), - Featureflags: getFeatureFlagList(b), + OS: clientinfo.GetOSNameAndVersion(b), + Featureflags: clientinfo.GetFeatureFlagList(b), } } @@ -385,7 +337,7 @@ func (cli *cliBouncers) newDeleteCmd() *cobra.Command { func (cli *cliBouncers) prune(duration time.Duration, force bool) error { if duration < 2*time.Minute { - if yes, err := askYesNo( + if yes, err := ask.YesNo( "The duration you provided is less than 2 minutes. "+ "This may remove active bouncers. Continue?", false); err != nil { return err @@ -408,7 +360,7 @@ func (cli *cliBouncers) prune(duration time.Duration, force bool) error { cli.listHuman(color.Output, bouncers) if !force { - if yes, err := askYesNo( + if yes, err := ask.YesNo( "You are about to PERMANENTLY remove the above bouncers from the database. "+ "These will NOT be recoverable. Continue?", false); err != nil { return err @@ -478,10 +430,10 @@ func (cli *cliBouncers) inspectHuman(out io.Writer, bouncer *ent.Bouncer) { {"Version", bouncer.Version}, {"Last Pull", lastPull}, {"Auth type", bouncer.AuthType}, - {"OS", getOSNameAndVersion(bouncer)}, + {"OS", clientinfo.GetOSNameAndVersion(bouncer)}, }) - for _, ff := range getFeatureFlagList(bouncer) { + for _, ff := range clientinfo.GetFeatureFlagList(bouncer) { t.AppendRow(table.Row{"Feature Flags", ff}) } diff --git a/cmd/crowdsec-cli/clientinfo/clientinfo.go b/cmd/crowdsec-cli/clientinfo/clientinfo.go new file mode 100644 index 00000000000..0bf1d98804f --- /dev/null +++ b/cmd/crowdsec-cli/clientinfo/clientinfo.go @@ -0,0 +1,39 @@ +package clientinfo + +import ( + "strings" +) + +type featureflagProvider interface { + GetFeatureflags() string +} + +type osProvider interface { + GetOsname() string + GetOsversion() string +} + +func GetOSNameAndVersion(o osProvider) string { + ret := o.GetOsname() + if o.GetOsversion() != "" { + if ret != "" { + ret += "/" + } + + ret += o.GetOsversion() + } + + if ret == "" { + return "?" + } + + return ret +} + +func GetFeatureFlagList(o featureflagProvider) []string { + if o.GetFeatureflags() == "" { + return nil + } + + return strings.Split(o.GetFeatureflags(), ",") +} diff --git a/cmd/crowdsec-cli/machines.go b/cmd/crowdsec-cli/machines.go index 34d0b1b9208..8b35245405f 100644 --- a/cmd/crowdsec-cli/machines.go +++ b/cmd/crowdsec-cli/machines.go @@ -19,6 +19,8 @@ import ( "github.com/spf13/cobra" "gopkg.in/yaml.v3" + "github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/ask" + "github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/clientinfo" "github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/cstable" "github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/idgen" "github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require" @@ -138,7 +140,7 @@ func (cli *cliMachines) listHuman(out io.Writer, machines ent.Machines) { hb = emoji.Warning + " " + hb } - t.AppendRow(table.Row{m.MachineId, m.IpAddress, m.UpdatedAt.Format(time.RFC3339), validated, m.Version, getOSNameAndVersion(m), m.AuthType, hb}) + t.AppendRow(table.Row{m.MachineId, m.IpAddress, m.UpdatedAt.Format(time.RFC3339), validated, m.Version, clientinfo.GetOSNameAndVersion(m), m.AuthType, hb}) } io.WriteString(out, t.Render() + "\n") @@ -171,8 +173,8 @@ func newMachineInfo(m *ent.Machine) machineInfo { Version: m.Version, IsValidated: m.IsValidated, AuthType: m.AuthType, - OS: getOSNameAndVersion(m), - Featureflags: getFeatureFlagList(m), + OS: clientinfo.GetOSNameAndVersion(m), + Featureflags: clientinfo.GetFeatureFlagList(m), Datasources: m.Datasources, } } @@ -466,7 +468,7 @@ func (cli *cliMachines) newDeleteCmd() *cobra.Command { func (cli *cliMachines) prune(duration time.Duration, notValidOnly bool, force bool) error { if duration < 2*time.Minute && !notValidOnly { - if yes, err := askYesNo( + if yes, err := ask.YesNo( "The duration you provided is less than 2 minutes. "+ "This can break installations if the machines are only temporarily disconnected. Continue?", false); err != nil { return err @@ -495,7 +497,7 @@ func (cli *cliMachines) prune(duration time.Duration, notValidOnly bool, force b cli.listHuman(color.Output, machines) if !force { - if yes, err := askYesNo( + if yes, err := ask.YesNo( "You are about to PERMANENTLY remove the above machines from the database. "+ "These will NOT be recoverable. Continue?", false); err != nil { return err @@ -588,7 +590,7 @@ func (cli *cliMachines) inspectHuman(out io.Writer, machine *ent.Machine) { {"Last Heartbeat", machine.LastHeartbeat}, {"Validated?", machine.IsValidated}, {"CrowdSec version", machine.Version}, - {"OS", getOSNameAndVersion(machine)}, + {"OS", clientinfo.GetOSNameAndVersion(machine)}, {"Auth type", machine.AuthType}, }) @@ -596,7 +598,7 @@ func (cli *cliMachines) inspectHuman(out io.Writer, machine *ent.Machine) { t.AppendRow(table.Row{"Datasources", fmt.Sprintf("%s: %d", dsName, dsCount)}) } - for _, ff := range getFeatureFlagList(machine) { + for _, ff := range clientinfo.GetFeatureFlagList(machine) { t.AppendRow(table.Row{"Feature Flags", ff}) }