refact "cscli" root cmd (#2811)

* refact "cscli" root cmd
* lint (naming, imports, whitespace)
This commit is contained in:
mmetc 2024-02-06 10:50:28 +01:00 committed by GitHub
parent fdc525164a
commit 4e724f6c0a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 198 additions and 139 deletions

View file

@ -53,7 +53,7 @@ linters-settings:
nestif: nestif:
# lower this after refactoring # lower this after refactoring
min-complexity: 27 min-complexity: 28
nlreturn: nlreturn:
block-size: 4 block-size: 4

View file

@ -36,13 +36,13 @@ func askYesNo(message string, defaultAnswer bool) (bool, error) {
} }
type cliBouncers struct { type cliBouncers struct {
db *database.Client db *database.Client
cfg configGetter cfg configGetter
} }
func NewCLIBouncers(getconfig configGetter) *cliBouncers { func NewCLIBouncers(cfg configGetter) *cliBouncers {
return &cliBouncers{ return &cliBouncers{
cfg: getconfig, cfg: cfg,
} }
} }
@ -197,13 +197,13 @@ cscli bouncers add MyBouncerName --key <random-key>`,
return cmd return cmd
} }
func (cli *cliBouncers) deleteValid(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { func (cli *cliBouncers) deleteValid(_ *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
bouncers, err := cli.db.ListBouncers() bouncers, err := cli.db.ListBouncers()
if err != nil { if err != nil {
cobra.CompError("unable to list bouncers " + err.Error()) cobra.CompError("unable to list bouncers " + err.Error())
} }
ret :=[]string{} ret := []string{}
for _, bouncer := range bouncers { for _, bouncer := range bouncers {
if strings.Contains(bouncer.Name, toComplete) && !slices.Contains(args, bouncer.Name) { if strings.Contains(bouncer.Name, toComplete) && !slices.Contains(args, bouncer.Name) {

View file

@ -146,7 +146,12 @@ func restoreConfigFromDirectory(dirPath string, oldBackup bool) error {
// Now we have config.yaml, we should regenerate config struct to have rights paths etc // Now we have config.yaml, we should regenerate config struct to have rights paths etc
ConfigFilePath = fmt.Sprintf("%s/config.yaml", csConfig.ConfigPaths.ConfigDir) ConfigFilePath = fmt.Sprintf("%s/config.yaml", csConfig.ConfigPaths.ConfigDir)
initConfig() log.Debug("Reloading configuration")
csConfig, _, err = loadConfigFor("config")
if err != nil {
return fmt.Errorf("failed to reload configuration: %s", err)
}
backupCAPICreds := fmt.Sprintf("%s/online_api_credentials.yaml", dirPath) backupCAPICreds := fmt.Sprintf("%s/online_api_credentials.yaml", dirPath)
if _, err = os.Stat(backupCAPICreds); err == nil { if _, err = os.Stat(backupCAPICreds); err == nil {
@ -227,7 +232,7 @@ func restoreConfigFromDirectory(dirPath string, oldBackup bool) error {
} }
} }
// if there is files in the acquis backup dir, restore them // if there are files in the acquis backup dir, restore them
acquisBackupDir := filepath.Join(dirPath, "acquis", "*.yaml") acquisBackupDir := filepath.Join(dirPath, "acquis", "*.yaml")
if acquisFiles, err := filepath.Glob(acquisBackupDir); err == nil { if acquisFiles, err := filepath.Glob(acquisBackupDir); err == nil {
for _, acquisFile := range acquisFiles { for _, acquisFile := range acquisFiles {

View file

@ -19,15 +19,14 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/crowdsecurity/crowdsec/pkg/metabase"
"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require" "github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require"
"github.com/crowdsecurity/crowdsec/pkg/metabase"
) )
var ( var (
metabaseUser = "crowdsec@crowdsec.net" metabaseUser = "crowdsec@crowdsec.net"
metabasePassword string metabasePassword string
metabaseDbPath string metabaseDBPath string
metabaseConfigPath string metabaseConfigPath string
metabaseConfigFolder = "metabase/" metabaseConfigFolder = "metabase/"
metabaseConfigFile = "metabase.yaml" metabaseConfigFile = "metabase.yaml"
@ -43,13 +42,13 @@ var (
// information needed to set up a random password on user's behalf // information needed to set up a random password on user's behalf
) )
type cliDashboard struct{ type cliDashboard struct {
cfg configGetter cfg configGetter
} }
func NewCLIDashboard(getconfig configGetter) *cliDashboard { func NewCLIDashboard(cfg configGetter) *cliDashboard {
return &cliDashboard{ return &cliDashboard{
cfg: getconfig, cfg: cfg,
} }
} }
@ -99,6 +98,7 @@ cscli dashboard remove
metabaseContainerID = oldContainerID metabaseContainerID = oldContainerID
} }
} }
return nil return nil
}, },
} }
@ -127,8 +127,8 @@ cscli dashboard setup --listen 0.0.0.0
cscli dashboard setup -l 0.0.0.0 -p 443 --password <password> cscli dashboard setup -l 0.0.0.0 -p 443 --password <password>
`, `,
RunE: func(_ *cobra.Command, _ []string) error { RunE: func(_ *cobra.Command, _ []string) error {
if metabaseDbPath == "" { if metabaseDBPath == "" {
metabaseDbPath = cli.cfg().ConfigPaths.DataDir metabaseDBPath = cli.cfg().ConfigPaths.DataDir
} }
if metabasePassword == "" { if metabasePassword == "" {
@ -152,7 +152,7 @@ cscli dashboard setup -l 0.0.0.0 -p 443 --password <password>
if err = cli.chownDatabase(dockerGroup.Gid); err != nil { if err = cli.chownDatabase(dockerGroup.Gid); err != nil {
return err return err
} }
mb, err := metabase.SetupMetabase(cli.cfg().API.Server.DbConfig, metabaseListenAddress, metabaseListenPort, metabaseUser, metabasePassword, metabaseDbPath, dockerGroup.Gid, metabaseContainerID, metabaseImage) mb, err := metabase.SetupMetabase(cli.cfg().API.Server.DbConfig, metabaseListenAddress, metabaseListenPort, metabaseUser, metabasePassword, metabaseDBPath, dockerGroup.Gid, metabaseContainerID, metabaseImage)
if err != nil { if err != nil {
return err return err
} }
@ -165,13 +165,14 @@ cscli dashboard setup -l 0.0.0.0 -p 443 --password <password>
fmt.Printf("\tURL : '%s'\n", mb.Config.ListenURL) fmt.Printf("\tURL : '%s'\n", mb.Config.ListenURL)
fmt.Printf("\tusername : '%s'\n", mb.Config.Username) fmt.Printf("\tusername : '%s'\n", mb.Config.Username)
fmt.Printf("\tpassword : '%s'\n", mb.Config.Password) fmt.Printf("\tpassword : '%s'\n", mb.Config.Password)
return nil return nil
}, },
} }
flags := cmd.Flags() flags := cmd.Flags()
flags.BoolVarP(&force, "force", "f", false, "Force setup : override existing files") flags.BoolVarP(&force, "force", "f", false, "Force setup : override existing files")
flags.StringVarP(&metabaseDbPath, "dir", "d", "", "Shared directory with metabase container") flags.StringVarP(&metabaseDBPath, "dir", "d", "", "Shared directory with metabase container")
flags.StringVarP(&metabaseListenAddress, "listen", "l", metabaseListenAddress, "Listen address of container") flags.StringVarP(&metabaseListenAddress, "listen", "l", metabaseListenAddress, "Listen address of container")
flags.StringVar(&metabaseImage, "metabase-image", metabaseImage, "Metabase image to use") flags.StringVar(&metabaseImage, "metabase-image", metabaseImage, "Metabase image to use")
flags.StringVarP(&metabaseListenPort, "port", "p", metabaseListenPort, "Listen port of container") flags.StringVarP(&metabaseListenPort, "port", "p", metabaseListenPort, "Listen port of container")
@ -203,6 +204,7 @@ func (cli *cliDashboard) newStartCmd() *cobra.Command {
} }
log.Infof("Started metabase") log.Infof("Started metabase")
log.Infof("url : http://%s:%s", mb.Config.ListenAddr, mb.Config.ListenPort) log.Infof("url : http://%s:%s", mb.Config.ListenAddr, mb.Config.ListenPort)
return nil return nil
}, },
} }
@ -241,6 +243,7 @@ func (cli *cliDashboard) newShowPasswordCmd() *cobra.Command {
return err return err
} }
log.Printf("'%s'", m.Config.Password) log.Printf("'%s'", m.Config.Password)
return nil return nil
}, },
} }
@ -313,6 +316,7 @@ cscli dashboard remove --force
} }
} }
} }
return nil return nil
}, },
} }

View file

@ -13,9 +13,9 @@ type cliDashboard struct{
cfg configGetter cfg configGetter
} }
func NewCLIDashboard(getconfig configGetter) *cliDashboard { func NewCLIDashboard(cfg configGetter) *cliDashboard {
return &cliDashboard{ return &cliDashboard{
cfg: getconfig, cfg: cfg,
} }
} }

View file

@ -116,14 +116,13 @@ func (cli *cliDecisions) decisionsToTable(alerts *models.GetAlertsResponse, prin
return nil return nil
} }
type cliDecisions struct { type cliDecisions struct {
cfg configGetter cfg configGetter
} }
func NewCLIDecisions(getconfig configGetter) *cliDecisions { func NewCLIDecisions(cfg configGetter) *cliDecisions {
return &cliDecisions{ return &cliDecisions{
cfg: getconfig, cfg: cfg,
} }
} }
@ -157,6 +156,7 @@ func (cli *cliDecisions) NewCommand() *cobra.Command {
if err != nil { if err != nil {
return fmt.Errorf("creating api client: %w", err) return fmt.Errorf("creating api client: %w", err)
} }
return nil return nil
}, },
} }
@ -393,6 +393,7 @@ cscli decisions add --scope username --value foobar
} }
log.Info("Decision successfully added") log.Info("Decision successfully added")
return nil return nil
}, },
} }
@ -499,6 +500,7 @@ cscli decisions delete --type captcha
} }
} }
log.Infof("%s decision(s) deleted", decisions.NbDeleted) log.Infof("%s decision(s) deleted", decisions.NbDeleted)
return nil return nil
}, },
} }

View file

@ -13,13 +13,13 @@ import (
"github.com/crowdsecurity/crowdsec/pkg/cwhub" "github.com/crowdsecurity/crowdsec/pkg/cwhub"
) )
type cliHub struct{ type cliHub struct {
cfg configGetter cfg configGetter
} }
func NewCLIHub(getconfig configGetter) *cliHub { func NewCLIHub(cfg configGetter) *cliHub {
return &cliHub{ return &cliHub{
cfg: getconfig, cfg: cfg,
} }
} }

View file

@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"os" "os"
"slices"
"strings" "strings"
"time" "time"
@ -17,7 +18,6 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"slices"
"github.com/crowdsecurity/machineid" "github.com/crowdsecurity/machineid"
@ -106,14 +106,14 @@ func getLastHeartbeat(m *ent.Machine) (string, bool) {
return hb, true return hb, true
} }
type cliMachines struct{ type cliMachines struct {
db *database.Client db *database.Client
cfg configGetter cfg configGetter
} }
func NewCLIMachines(getconfig configGetter) *cliMachines { func NewCLIMachines(cfg configGetter) *cliMachines {
return &cliMachines{ return &cliMachines{
cfg: getconfig, cfg: cfg,
} }
} }
@ -136,6 +136,7 @@ Note: This command requires database direct access, so is intended to be run on
if err != nil { if err != nil {
return fmt.Errorf("unable to create new database client: %s", err) return fmt.Errorf("unable to create new database client: %s", err)
} }
return nil return nil
}, },
} }
@ -249,7 +250,7 @@ cscli machines add -f- --auto > /tmp/mycreds.yaml`,
func (cli *cliMachines) add(args []string, machinePassword string, dumpFile string, apiURL string, interactive bool, autoAdd bool, force bool) error { func (cli *cliMachines) add(args []string, machinePassword string, dumpFile string, apiURL string, interactive bool, autoAdd bool, force bool) error {
var ( var (
err error err error
machineID string machineID string
) )
@ -347,7 +348,7 @@ func (cli *cliMachines) add(args []string, machinePassword string, dumpFile stri
return nil return nil
} }
func (cli *cliMachines) deleteValid(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { func (cli *cliMachines) deleteValid(_ *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
machines, err := cli.db.ListMachines() machines, err := cli.db.ListMachines()
if err != nil { if err != nil {
cobra.CompError("unable to list machines " + err.Error()) cobra.CompError("unable to list machines " + err.Error())
@ -447,9 +448,9 @@ func (cli *cliMachines) prune(duration time.Duration, notValidOnly bool, force b
func (cli *cliMachines) newPruneCmd() *cobra.Command { func (cli *cliMachines) newPruneCmd() *cobra.Command {
var ( var (
duration time.Duration duration time.Duration
notValidOnly bool notValidOnly bool
force bool force bool
) )
const defaultDuration = 10 * time.Minute const defaultDuration = 10 * time.Minute

View file

@ -15,45 +15,88 @@ import (
"github.com/crowdsecurity/crowdsec/pkg/fflag" "github.com/crowdsecurity/crowdsec/pkg/fflag"
) )
var trace_lvl, dbg_lvl, nfo_lvl, wrn_lvl, err_lvl bool
var ConfigFilePath string var ConfigFilePath string
var csConfig *csconfig.Config var csConfig *csconfig.Config
var dbClient *database.Client var dbClient *database.Client
var outputFormat string type configGetter func() *csconfig.Config
var OutputColor string
var mergedConfig string var mergedConfig string
// flagBranch overrides the value in csConfig.Cscli.HubBranch type cliRoot struct {
var flagBranch = "" logTrace bool
logDebug bool
logInfo bool
logWarn bool
logErr bool
outputColor string
outputFormat string
// flagBranch overrides the value in csConfig.Cscli.HubBranch
flagBranch string
}
type configGetter func() *csconfig.Config func newCliRoot() *cliRoot {
return &cliRoot{}
}
func initConfig() { // cfg() is a helper function to get the configuration loaded from config.yaml,
var err error // we pass it to subcommands because the file is not read until the Execute() call
func (cli *cliRoot) cfg() *csconfig.Config {
return csConfig
}
if trace_lvl { // wantedLogLevel returns the log level requested in the command line flags.
log.SetLevel(log.TraceLevel) func (cli *cliRoot) wantedLogLevel() log.Level {
} else if dbg_lvl { switch {
log.SetLevel(log.DebugLevel) case cli.logTrace:
} else if nfo_lvl { return log.TraceLevel
log.SetLevel(log.InfoLevel) case cli.logDebug:
} else if wrn_lvl { return log.DebugLevel
log.SetLevel(log.WarnLevel) case cli.logInfo:
} else if err_lvl { return log.InfoLevel
log.SetLevel(log.ErrorLevel) case cli.logWarn:
return log.WarnLevel
case cli.logErr:
return log.ErrorLevel
default:
return log.InfoLevel
}
}
// loadConfigFor loads the configuration file for the given sub-command.
// If the sub-command does not need it, it returns a default configuration.
func loadConfigFor(command string) (*csconfig.Config, string, error) {
noNeedConfig := []string{
"doc",
"help",
"completion",
"version",
"hubtest",
} }
if !slices.Contains(NoNeedConfig, os.Args[1]) { if !slices.Contains(noNeedConfig, command) {
log.Debugf("Using %s as configuration file", ConfigFilePath) log.Debugf("Using %s as configuration file", ConfigFilePath)
csConfig, mergedConfig, err = csconfig.NewConfig(ConfigFilePath, false, false, true)
config, merged, err := csconfig.NewConfig(ConfigFilePath, false, false, true)
if err != nil { if err != nil {
log.Fatal(err) return nil, "", err
} }
} else {
csConfig = csconfig.NewDefaultConfig() return config, merged, nil
}
return csconfig.NewDefaultConfig(), "", nil
}
// initialize is called before the subcommand is executed.
func (cli *cliRoot) initialize() {
var err error
log.SetLevel(cli.wantedLogLevel())
csConfig, mergedConfig, err = loadConfigFor(os.Args[1])
if err != nil {
log.Fatal(err)
} }
// recap of the enabled feature flags, because logging // recap of the enabled feature flags, because logging
@ -62,12 +105,12 @@ func initConfig() {
log.Debugf("Enabled feature flags: %s", fflist) log.Debugf("Enabled feature flags: %s", fflist)
} }
if flagBranch != "" { if cli.flagBranch != "" {
csConfig.Cscli.HubBranch = flagBranch csConfig.Cscli.HubBranch = cli.flagBranch
} }
if outputFormat != "" { if cli.outputFormat != "" {
csConfig.Cscli.Output = outputFormat csConfig.Cscli.Output = cli.outputFormat
} }
if csConfig.Cscli.Output == "" { if csConfig.Cscli.Output == "" {
@ -85,11 +128,11 @@ func initConfig() {
log.SetLevel(log.ErrorLevel) log.SetLevel(log.ErrorLevel)
} }
if OutputColor != "" { if cli.outputColor != "" {
csConfig.Cscli.Color = OutputColor csConfig.Cscli.Color = cli.outputColor
if OutputColor != "yes" && OutputColor != "no" && OutputColor != "auto" { if cli.outputColor != "yes" && cli.outputColor != "no" && cli.outputColor != "auto" {
log.Fatalf("output color %s unknown", OutputColor) log.Fatalf("output color %s unknown", cli.outputColor)
} }
} }
} }
@ -102,15 +145,25 @@ var validArgs = []string{
"postoverflows", "scenarios", "simulation", "support", "version", "postoverflows", "scenarios", "simulation", "support", "version",
} }
var NoNeedConfig = []string{ func (cli *cliRoot) colorize(cmd *cobra.Command) {
"doc", cc.Init(&cc.Config{
"help", RootCmd: cmd,
"completion", Headings: cc.Yellow,
"version", Commands: cc.Green + cc.Bold,
"hubtest", CmdShortDescr: cc.Cyan,
Example: cc.Italic,
ExecName: cc.Bold,
Aliases: cc.Bold + cc.Italic,
FlagsDataType: cc.White,
Flags: cc.Green,
FlagsDescr: cc.Cyan,
NoExtraNewlines: true,
NoBottomNewline: true,
})
cmd.SetOut(color.Output)
} }
func main() { func (cli *cliRoot) NewCommand() *cobra.Command {
// set the formatter asap and worry about level later // set the formatter asap and worry about level later
logFormatter := &log.TextFormatter{TimestampFormat: time.RFC3339, FullTimestamp: true} logFormatter := &log.TextFormatter{TimestampFormat: time.RFC3339, FullTimestamp: true}
log.SetFormatter(logFormatter) log.SetFormatter(logFormatter)
@ -135,33 +188,25 @@ It is meant to allow you to manage bans, parsers/scenarios/etc, api and generall
/*TBD examples*/ /*TBD examples*/
} }
cc.Init(&cc.Config{ cli.colorize(cmd)
RootCmd: cmd,
Headings: cc.Yellow,
Commands: cc.Green + cc.Bold,
CmdShortDescr: cc.Cyan,
Example: cc.Italic,
ExecName: cc.Bold,
Aliases: cc.Bold + cc.Italic,
FlagsDataType: cc.White,
Flags: cc.Green,
FlagsDescr: cc.Cyan,
NoExtraNewlines: true,
NoBottomNewline: true,
})
cmd.SetOut(color.Output)
cmd.PersistentFlags().StringVarP(&ConfigFilePath, "config", "c", csconfig.DefaultConfigPath("config.yaml"), "path to crowdsec config file") /*don't sort flags so we can enforce order*/
cmd.PersistentFlags().StringVarP(&outputFormat, "output", "o", "", "Output format: human, json, raw") cmd.Flags().SortFlags = false
cmd.PersistentFlags().StringVarP(&OutputColor, "color", "", "auto", "Output color: yes, no, auto")
cmd.PersistentFlags().BoolVar(&dbg_lvl, "debug", false, "Set logging to debug")
cmd.PersistentFlags().BoolVar(&nfo_lvl, "info", false, "Set logging to info")
cmd.PersistentFlags().BoolVar(&wrn_lvl, "warning", false, "Set logging to warning")
cmd.PersistentFlags().BoolVar(&err_lvl, "error", false, "Set logging to error")
cmd.PersistentFlags().BoolVar(&trace_lvl, "trace", false, "Set logging to trace")
cmd.PersistentFlags().StringVar(&flagBranch, "branch", "", "Override hub branch on github")
if err := cmd.PersistentFlags().MarkHidden("branch"); err != nil { pflags := cmd.PersistentFlags()
pflags.SortFlags = false
pflags.StringVarP(&ConfigFilePath, "config", "c", csconfig.DefaultConfigPath("config.yaml"), "path to crowdsec config file")
pflags.StringVarP(&cli.outputFormat, "output", "o", "", "Output format: human, json, raw")
pflags.StringVarP(&cli.outputColor, "color", "", "auto", "Output color: yes, no, auto")
pflags.BoolVar(&cli.logDebug, "debug", false, "Set logging to debug")
pflags.BoolVar(&cli.logInfo, "info", false, "Set logging to info")
pflags.BoolVar(&cli.logWarn, "warning", false, "Set logging to warning")
pflags.BoolVar(&cli.logErr, "error", false, "Set logging to error")
pflags.BoolVar(&cli.logTrace, "trace", false, "Set logging to trace")
pflags.StringVar(&cli.flagBranch, "branch", "", "Override hub branch on github")
if err := pflags.MarkHidden("branch"); err != nil {
log.Fatalf("failed to hide flag: %s", err) log.Fatalf("failed to hide flag: %s", err)
} }
@ -181,29 +226,20 @@ It is meant to allow you to manage bans, parsers/scenarios/etc, api and generall
} }
if len(os.Args) > 1 { if len(os.Args) > 1 {
cobra.OnInitialize(initConfig) cobra.OnInitialize(cli.initialize)
}
/*don't sort flags so we can enforce order*/
cmd.Flags().SortFlags = false
cmd.PersistentFlags().SortFlags = false
// we use a getter because the config is not initialized until the Execute() call
getconfig := func() *csconfig.Config {
return csConfig
} }
cmd.AddCommand(NewCLIDoc().NewCommand(cmd)) cmd.AddCommand(NewCLIDoc().NewCommand(cmd))
cmd.AddCommand(NewCLIVersion().NewCommand()) cmd.AddCommand(NewCLIVersion().NewCommand())
cmd.AddCommand(NewConfigCmd()) cmd.AddCommand(NewConfigCmd())
cmd.AddCommand(NewCLIHub(getconfig).NewCommand()) cmd.AddCommand(NewCLIHub(cli.cfg).NewCommand())
cmd.AddCommand(NewCLIMetrics(getconfig).NewCommand()) cmd.AddCommand(NewCLIMetrics(cli.cfg).NewCommand())
cmd.AddCommand(NewCLIDashboard(getconfig).NewCommand()) cmd.AddCommand(NewCLIDashboard(cli.cfg).NewCommand())
cmd.AddCommand(NewCLIDecisions(getconfig).NewCommand()) cmd.AddCommand(NewCLIDecisions(cli.cfg).NewCommand())
cmd.AddCommand(NewCLIAlerts().NewCommand()) cmd.AddCommand(NewCLIAlerts().NewCommand())
cmd.AddCommand(NewCLISimulation(getconfig).NewCommand()) cmd.AddCommand(NewCLISimulation(cli.cfg).NewCommand())
cmd.AddCommand(NewCLIBouncers(getconfig).NewCommand()) cmd.AddCommand(NewCLIBouncers(cli.cfg).NewCommand())
cmd.AddCommand(NewCLIMachines(getconfig).NewCommand()) cmd.AddCommand(NewCLIMachines(cli.cfg).NewCommand())
cmd.AddCommand(NewCLICapi().NewCommand()) cmd.AddCommand(NewCLICapi().NewCommand())
cmd.AddCommand(NewLapiCmd()) cmd.AddCommand(NewLapiCmd())
cmd.AddCommand(NewCompletionCmd()) cmd.AddCommand(NewCompletionCmd())
@ -212,7 +248,7 @@ It is meant to allow you to manage bans, parsers/scenarios/etc, api and generall
cmd.AddCommand(NewCLIHubTest().NewCommand()) cmd.AddCommand(NewCLIHubTest().NewCommand())
cmd.AddCommand(NewCLINotifications().NewCommand()) cmd.AddCommand(NewCLINotifications().NewCommand())
cmd.AddCommand(NewCLISupport().NewCommand()) cmd.AddCommand(NewCLISupport().NewCommand())
cmd.AddCommand(NewCLIPapi(getconfig).NewCommand()) cmd.AddCommand(NewCLIPapi(cli.cfg).NewCommand())
cmd.AddCommand(NewCLICollection().NewCommand()) cmd.AddCommand(NewCLICollection().NewCommand())
cmd.AddCommand(NewCLIParser().NewCommand()) cmd.AddCommand(NewCLIParser().NewCommand())
cmd.AddCommand(NewCLIScenario().NewCommand()) cmd.AddCommand(NewCLIScenario().NewCommand())
@ -225,6 +261,11 @@ It is meant to allow you to manage bans, parsers/scenarios/etc, api and generall
cmd.AddCommand(NewSetupCmd()) cmd.AddCommand(NewSetupCmd())
} }
return cmd
}
func main() {
cmd := newCliRoot().NewCommand()
if err := cmd.Execute(); err != nil { if err := cmd.Execute(); err != nil {
log.Fatal(err) log.Fatal(err)
} }

View file

@ -50,18 +50,18 @@ type metricStore map[string]metricSection
func NewMetricStore() metricStore { func NewMetricStore() metricStore {
return metricStore{ return metricStore{
"acquisition": statAcquis{}, "acquisition": statAcquis{},
"buckets": statBucket{}, "buckets": statBucket{},
"parsers": statParser{}, "parsers": statParser{},
"lapi": statLapi{}, "lapi": statLapi{},
"lapi-machine": statLapiMachine{}, "lapi-machine": statLapiMachine{},
"lapi-bouncer": statLapiBouncer{}, "lapi-bouncer": statLapiBouncer{},
"lapi-decisions": statLapiDecision{}, "lapi-decisions": statLapiDecision{},
"decisions": statDecision{}, "decisions": statDecision{},
"alerts": statAlert{}, "alerts": statAlert{},
"stash": statStash{}, "stash": statStash{},
"appsec-engine": statAppsecEngine{}, "appsec-engine": statAppsecEngine{},
"appsec-rule": statAppsecRule{}, "appsec-rule": statAppsecRule{},
} }
} }
@ -116,17 +116,21 @@ func (ms metricStore) Fetch(url string) error {
if !strings.HasPrefix(fam.Name, "cs_") { if !strings.HasPrefix(fam.Name, "cs_") {
continue continue
} }
log.Tracef("round %d", idx) log.Tracef("round %d", idx)
for _, m := range fam.Metrics { for _, m := range fam.Metrics {
metric, ok := m.(prom2json.Metric) metric, ok := m.(prom2json.Metric)
if !ok { if !ok {
log.Debugf("failed to convert metric to prom2json.Metric") log.Debugf("failed to convert metric to prom2json.Metric")
continue continue
} }
name, ok := metric.Labels["name"] name, ok := metric.Labels["name"]
if !ok { if !ok {
log.Debugf("no name in Metric %v", metric.Labels) log.Debugf("no name in Metric %v", metric.Labels)
} }
source, ok := metric.Labels["source"] source, ok := metric.Labels["source"]
if !ok { if !ok {
log.Debugf("no source in Metric %v for %s", metric.Labels, fam.Name) log.Debugf("no source in Metric %v for %s", metric.Labels, fam.Name)
@ -153,6 +157,7 @@ func (ms metricStore) Fetch(url string) error {
if err != nil { if err != nil {
log.Errorf("Unexpected int value %s : %s", value, err) log.Errorf("Unexpected int value %s : %s", value, err)
} }
ival := int(fval) ival := int(fval)
switch fam.Name { switch fam.Name {
/*buckets*/ /*buckets*/
@ -303,9 +308,9 @@ type cliMetrics struct {
cfg configGetter cfg configGetter
} }
func NewCLIMetrics(getconfig configGetter) *cliMetrics { func NewCLIMetrics(cfg configGetter) *cliMetrics {
return &cliMetrics{ return &cliMetrics{
cfg: getconfig, cfg: cfg,
} }
} }

View file

@ -10,19 +10,18 @@ import (
"github.com/crowdsecurity/go-cs-lib/ptr" "github.com/crowdsecurity/go-cs-lib/ptr"
"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require"
"github.com/crowdsecurity/crowdsec/pkg/apiserver" "github.com/crowdsecurity/crowdsec/pkg/apiserver"
"github.com/crowdsecurity/crowdsec/pkg/database" "github.com/crowdsecurity/crowdsec/pkg/database"
"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require"
) )
type cliPapi struct { type cliPapi struct {
cfg configGetter cfg configGetter
} }
func NewCLIPapi(getconfig configGetter) *cliPapi { func NewCLIPapi(cfg configGetter) *cliPapi {
return &cliPapi{ return &cliPapi{
cfg: getconfig, cfg: cfg,
} }
} }
@ -43,6 +42,7 @@ func (cli *cliPapi) NewCommand() *cobra.Command {
if err := require.PAPI(cfg); err != nil { if err := require.PAPI(cfg); err != nil {
return err return err
} }
return nil return nil
}, },
} }

View file

@ -3,23 +3,23 @@ package main
import ( import (
"fmt" "fmt"
"os" "os"
"slices"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"slices"
"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require" "github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require"
"github.com/crowdsecurity/crowdsec/pkg/cwhub" "github.com/crowdsecurity/crowdsec/pkg/cwhub"
) )
type cliSimulation struct{ type cliSimulation struct {
cfg configGetter cfg configGetter
} }
func NewCLISimulation(getconfig configGetter) *cliSimulation { func NewCLISimulation(cfg configGetter) *cliSimulation {
return &cliSimulation{ return &cliSimulation{
cfg: getconfig, cfg: cfg,
} }
} }
@ -38,6 +38,7 @@ cscli simulation disable crowdsecurity/ssh-bf`,
if cli.cfg().Cscli.SimulationConfig == nil { if cli.cfg().Cscli.SimulationConfig == nil {
return fmt.Errorf("no simulation configured") return fmt.Errorf("no simulation configured")
} }
return nil return nil
}, },
PersistentPostRun: func(cmd *cobra.Command, _ []string) { PersistentPostRun: func(cmd *cobra.Command, _ []string) {