Browse Source

cscli refact - encapsulation with types (#2643)

* refactor type cliHub, cliBouncers, cliMachines, cliPapi, cliNotifications, cliSupport, type cliExplain
mmetc 1 year ago
parent
commit
3e86f52250

+ 57 - 51
cmd/crowdsec-cli/bouncers.go

@@ -60,8 +60,46 @@ func getBouncers(out io.Writer, dbClient *database.Client) error {
 	return nil
 	return nil
 }
 }
 
 
-func NewBouncersListCmd() *cobra.Command {
-	cmdBouncersList := &cobra.Command{
+type cliBouncers struct {}
+
+func NewCLIBouncers() *cliBouncers {
+	return &cliBouncers{}
+}
+
+func (cli cliBouncers) NewCommand() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "bouncers [action]",
+		Short: "Manage bouncers [requires local API]",
+		Long: `To list/add/delete/prune bouncers.
+Note: This command requires database direct access, so is intended to be run on Local API/master.
+`,
+		Args:              cobra.MinimumNArgs(1),
+		Aliases:           []string{"bouncer"},
+		DisableAutoGenTag: true,
+		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+			var err error
+			if err = require.LAPI(csConfig); err != nil {
+				return err
+			}
+
+			dbClient, err = database.NewClient(csConfig.DbConfig)
+			if err != nil {
+				return fmt.Errorf("unable to create new database client: %s", err)
+			}
+			return nil
+		},
+	}
+
+	cmd.AddCommand(cli.NewListCmd())
+	cmd.AddCommand(cli.NewAddCmd())
+	cmd.AddCommand(cli.NewDeleteCmd())
+	cmd.AddCommand(cli.NewPruneCmd())
+
+	return cmd
+}
+
+func (cli cliBouncers) NewListCmd() *cobra.Command {
+	cmd := &cobra.Command{
 		Use:               "list",
 		Use:               "list",
 		Short:             "list all bouncers within the database",
 		Short:             "list all bouncers within the database",
 		Example:           `cscli bouncers list`,
 		Example:           `cscli bouncers list`,
@@ -76,10 +114,10 @@ func NewBouncersListCmd() *cobra.Command {
 		},
 		},
 	}
 	}
 
 
-	return cmdBouncersList
+	return cmd
 }
 }
 
 
-func runBouncersAdd(cmd *cobra.Command, args []string) error {
+func (cli cliBouncers) add(cmd *cobra.Command, args []string) error {
 	keyLength := 32
 	keyLength := 32
 
 
 	flags := cmd.Flags()
 	flags := cmd.Flags()
@@ -125,26 +163,26 @@ func runBouncersAdd(cmd *cobra.Command, args []string) error {
 	return nil
 	return nil
 }
 }
 
 
-func NewBouncersAddCmd() *cobra.Command {
-	cmdBouncersAdd := &cobra.Command{
+func (cli cliBouncers) NewAddCmd() *cobra.Command {
+	cmd := &cobra.Command{
 		Use:   "add MyBouncerName",
 		Use:   "add MyBouncerName",
 		Short: "add a single bouncer to the database",
 		Short: "add a single bouncer to the database",
 		Example: `cscli bouncers add MyBouncerName
 		Example: `cscli bouncers add MyBouncerName
 cscli bouncers add MyBouncerName --key <random-key>`,
 cscli bouncers add MyBouncerName --key <random-key>`,
 		Args:              cobra.ExactArgs(1),
 		Args:              cobra.ExactArgs(1),
 		DisableAutoGenTag: true,
 		DisableAutoGenTag: true,
-		RunE:              runBouncersAdd,
+		RunE:              cli.add,
 	}
 	}
 
 
-	flags := cmdBouncersAdd.Flags()
+	flags := cmd.Flags()
 	flags.StringP("length", "l", "", "length of the api key")
 	flags.StringP("length", "l", "", "length of the api key")
 	flags.MarkDeprecated("length", "use --key instead")
 	flags.MarkDeprecated("length", "use --key instead")
 	flags.StringP("key", "k", "", "api key for the bouncer")
 	flags.StringP("key", "k", "", "api key for the bouncer")
 
 
-	return cmdBouncersAdd
+	return cmd
 }
 }
 
 
-func runBouncersDelete(cmd *cobra.Command, args []string) error {
+func (cli cliBouncers) delete(cmd *cobra.Command, args []string) error {
 	for _, bouncerID := range args {
 	for _, bouncerID := range args {
 		err := dbClient.DeleteBouncer(bouncerID)
 		err := dbClient.DeleteBouncer(bouncerID)
 		if err != nil {
 		if err != nil {
@@ -156,8 +194,8 @@ func runBouncersDelete(cmd *cobra.Command, args []string) error {
 	return nil
 	return nil
 }
 }
 
 
-func NewBouncersDeleteCmd() *cobra.Command {
-	cmdBouncersDelete := &cobra.Command{
+func (cli cliBouncers) NewDeleteCmd() *cobra.Command {
+	cmd := &cobra.Command{
 		Use:               "delete MyBouncerName",
 		Use:               "delete MyBouncerName",
 		Short:             "delete bouncer(s) from the database",
 		Short:             "delete bouncer(s) from the database",
 		Args:              cobra.MinimumNArgs(1),
 		Args:              cobra.MinimumNArgs(1),
@@ -182,15 +220,15 @@ func NewBouncersDeleteCmd() *cobra.Command {
 			}
 			}
 			return ret, cobra.ShellCompDirectiveNoFileComp
 			return ret, cobra.ShellCompDirectiveNoFileComp
 		},
 		},
-		RunE: runBouncersDelete,
+		RunE: cli.delete,
 	}
 	}
 
 
-	return cmdBouncersDelete
+	return cmd
 }
 }
 
 
-func NewBouncersPruneCmd() *cobra.Command {
+func (cli cliBouncers) NewPruneCmd() *cobra.Command {
 	var parsedDuration time.Duration
 	var parsedDuration time.Duration
-	cmdBouncersPrune := &cobra.Command{
+	cmd := &cobra.Command{
 		Use:               "prune",
 		Use:               "prune",
 		Short:             "prune multiple bouncers from the database",
 		Short:             "prune multiple bouncers from the database",
 		Args:              cobra.NoArgs,
 		Args:              cobra.NoArgs,
@@ -253,39 +291,7 @@ cscli bouncers prune -d 60m --force`,
 			return nil
 			return nil
 		},
 		},
 	}
 	}
-	cmdBouncersPrune.Flags().StringP("duration", "d", "60m", "duration of time since last pull")
-	cmdBouncersPrune.Flags().Bool("force", false, "force prune without asking for confirmation")
-	return cmdBouncersPrune
-}
-
-func NewBouncersCmd() *cobra.Command {
-	var cmdBouncers = &cobra.Command{
-		Use:   "bouncers [action]",
-		Short: "Manage bouncers [requires local API]",
-		Long: `To list/add/delete/prune bouncers.
-Note: This command requires database direct access, so is intended to be run on Local API/master.
-`,
-		Args:              cobra.MinimumNArgs(1),
-		Aliases:           []string{"bouncer"},
-		DisableAutoGenTag: true,
-		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
-			var err error
-			if err = require.LAPI(csConfig); err != nil {
-				return err
-			}
-
-			dbClient, err = database.NewClient(csConfig.DbConfig)
-			if err != nil {
-				return fmt.Errorf("unable to create new database client: %s", err)
-			}
-			return nil
-		},
-	}
-
-	cmdBouncers.AddCommand(NewBouncersListCmd())
-	cmdBouncers.AddCommand(NewBouncersAddCmd())
-	cmdBouncers.AddCommand(NewBouncersDeleteCmd())
-	cmdBouncers.AddCommand(NewBouncersPruneCmd())
-
-	return cmdBouncers
+	cmd.Flags().StringP("duration", "d", "60m", "duration of time since last pull")
+	cmd.Flags().Bool("force", false, "force prune without asking for confirmation")
+	return cmd
 }
 }

+ 79 - 73
cmd/crowdsec-cli/explain.go

@@ -34,7 +34,85 @@ func GetLineCountForFile(filepath string) (int, error) {
 	return lc, nil
 	return lc, nil
 }
 }
 
 
-func runExplain(cmd *cobra.Command, args []string) error {
+type cliExplain struct {}
+
+func NewCLIExplain() *cliExplain {
+	return &cliExplain{}
+}
+
+func (cli cliExplain) NewCommand() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "explain",
+		Short: "Explain log pipeline",
+		Long: `
+Explain log pipeline 
+		`,
+		Example: `
+cscli explain --file ./myfile.log --type nginx 
+cscli explain --log "Sep 19 18:33:22 scw-d95986 sshd[24347]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=1.2.3.4" --type syslog
+cscli explain --dsn "file://myfile.log" --type nginx
+tail -n 5 myfile.log | cscli explain --type nginx -f -
+		`,
+		Args:              cobra.ExactArgs(0),
+		DisableAutoGenTag: true,
+		RunE:              cli.run,
+		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+			flags := cmd.Flags()
+
+			logFile, err := flags.GetString("file")
+			if err != nil {
+				return err
+			}
+
+			dsn, err := flags.GetString("dsn")
+			if err != nil {
+				return err
+			}
+
+			logLine, err := flags.GetString("log")
+			if err != nil {
+				return err
+			}
+
+			logType, err := flags.GetString("type")
+			if err != nil {
+				return err
+			}
+
+			if logLine == "" && logFile == "" && dsn == "" {
+				printHelp(cmd)
+				fmt.Println()
+				return fmt.Errorf("please provide --log, --file or --dsn flag")
+			}
+			if logType == "" {
+				printHelp(cmd)
+				fmt.Println()
+				return fmt.Errorf("please provide --type flag")
+			}
+			fileInfo, _ := os.Stdin.Stat()
+			if logFile == "-" && ((fileInfo.Mode() & os.ModeCharDevice) == os.ModeCharDevice) {
+				return fmt.Errorf("the option -f - is intended to work with pipes")
+			}
+			return nil
+		},
+	}
+
+	flags := cmd.Flags()
+
+	flags.StringP("file", "f", "", "Log file to test")
+	flags.StringP("dsn", "d", "", "DSN to test")
+	flags.StringP("log", "l", "", "Log line to test")
+	flags.StringP("type", "t", "", "Type of the acquisition to test")
+	flags.String("labels", "", "Additional labels to add to the acquisition format (key:value,key2:value2)")
+	flags.BoolP("verbose", "v", false, "Display individual changes")
+	flags.Bool("failures", false, "Only show failed lines")
+	flags.Bool("only-successful-parsers", false, "Only show successful parsers")
+	flags.String("crowdsec", "crowdsec", "Path to crowdsec")
+
+	return cmd
+}
+
+func (cli cliExplain) run(cmd *cobra.Command, args []string) error {
 	flags := cmd.Flags()
 	flags := cmd.Flags()
 
 
 	logFile, err := flags.GetString("file")
 	logFile, err := flags.GetString("file")
@@ -189,75 +267,3 @@ func runExplain(cmd *cobra.Command, args []string) error {
 
 
 	return nil
 	return nil
 }
 }
-
-func NewExplainCmd() *cobra.Command {
-	cmdExplain := &cobra.Command{
-		Use:   "explain",
-		Short: "Explain log pipeline",
-		Long: `
-Explain log pipeline 
-		`,
-		Example: `
-cscli explain --file ./myfile.log --type nginx 
-cscli explain --log "Sep 19 18:33:22 scw-d95986 sshd[24347]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=1.2.3.4" --type syslog
-cscli explain --dsn "file://myfile.log" --type nginx
-tail -n 5 myfile.log | cscli explain --type nginx -f -
-		`,
-		Args:              cobra.ExactArgs(0),
-		DisableAutoGenTag: true,
-		RunE:              runExplain,
-		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
-			flags := cmd.Flags()
-
-			logFile, err := flags.GetString("file")
-			if err != nil {
-				return err
-			}
-
-			dsn, err := flags.GetString("dsn")
-			if err != nil {
-				return err
-			}
-
-			logLine, err := flags.GetString("log")
-			if err != nil {
-				return err
-			}
-
-			logType, err := flags.GetString("type")
-			if err != nil {
-				return err
-			}
-
-			if logLine == "" && logFile == "" && dsn == "" {
-				printHelp(cmd)
-				fmt.Println()
-				return fmt.Errorf("please provide --log, --file or --dsn flag")
-			}
-			if logType == "" {
-				printHelp(cmd)
-				fmt.Println()
-				return fmt.Errorf("please provide --type flag")
-			}
-			fileInfo, _ := os.Stdin.Stat()
-			if logFile == "-" && ((fileInfo.Mode() & os.ModeCharDevice) == os.ModeCharDevice) {
-				return fmt.Errorf("the option -f - is intended to work with pipes")
-			}
-			return nil
-		},
-	}
-
-	flags := cmdExplain.Flags()
-
-	flags.StringP("file", "f", "", "Log file to test")
-	flags.StringP("dsn", "d", "", "DSN to test")
-	flags.StringP("log", "l", "", "Log line to test")
-	flags.StringP("type", "t", "", "Type of the acquisition to test")
-	flags.String("labels", "", "Additional labels to add to the acquisition format (key:value,key2:value2)")
-	flags.BoolP("verbose", "v", false, "Display individual changes")
-	flags.Bool("failures", false, "Only show failed lines")
-	flags.Bool("only-successful-parsers", false, "Only show successful parsers")
-	flags.String("crowdsec", "crowdsec", "Path to crowdsec")
-
-	return cmdExplain
-}

+ 35 - 29
cmd/crowdsec-cli/hub.go

@@ -13,8 +13,14 @@ import (
 	"github.com/crowdsecurity/crowdsec/pkg/cwhub"
 	"github.com/crowdsecurity/crowdsec/pkg/cwhub"
 )
 )
 
 
-func NewHubCmd() *cobra.Command {
-	cmdHub := &cobra.Command{
+type cliHub struct{}
+
+func NewCLIHub() *cliHub {
+	return &cliHub{}
+}
+
+func (cli cliHub) NewCommand() *cobra.Command {
+	cmd := &cobra.Command{
 		Use:   "hub [action]",
 		Use:   "hub [action]",
 		Short: "Manage hub index",
 		Short: "Manage hub index",
 		Long: `Hub management
 		Long: `Hub management
@@ -28,15 +34,15 @@ cscli hub upgrade`,
 		DisableAutoGenTag: true,
 		DisableAutoGenTag: true,
 	}
 	}
 
 
-	cmdHub.AddCommand(NewHubListCmd())
-	cmdHub.AddCommand(NewHubUpdateCmd())
-	cmdHub.AddCommand(NewHubUpgradeCmd())
-	cmdHub.AddCommand(NewHubTypesCmd())
+	cmd.AddCommand(cli.NewListCmd())
+	cmd.AddCommand(cli.NewUpdateCmd())
+	cmd.AddCommand(cli.NewUpgradeCmd())
+	cmd.AddCommand(cli.NewTypesCmd())
 
 
-	return cmdHub
+	return cmd
 }
 }
 
 
-func runHubList(cmd *cobra.Command, args []string) error {
+func (cli cliHub) list(cmd *cobra.Command, args []string) error {
 	flags := cmd.Flags()
 	flags := cmd.Flags()
 
 
 	all, err := flags.GetBool("all")
 	all, err := flags.GetBool("all")
@@ -74,22 +80,22 @@ func runHubList(cmd *cobra.Command, args []string) error {
 	return nil
 	return nil
 }
 }
 
 
-func NewHubListCmd() *cobra.Command {
-	cmdHubList := &cobra.Command{
+func (cli cliHub) NewListCmd() *cobra.Command {
+	cmd := &cobra.Command{
 		Use:               "list [-a]",
 		Use:               "list [-a]",
 		Short:             "List all installed configurations",
 		Short:             "List all installed configurations",
 		Args:              cobra.ExactArgs(0),
 		Args:              cobra.ExactArgs(0),
 		DisableAutoGenTag: true,
 		DisableAutoGenTag: true,
-		RunE:              runHubList,
+		RunE:              cli.list,
 	}
 	}
 
 
-	flags := cmdHubList.Flags()
+	flags := cmd.Flags()
 	flags.BoolP("all", "a", false, "List disabled items as well")
 	flags.BoolP("all", "a", false, "List disabled items as well")
 
 
-	return cmdHubList
+	return cmd
 }
 }
 
 
-func runHubUpdate(cmd *cobra.Command, args []string) error {
+func (cli cliHub) update(cmd *cobra.Command, args []string) error {
 	local := csConfig.Hub
 	local := csConfig.Hub
 	remote := require.RemoteHub(csConfig)
 	remote := require.RemoteHub(csConfig)
 
 
@@ -106,8 +112,8 @@ func runHubUpdate(cmd *cobra.Command, args []string) error {
 	return nil
 	return nil
 }
 }
 
 
-func NewHubUpdateCmd() *cobra.Command {
-	cmdHubUpdate := &cobra.Command{
+func (cli cliHub) NewUpdateCmd() *cobra.Command {
+	cmd := &cobra.Command{
 		Use:   "update",
 		Use:   "update",
 		Short: "Download the latest index (catalog of available configurations)",
 		Short: "Download the latest index (catalog of available configurations)",
 		Long: `
 		Long: `
@@ -115,13 +121,13 @@ Fetches the .index.json file from the hub, containing the list of available conf
 `,
 `,
 		Args:              cobra.ExactArgs(0),
 		Args:              cobra.ExactArgs(0),
 		DisableAutoGenTag: true,
 		DisableAutoGenTag: true,
-		RunE:              runHubUpdate,
+		RunE:              cli.update,
 	}
 	}
 
 
-	return cmdHubUpdate
+	return cmd
 }
 }
 
 
-func runHubUpgrade(cmd *cobra.Command, args []string) error {
+func (cli cliHub) upgrade(cmd *cobra.Command, args []string) error {
 	flags := cmd.Flags()
 	flags := cmd.Flags()
 
 
 	force, err := flags.GetBool("force")
 	force, err := flags.GetBool("force")
@@ -158,8 +164,8 @@ func runHubUpgrade(cmd *cobra.Command, args []string) error {
 	return nil
 	return nil
 }
 }
 
 
-func NewHubUpgradeCmd() *cobra.Command {
-	cmdHubUpgrade := &cobra.Command{
+func (cli cliHub) NewUpgradeCmd() *cobra.Command {
+	cmd := &cobra.Command{
 		Use:   "upgrade",
 		Use:   "upgrade",
 		Short: "Upgrade all configurations to their latest version",
 		Short: "Upgrade all configurations to their latest version",
 		Long: `
 		Long: `
@@ -167,16 +173,16 @@ Upgrade all configs installed from Crowdsec Hub. Run 'sudo cscli hub update' if
 `,
 `,
 		Args:              cobra.ExactArgs(0),
 		Args:              cobra.ExactArgs(0),
 		DisableAutoGenTag: true,
 		DisableAutoGenTag: true,
-		RunE:              runHubUpgrade,
+		RunE:              cli.upgrade,
 	}
 	}
 
 
-	flags := cmdHubUpgrade.Flags()
+	flags := cmd.Flags()
 	flags.Bool("force", false, "Force upgrade: overwrite tainted and outdated files")
 	flags.Bool("force", false, "Force upgrade: overwrite tainted and outdated files")
 
 
-	return cmdHubUpgrade
+	return cmd
 }
 }
 
 
-func runHubTypes(cmd *cobra.Command, args []string) error {
+func (cli cliHub) types(cmd *cobra.Command, args []string) error {
 	switch csConfig.Cscli.Output {
 	switch csConfig.Cscli.Output {
 	case "human":
 	case "human":
 		s, err := yaml.Marshal(cwhub.ItemTypes)
 		s, err := yaml.Marshal(cwhub.ItemTypes)
@@ -198,8 +204,8 @@ func runHubTypes(cmd *cobra.Command, args []string) error {
 	return nil
 	return nil
 }
 }
 
 
-func NewHubTypesCmd() *cobra.Command {
-	cmdHubTypes := &cobra.Command{
+func (cli cliHub) NewTypesCmd() *cobra.Command {
+	cmd := &cobra.Command{
 		Use:   "types",
 		Use:   "types",
 		Short: "List supported item types",
 		Short: "List supported item types",
 		Long: `
 		Long: `
@@ -207,8 +213,8 @@ List the types of supported hub items.
 `,
 `,
 		Args:              cobra.ExactArgs(0),
 		Args:              cobra.ExactArgs(0),
 		DisableAutoGenTag: true,
 		DisableAutoGenTag: true,
-		RunE:              runHubTypes,
+		RunE:              cli.types,
 	}
 	}
 
 
-	return cmdHubTypes
+	return cmd
 }
 }

+ 61 - 57
cmd/crowdsec-cli/machines.go

@@ -142,8 +142,46 @@ func getAgents(out io.Writer, dbClient *database.Client) error {
 	return nil
 	return nil
 }
 }
 
 
-func NewMachinesListCmd() *cobra.Command {
-	cmdMachinesList := &cobra.Command{
+type cliMachines struct {}
+
+func NewCLIMachines() *cliMachines {
+	return &cliMachines{}
+}
+
+func (cli cliMachines) NewCommand() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "machines [action]",
+		Short: "Manage local API machines [requires local API]",
+		Long: `To list/add/delete/validate/prune machines.
+Note: This command requires database direct access, so is intended to be run on the local API machine.
+`,
+		Example:           `cscli machines [action]`,
+		DisableAutoGenTag: true,
+		Aliases:           []string{"machine"},
+		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+			var err error
+			if err := require.LAPI(csConfig); err != nil {
+				return err
+			}
+			dbClient, err = database.NewClient(csConfig.DbConfig)
+			if err != nil {
+				return fmt.Errorf("unable to create new database client: %s", err)
+			}
+			return nil
+		},
+	}
+
+	cmd.AddCommand(cli.NewListCmd())
+	cmd.AddCommand(cli.NewAddCmd())
+	cmd.AddCommand(cli.NewDeleteCmd())
+	cmd.AddCommand(cli.NewValidateCmd())
+	cmd.AddCommand(cli.NewPruneCmd())
+
+	return cmd
+}
+
+func (cli cliMachines) NewListCmd() *cobra.Command {
+	cmd := &cobra.Command{
 		Use:               "list",
 		Use:               "list",
 		Short:             "list all machines in the database",
 		Short:             "list all machines in the database",
 		Long:              `list all machines in the database with their status and last heartbeat`,
 		Long:              `list all machines in the database with their status and last heartbeat`,
@@ -160,11 +198,11 @@ func NewMachinesListCmd() *cobra.Command {
 		},
 		},
 	}
 	}
 
 
-	return cmdMachinesList
+	return cmd
 }
 }
 
 
-func NewMachinesAddCmd() *cobra.Command {
-	cmdMachinesAdd := &cobra.Command{
+func (cli cliMachines) NewAddCmd() *cobra.Command {
+	cmd := &cobra.Command{
 		Use:               "add",
 		Use:               "add",
 		Short:             "add a single machine to the database",
 		Short:             "add a single machine to the database",
 		DisableAutoGenTag: true,
 		DisableAutoGenTag: true,
@@ -174,10 +212,10 @@ cscli machines add --auto
 cscli machines add MyTestMachine --auto
 cscli machines add MyTestMachine --auto
 cscli machines add MyTestMachine --password MyPassword
 cscli machines add MyTestMachine --password MyPassword
 `,
 `,
-		RunE: runMachinesAdd,
+		RunE: cli.add,
 	}
 	}
 
 
-	flags := cmdMachinesAdd.Flags()
+	flags := cmd.Flags()
 	flags.StringP("password", "p", "", "machine password to login to the API")
 	flags.StringP("password", "p", "", "machine password to login to the API")
 	flags.StringP("file", "f", "", "output file destination (defaults to "+csconfig.DefaultConfigPath("local_api_credentials.yaml")+")")
 	flags.StringP("file", "f", "", "output file destination (defaults to "+csconfig.DefaultConfigPath("local_api_credentials.yaml")+")")
 	flags.StringP("url", "u", "", "URL of the local API")
 	flags.StringP("url", "u", "", "URL of the local API")
@@ -185,12 +223,10 @@ cscli machines add MyTestMachine --password MyPassword
 	flags.BoolP("auto", "a", false, "automatically generate password (and username if not provided)")
 	flags.BoolP("auto", "a", false, "automatically generate password (and username if not provided)")
 	flags.Bool("force", false, "will force add the machine if it already exist")
 	flags.Bool("force", false, "will force add the machine if it already exist")
 
 
-	return cmdMachinesAdd
+	return cmd
 }
 }
 
 
-func runMachinesAdd(cmd *cobra.Command, args []string) error {
-	var err error
-
+func (cli cliMachines) add(cmd *cobra.Command, args []string) error {
 	flags := cmd.Flags()
 	flags := cmd.Flags()
 
 
 	machinePassword, err := flags.GetString("password")
 	machinePassword, err := flags.GetString("password")
@@ -308,8 +344,8 @@ func runMachinesAdd(cmd *cobra.Command, args []string) error {
 	return nil
 	return nil
 }
 }
 
 
-func NewMachinesDeleteCmd() *cobra.Command {
-	cmdMachinesDelete := &cobra.Command{
+func (cli cliMachines) NewDeleteCmd() *cobra.Command {
+	cmd := &cobra.Command{
 		Use:               "delete [machine_name]...",
 		Use:               "delete [machine_name]...",
 		Short:             "delete machine(s) by name",
 		Short:             "delete machine(s) by name",
 		Example:           `cscli machines delete "machine1" "machine2"`,
 		Example:           `cscli machines delete "machine1" "machine2"`,
@@ -329,13 +365,13 @@ func NewMachinesDeleteCmd() *cobra.Command {
 			}
 			}
 			return ret, cobra.ShellCompDirectiveNoFileComp
 			return ret, cobra.ShellCompDirectiveNoFileComp
 		},
 		},
-		RunE: runMachinesDelete,
+		RunE: cli.delete,
 	}
 	}
 
 
-	return cmdMachinesDelete
+	return cmd
 }
 }
 
 
-func runMachinesDelete(cmd *cobra.Command, args []string) error {
+func (cli cliMachines) delete(cmd *cobra.Command, args []string) error {
 	for _, machineID := range args {
 	for _, machineID := range args {
 		err := dbClient.DeleteWatcher(machineID)
 		err := dbClient.DeleteWatcher(machineID)
 		if err != nil {
 		if err != nil {
@@ -348,9 +384,9 @@ func runMachinesDelete(cmd *cobra.Command, args []string) error {
 	return nil
 	return nil
 }
 }
 
 
-func NewMachinesPruneCmd() *cobra.Command {
+func (cli cliMachines) NewPruneCmd() *cobra.Command {
 	var parsedDuration time.Duration
 	var parsedDuration time.Duration
-	cmdMachinesPrune := &cobra.Command{
+	cmd := &cobra.Command{
 		Use:   "prune",
 		Use:   "prune",
 		Short: "prune multiple machines from the database",
 		Short: "prune multiple machines from the database",
 		Long:  `prune multiple machines that are not validated or have not connected to the local API in a given duration.`,
 		Long:  `prune multiple machines that are not validated or have not connected to the local API in a given duration.`,
@@ -421,15 +457,15 @@ cscli machines prune --not-validated-only --force`,
 			return nil
 			return nil
 		},
 		},
 	}
 	}
-	cmdMachinesPrune.Flags().StringP("duration", "d", "10m", "duration of time since validated machine last heartbeat")
-	cmdMachinesPrune.Flags().Bool("not-validated-only", false, "only prune machines that are not validated")
-	cmdMachinesPrune.Flags().Bool("force", false, "force prune without asking for confirmation")
+	cmd.Flags().StringP("duration", "d", "10m", "duration of time since validated machine last heartbeat")
+	cmd.Flags().Bool("not-validated-only", false, "only prune machines that are not validated")
+	cmd.Flags().Bool("force", false, "force prune without asking for confirmation")
 
 
-	return cmdMachinesPrune
+	return cmd
 }
 }
 
 
-func NewMachinesValidateCmd() *cobra.Command {
-	cmdMachinesValidate := &cobra.Command{
+func (cli cliMachines) NewValidateCmd() *cobra.Command {
+	cmd := &cobra.Command{
 		Use:               "validate",
 		Use:               "validate",
 		Short:             "validate a machine to access the local API",
 		Short:             "validate a machine to access the local API",
 		Long:              `validate a machine to access the local API.`,
 		Long:              `validate a machine to access the local API.`,
@@ -447,37 +483,5 @@ func NewMachinesValidateCmd() *cobra.Command {
 		},
 		},
 	}
 	}
 
 
-	return cmdMachinesValidate
-}
-
-func NewMachinesCmd() *cobra.Command {
-	var cmdMachines = &cobra.Command{
-		Use:   "machines [action]",
-		Short: "Manage local API machines [requires local API]",
-		Long: `To list/add/delete/validate/prune machines.
-Note: This command requires database direct access, so is intended to be run on the local API machine.
-`,
-		Example:           `cscli machines [action]`,
-		DisableAutoGenTag: true,
-		Aliases:           []string{"machine"},
-		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
-			var err error
-			if err := require.LAPI(csConfig); err != nil {
-				return err
-			}
-			dbClient, err = database.NewClient(csConfig.DbConfig)
-			if err != nil {
-				return fmt.Errorf("unable to create new database client: %s", err)
-			}
-			return nil
-		},
-	}
-
-	cmdMachines.AddCommand(NewMachinesListCmd())
-	cmdMachines.AddCommand(NewMachinesAddCmd())
-	cmdMachines.AddCommand(NewMachinesDeleteCmd())
-	cmdMachines.AddCommand(NewMachinesValidateCmd())
-	cmdMachines.AddCommand(NewMachinesPruneCmd())
-
-	return cmdMachines
+	return cmd
 }
 }

+ 7 - 7
cmd/crowdsec-cli/main.go

@@ -225,22 +225,22 @@ It is meant to allow you to manage bans, parsers/scenarios/etc, api and generall
 	rootCmd.PersistentFlags().SortFlags = false
 	rootCmd.PersistentFlags().SortFlags = false
 
 
 	rootCmd.AddCommand(NewConfigCmd())
 	rootCmd.AddCommand(NewConfigCmd())
-	rootCmd.AddCommand(NewHubCmd())
+	rootCmd.AddCommand(NewCLIHub().NewCommand())
 	rootCmd.AddCommand(NewMetricsCmd())
 	rootCmd.AddCommand(NewMetricsCmd())
 	rootCmd.AddCommand(NewDashboardCmd())
 	rootCmd.AddCommand(NewDashboardCmd())
 	rootCmd.AddCommand(NewDecisionsCmd())
 	rootCmd.AddCommand(NewDecisionsCmd())
 	rootCmd.AddCommand(NewAlertsCmd())
 	rootCmd.AddCommand(NewAlertsCmd())
 	rootCmd.AddCommand(NewSimulationCmds())
 	rootCmd.AddCommand(NewSimulationCmds())
-	rootCmd.AddCommand(NewBouncersCmd())
-	rootCmd.AddCommand(NewMachinesCmd())
+	rootCmd.AddCommand(NewCLIBouncers().NewCommand())
+	rootCmd.AddCommand(NewCLIMachines().NewCommand())
 	rootCmd.AddCommand(NewCapiCmd())
 	rootCmd.AddCommand(NewCapiCmd())
 	rootCmd.AddCommand(NewLapiCmd())
 	rootCmd.AddCommand(NewLapiCmd())
 	rootCmd.AddCommand(NewCompletionCmd())
 	rootCmd.AddCommand(NewCompletionCmd())
 	rootCmd.AddCommand(NewConsoleCmd())
 	rootCmd.AddCommand(NewConsoleCmd())
-	rootCmd.AddCommand(NewExplainCmd())
+	rootCmd.AddCommand(NewCLIExplain().NewCommand())
 	rootCmd.AddCommand(NewHubTestCmd())
 	rootCmd.AddCommand(NewHubTestCmd())
-	rootCmd.AddCommand(NewNotificationsCmd())
-	rootCmd.AddCommand(NewSupportCmd())
+	rootCmd.AddCommand(NewCLINotifications().NewCommand())
+	rootCmd.AddCommand(NewCLISupport().NewCommand())
 
 
 	rootCmd.AddCommand(NewCollectionCLI().NewCommand())
 	rootCmd.AddCommand(NewCollectionCLI().NewCommand())
 	rootCmd.AddCommand(NewParserCLI().NewCommand())
 	rootCmd.AddCommand(NewParserCLI().NewCommand())
@@ -254,7 +254,7 @@ It is meant to allow you to manage bans, parsers/scenarios/etc, api and generall
 	}
 	}
 
 
 	if fflag.PapiClient.IsEnabled() {
 	if fflag.PapiClient.IsEnabled() {
-		rootCmd.AddCommand(NewPapiCmd())
+		rootCmd.AddCommand(NewCLIPapi().NewCommand())
 	}
 	}
 
 
 	if err := rootCmd.Execute(); err != nil {
 	if err := rootCmd.Execute(); err != nil {

+ 28 - 21
cmd/crowdsec-cli/notifications.go

@@ -39,8 +39,15 @@ type NotificationsCfg struct {
 	ids      []uint
 	ids      []uint
 }
 }
 
 
-func NewNotificationsCmd() *cobra.Command {
-	var cmdNotifications = &cobra.Command{
+
+type cliNotifications struct {}
+
+func NewCLINotifications() *cliNotifications {
+	return &cliNotifications{}
+}
+
+func (cli cliNotifications) NewCommand() *cobra.Command {
+	cmd := &cobra.Command{
 		Use:               "notifications [action]",
 		Use:               "notifications [action]",
 		Short:             "Helper for notification plugin configuration",
 		Short:             "Helper for notification plugin configuration",
 		Long:              "To list/inspect/test notification template",
 		Long:              "To list/inspect/test notification template",
@@ -62,12 +69,12 @@ func NewNotificationsCmd() *cobra.Command {
 		},
 		},
 	}
 	}
 
 
-	cmdNotifications.AddCommand(NewNotificationsListCmd())
-	cmdNotifications.AddCommand(NewNotificationsInspectCmd())
-	cmdNotifications.AddCommand(NewNotificationsReinjectCmd())
-	cmdNotifications.AddCommand(NewNotificationsTestCmd())
+	cmd.AddCommand(cli.NewListCmd())
+	cmd.AddCommand(cli.NewInspectCmd())
+	cmd.AddCommand(cli.NewReinjectCmd())
+	cmd.AddCommand(cli.NewTestCmd())
 
 
-	return cmdNotifications
+	return cmd
 }
 }
 
 
 func getPluginConfigs() (map[string]csplugin.PluginConfig, error) {
 func getPluginConfigs() (map[string]csplugin.PluginConfig, error) {
@@ -141,8 +148,8 @@ func getProfilesConfigs() (map[string]NotificationsCfg, error) {
 	return ncfgs, nil
 	return ncfgs, nil
 }
 }
 
 
-func NewNotificationsListCmd() *cobra.Command {
-	var cmdNotificationsList = &cobra.Command{
+func (cli cliNotifications) NewListCmd() *cobra.Command {
+	cmd := &cobra.Command{
 		Use:               "list",
 		Use:               "list",
 		Short:             "list active notifications plugins",
 		Short:             "list active notifications plugins",
 		Long:              `list active notifications plugins`,
 		Long:              `list active notifications plugins`,
@@ -185,11 +192,11 @@ func NewNotificationsListCmd() *cobra.Command {
 		},
 		},
 	}
 	}
 
 
-	return cmdNotificationsList
+	return cmd
 }
 }
 
 
-func NewNotificationsInspectCmd() *cobra.Command {
-	var cmdNotificationsInspect = &cobra.Command{
+func (cli cliNotifications) NewInspectCmd() *cobra.Command {
+	cmd := &cobra.Command{
 		Use:               "inspect",
 		Use:               "inspect",
 		Short:             "Inspect active notifications plugin configuration",
 		Short:             "Inspect active notifications plugin configuration",
 		Long:              `Inspect active notifications plugin and show configuration`,
 		Long:              `Inspect active notifications plugin and show configuration`,
@@ -230,16 +237,16 @@ func NewNotificationsInspectCmd() *cobra.Command {
 		},
 		},
 	}
 	}
 
 
-	return cmdNotificationsInspect
+	return cmd
 }
 }
 
 
-func NewNotificationsTestCmd() *cobra.Command {
+func (cli cliNotifications) NewTestCmd() *cobra.Command {
 	var (
 	var (
 		pluginBroker  csplugin.PluginBroker
 		pluginBroker  csplugin.PluginBroker
 		pluginTomb    tomb.Tomb
 		pluginTomb    tomb.Tomb
 		alertOverride string
 		alertOverride string
 	)
 	)
-	var cmdNotificationsTest = &cobra.Command{
+	cmd := &cobra.Command{
 		Use:               "test [plugin name]",
 		Use:               "test [plugin name]",
 		Short:             "send a generic test alert to notification plugin",
 		Short:             "send a generic test alert to notification plugin",
 		Long:              `send a generic test alert to a notification plugin to test configuration even if is not active`,
 		Long:              `send a generic test alert to a notification plugin to test configuration even if is not active`,
@@ -313,16 +320,16 @@ func NewNotificationsTestCmd() *cobra.Command {
 			return nil
 			return nil
 		},
 		},
 	}
 	}
-	cmdNotificationsTest.Flags().StringVarP(&alertOverride, "alert", "a", "", "JSON string used to override alert fields in the generic alert (see crowdsec/pkg/models/alert.go in the source tree for the full definition of the object)")
+	cmd.Flags().StringVarP(&alertOverride, "alert", "a", "", "JSON string used to override alert fields in the generic alert (see crowdsec/pkg/models/alert.go in the source tree for the full definition of the object)")
 
 
-	return cmdNotificationsTest
+	return cmd
 }
 }
 
 
-func NewNotificationsReinjectCmd() *cobra.Command {
+func (cli cliNotifications) NewReinjectCmd() *cobra.Command {
 	var alertOverride string
 	var alertOverride string
 	var alert *models.Alert
 	var alert *models.Alert
 
 
-	var cmdNotificationsReinject = &cobra.Command{
+	cmd := &cobra.Command{
 		Use:   "reinject",
 		Use:   "reinject",
 		Short: "reinject an alert into profiles to trigger notifications",
 		Short: "reinject an alert into profiles to trigger notifications",
 		Long:  `reinject an alert into profiles to be evaluated by the filter and sent to matched notifications plugins`,
 		Long:  `reinject an alert into profiles to be evaluated by the filter and sent to matched notifications plugins`,
@@ -401,9 +408,9 @@ cscli notifications reinject <alert_id> -a '{"remediation": true,"scenario":"not
 			return nil
 			return nil
 		},
 		},
 	}
 	}
-	cmdNotificationsReinject.Flags().StringVarP(&alertOverride, "alert", "a", "", "JSON string used to override alert fields in the reinjected alert (see crowdsec/pkg/models/alert.go in the source tree for the full definition of the object)")
+	cmd.Flags().StringVarP(&alertOverride, "alert", "a", "", "JSON string used to override alert fields in the reinjected alert (see crowdsec/pkg/models/alert.go in the source tree for the full definition of the object)")
 
 
-	return cmdNotificationsReinject
+	return cmd
 }
 }
 
 
 func FetchAlertFromArgString(toParse string) (*models.Alert, error) {
 func FetchAlertFromArgString(toParse string) (*models.Alert, error) {

+ 17 - 11
cmd/crowdsec-cli/papi.go

@@ -15,8 +15,14 @@ import (
 	"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require"
 	"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require"
 )
 )
 
 
-func NewPapiCmd() *cobra.Command {
-	var cmdLapi = &cobra.Command{
+type cliPapi struct {}
+
+func NewCLIPapi() *cliPapi {
+	return &cliPapi{}
+}
+
+func (cli cliPapi) NewCommand() *cobra.Command {
+	var cmd = &cobra.Command{
 		Use:               "papi [action]",
 		Use:               "papi [action]",
 		Short:             "Manage interaction with Polling API (PAPI)",
 		Short:             "Manage interaction with Polling API (PAPI)",
 		Args:              cobra.MinimumNArgs(1),
 		Args:              cobra.MinimumNArgs(1),
@@ -35,14 +41,14 @@ func NewPapiCmd() *cobra.Command {
 		},
 		},
 	}
 	}
 
 
-	cmdLapi.AddCommand(NewPapiStatusCmd())
-	cmdLapi.AddCommand(NewPapiSyncCmd())
+	cmd.AddCommand(cli.NewStatusCmd())
+	cmd.AddCommand(cli.NewSyncCmd())
 
 
-	return cmdLapi
+	return cmd
 }
 }
 
 
-func NewPapiStatusCmd() *cobra.Command {
-	cmdCapiStatus := &cobra.Command{
+func (cli cliPapi) NewStatusCmd() *cobra.Command {
+	cmd := &cobra.Command{
 		Use:               "status",
 		Use:               "status",
 		Short:             "Get status of the Polling API",
 		Short:             "Get status of the Polling API",
 		Args:              cobra.MinimumNArgs(0),
 		Args:              cobra.MinimumNArgs(0),
@@ -87,11 +93,11 @@ func NewPapiStatusCmd() *cobra.Command {
 		},
 		},
 	}
 	}
 
 
-	return cmdCapiStatus
+	return cmd
 }
 }
 
 
-func NewPapiSyncCmd() *cobra.Command {
-	cmdCapiSync := &cobra.Command{
+func (cli cliPapi) NewSyncCmd() *cobra.Command {
+	cmd := &cobra.Command{
 		Use:               "sync",
 		Use:               "sync",
 		Short:             "Sync with the Polling API, pulling all non-expired orders for the instance",
 		Short:             "Sync with the Polling API, pulling all non-expired orders for the instance",
 		Args:              cobra.MinimumNArgs(0),
 		Args:              cobra.MinimumNArgs(0),
@@ -135,5 +141,5 @@ func NewPapiSyncCmd() *cobra.Command {
 		},
 		},
 	}
 	}
 
 
-	return cmdCapiSync
+	return cmd
 }
 }

+ 18 - 6
cmd/crowdsec-cli/support.go

@@ -237,8 +237,14 @@ func collectAcquisitionConfig() map[string][]byte {
 	return ret
 	return ret
 }
 }
 
 
-func NewSupportCmd() *cobra.Command {
-	var cmdSupport = &cobra.Command{
+type cliSupport struct {}
+
+func NewCLISupport() *cliSupport {
+	return &cliSupport{}
+}
+
+func (cli cliSupport) NewCommand() *cobra.Command {
+	cmd := &cobra.Command{
 		Use:               "support [action]",
 		Use:               "support [action]",
 		Short:             "Provide commands to help during support",
 		Short:             "Provide commands to help during support",
 		Args:              cobra.MinimumNArgs(1),
 		Args:              cobra.MinimumNArgs(1),
@@ -248,9 +254,15 @@ func NewSupportCmd() *cobra.Command {
 		},
 		},
 	}
 	}
 
 
+	cmd.AddCommand(cli.NewDumpCmd())
+
+	return cmd
+}
+
+func (cli cliSupport) NewDumpCmd() *cobra.Command {
 	var outFile string
 	var outFile string
 
 
-	cmdDump := &cobra.Command{
+	cmd := &cobra.Command{
 		Use:   "dump",
 		Use:   "dump",
 		Short: "Dump all your configuration to a zip file for easier support",
 		Short: "Dump all your configuration to a zip file for easier support",
 		Long: `Dump the following informations:
 		Long: `Dump the following informations:
@@ -415,8 +427,8 @@ cscli support dump -f /tmp/crowdsec-support.zip
 			log.Infof("Written zip file to %s", outFile)
 			log.Infof("Written zip file to %s", outFile)
 		},
 		},
 	}
 	}
-	cmdDump.Flags().StringVarP(&outFile, "outFile", "f", "", "File to dump the information to")
-	cmdSupport.AddCommand(cmdDump)
 
 
-	return cmdSupport
+	cmd.Flags().StringVarP(&outFile, "outFile", "f", "", "File to dump the information to")
+
+	return cmd
 }
 }