From 4bffc0df214d9764619ebd78c2b349a17544c075 Mon Sep 17 00:00:00 2001 From: mmetc <92726601+mmetc@users.noreply.github.com> Date: Thu, 19 Jan 2023 13:29:36 +0100 Subject: [PATCH] break in smaller functions cscli hub, hubtest, notifications, parsers, scenarios, simulation (#2004) --- cmd/crowdsec-cli/hub.go | 23 ++++- cmd/crowdsec-cli/hubtest.go | 64 +++++++++--- cmd/crowdsec-cli/notifications.go | 157 +++++++++++++++++------------- cmd/crowdsec-cli/parsers.go | 40 ++++++-- cmd/crowdsec-cli/scenarios.go | 35 +++++-- cmd/crowdsec-cli/simulation.go | 24 ++++- 6 files changed, 243 insertions(+), 100 deletions(-) diff --git a/cmd/crowdsec-cli/hub.go b/cmd/crowdsec-cli/hub.go index 6b35eb6aa..5a97b9039 100644 --- a/cmd/crowdsec-cli/hub.go +++ b/cmd/crowdsec-cli/hub.go @@ -11,7 +11,6 @@ import ( ) func NewHubCmd() *cobra.Command { - /* ---- HUB COMMAND */ var cmdHub = &cobra.Command{ Use: "hub [action]", Short: "Manage Hub", @@ -37,6 +36,14 @@ cscli hub update # Download list of available configurations from the hub } cmdHub.PersistentFlags().StringVarP(&cwhub.HubBranch, "branch", "b", "", "Use given branch from hub") + cmdHub.AddCommand(NewHubListCmd()) + cmdHub.AddCommand(NewHubUpdateCmd()) + cmdHub.AddCommand(NewHubUpgradeCmd()) + + return cmdHub +} + +func NewHubListCmd() *cobra.Command { var cmdHubList = &cobra.Command{ Use: "list [-a]", Short: "List installed configs", @@ -63,8 +70,11 @@ cscli hub update # Download list of available configurations from the hub }, } cmdHubList.PersistentFlags().BoolVarP(&all, "all", "a", false, "List disabled items as well") - cmdHub.AddCommand(cmdHubList) + return cmdHubList +} + +func NewHubUpdateCmd() *cobra.Command { var cmdHubUpdate = &cobra.Command{ Use: "update", Short: "Fetch available configs from hub", @@ -97,8 +107,11 @@ Fetches the [.index.json](https://github.com/crowdsecurity/hub/blob/master/.inde } }, } - cmdHub.AddCommand(cmdHubUpdate) + return cmdHubUpdate +} + +func NewHubUpgradeCmd() *cobra.Command { var cmdHubUpgrade = &cobra.Command{ Use: "upgrade", Short: "Upgrade all configs installed from hub", @@ -137,6 +150,6 @@ Upgrade all configs installed from Crowdsec Hub. Run 'sudo cscli hub update' if }, } cmdHubUpgrade.PersistentFlags().BoolVar(&forceAction, "force", false, "Force upgrade : Overwrite tainted and outdated files") - cmdHub.AddCommand(cmdHubUpgrade) - return cmdHub + + return cmdHubUpgrade } diff --git a/cmd/crowdsec-cli/hubtest.go b/cmd/crowdsec-cli/hubtest.go index 717291f03..7772df3eb 100644 --- a/cmd/crowdsec-cli/hubtest.go +++ b/cmd/crowdsec-cli/hubtest.go @@ -23,9 +23,7 @@ var ( ) func NewHubTestCmd() *cobra.Command { - /* ---- HUB COMMAND */ var hubPath string - var logType string var crowdsecPath string var cscliPath string @@ -47,11 +45,26 @@ func NewHubTestCmd() *cobra.Command { cmdHubTest.PersistentFlags().StringVar(&crowdsecPath, "crowdsec", "crowdsec", "Path to crowdsec") cmdHubTest.PersistentFlags().StringVar(&cscliPath, "cscli", "cscli", "Path to cscli") + cmdHubTest.AddCommand(NewHubTestCreateCmd()) + cmdHubTest.AddCommand(NewHubTestRunCmd()) + cmdHubTest.AddCommand(NewHubTestCleanCmd()) + cmdHubTest.AddCommand(NewHubTestInfoCmd()) + cmdHubTest.AddCommand(NewHubTestListCmd()) + cmdHubTest.AddCommand(NewHubTestCoverageCmd()) + cmdHubTest.AddCommand(NewHubTestEvalCmd()) + cmdHubTest.AddCommand(NewHubTestExplainCmd()) + + return cmdHubTest +} + + +func NewHubTestCreateCmd() *cobra.Command { parsers := []string{} postoverflows := []string{} scenarios := []string{} var ignoreParsers bool var labels map[string]string + var logType string var cmdHubTestCreate = &cobra.Command{ Use: "create", @@ -153,11 +166,16 @@ cscli hubtest create my-scenario-test --parsers crowdsecurity/nginx --scenarios cmdHubTestCreate.Flags().StringSliceVar(&postoverflows, "postoverflows", postoverflows, "Postoverflows to add to test") cmdHubTestCreate.Flags().StringSliceVarP(&scenarios, "scenarios", "s", scenarios, "Scenarios to add to test") cmdHubTestCreate.PersistentFlags().BoolVar(&ignoreParsers, "ignore-parsers", false, "Don't run test on parsers") - cmdHubTest.AddCommand(cmdHubTestCreate) + return cmdHubTestCreate +} + + +func NewHubTestRunCmd() *cobra.Command { var noClean bool var runAll bool var forceClean bool + var cmdHubTestRun = &cobra.Command{ Use: "run", Short: "run [test_name]", @@ -300,8 +318,12 @@ cscli hubtest create my-scenario-test --parsers crowdsecurity/nginx --scenarios cmdHubTestRun.Flags().BoolVar(&noClean, "no-clean", false, "Don't clean runtime environment if test succeed") cmdHubTestRun.Flags().BoolVar(&forceClean, "clean", false, "Clean runtime environment if test fail") cmdHubTestRun.Flags().BoolVar(&runAll, "all", false, "Run all tests") - cmdHubTest.AddCommand(cmdHubTestRun) + return cmdHubTestRun +} + + +func NewHubTestCleanCmd() *cobra.Command { var cmdHubTestClean = &cobra.Command{ Use: "clean", Short: "clean [test_name]", @@ -319,8 +341,12 @@ cscli hubtest create my-scenario-test --parsers crowdsecurity/nginx --scenarios } }, } - cmdHubTest.AddCommand(cmdHubTestClean) + return cmdHubTestClean +} + + +func NewHubTestInfoCmd() *cobra.Command { var cmdHubTestInfo = &cobra.Command{ Use: "info", Short: "info [test_name]", @@ -342,8 +368,12 @@ cscli hubtest create my-scenario-test --parsers crowdsecurity/nginx --scenarios } }, } - cmdHubTest.AddCommand(cmdHubTestInfo) + return cmdHubTestInfo +} + + +func NewHubTestListCmd() *cobra.Command { var cmdHubTestList = &cobra.Command{ Use: "list", Short: "list", @@ -367,11 +397,16 @@ cscli hubtest create my-scenario-test --parsers crowdsecurity/nginx --scenarios } }, } - cmdHubTest.AddCommand(cmdHubTestList) + return cmdHubTestList +} + + +func NewHubTestCoverageCmd() *cobra.Command { var showParserCov bool var showScenarioCov bool var showOnlyPercent bool + var cmdHubTestCoverage = &cobra.Command{ Use: "coverage", Short: "coverage", @@ -463,8 +498,12 @@ cscli hubtest create my-scenario-test --parsers crowdsecurity/nginx --scenarios cmdHubTestCoverage.PersistentFlags().BoolVar(&showOnlyPercent, "percent", false, "Show only percentages of coverage") cmdHubTestCoverage.PersistentFlags().BoolVar(&showParserCov, "parsers", false, "Show only parsers coverage") cmdHubTestCoverage.PersistentFlags().BoolVar(&showScenarioCov, "scenarios", false, "Show only scenarios coverage") - cmdHubTest.AddCommand(cmdHubTestCoverage) + return cmdHubTestCoverage +} + + +func NewHubTestEvalCmd() *cobra.Command { var evalExpression string var cmdHubTestEval = &cobra.Command{ Use: "eval", @@ -490,8 +529,12 @@ cscli hubtest create my-scenario-test --parsers crowdsecurity/nginx --scenarios }, } cmdHubTestEval.PersistentFlags().StringVarP(&evalExpression, "expr", "e", "", "Expression to eval") - cmdHubTest.AddCommand(cmdHubTestEval) + return cmdHubTestEval +} + + +func NewHubTestExplainCmd() *cobra.Command { var cmdHubTestExplain = &cobra.Command{ Use: "explain", Short: "explain [test_name]", @@ -531,7 +574,6 @@ cscli hubtest create my-scenario-test --parsers crowdsecurity/nginx --scenarios } }, } - cmdHubTest.AddCommand(cmdHubTestExplain) - return cmdHubTest + return cmdHubTestExplain } diff --git a/cmd/crowdsec-cli/notifications.go b/cmd/crowdsec-cli/notifications.go index fd5238688..f9b51b381 100644 --- a/cmd/crowdsec-cli/notifications.go +++ b/cmd/crowdsec-cli/notifications.go @@ -27,12 +27,14 @@ import ( "github.com/crowdsecurity/crowdsec/pkg/cwversion" ) + type NotificationsCfg struct { Config csplugin.PluginConfig `json:"plugin_config"` Profiles []*csconfig.ProfileCfg `json:"associated_profiles"` ids []uint } + func NewNotificationsCmd() *cobra.Command { var cmdNotifications = &cobra.Command{ Use: "notifications [action]", @@ -54,6 +56,80 @@ func NewNotificationsCmd() *cobra.Command { }, } + + cmdNotifications.AddCommand(NewNotificationsListCmd()) + cmdNotifications.AddCommand(NewNotificationsInspectCmd()) + cmdNotifications.AddCommand(NewNotificationsReinjectCmd()) + + return cmdNotifications +} + + +func getNotificationsConfiguration() (map[string]NotificationsCfg, error) { + pcfgs := map[string]csplugin.PluginConfig{} + wf := func(path string, info fs.FileInfo, err error) error { + if info == nil { + return errors.Wrapf(err, "error while traversing directory %s", path) + } + name := filepath.Join(csConfig.ConfigPaths.NotificationDir, info.Name()) //Avoid calling info.Name() twice + if (strings.HasSuffix(name, "yaml") || strings.HasSuffix(name, "yml")) && !(info.IsDir()) { + ts, err := csplugin.ParsePluginConfigFile(name) + if err != nil { + return errors.Wrapf(err, "Loading notifification plugin configuration with %s", name) + } + for _, t := range ts { + pcfgs[t.Name] = t + } + } + return nil + } + + if err := filepath.Walk(csConfig.ConfigPaths.NotificationDir, wf); err != nil { + return nil, errors.Wrap(err, "Loading notifification plugin configuration") + } + + // A bit of a tricky stuf now: reconcile profiles and notification plugins + ncfgs := map[string]NotificationsCfg{} + profiles, err := csprofiles.NewProfile(csConfig.API.Server.Profiles) + if err != nil { + return nil, errors.Wrap(err, "Cannot extract profiles from configuration") + } + for profileID, profile := range profiles { + loop: + for _, notif := range profile.Cfg.Notifications { + for name, pc := range pcfgs { + if notif == name { + if _, ok := ncfgs[pc.Name]; !ok { + ncfgs[pc.Name] = NotificationsCfg{ + Config: pc, + Profiles: []*csconfig.ProfileCfg{profile.Cfg}, + ids: []uint{uint(profileID)}, + } + continue loop + } + tmp := ncfgs[pc.Name] + for _, pr := range tmp.Profiles { + var profiles []*csconfig.ProfileCfg + if pr.Name == profile.Cfg.Name { + continue + } + profiles = append(tmp.Profiles, profile.Cfg) + ids := append(tmp.ids, uint(profileID)) + ncfgs[pc.Name] = NotificationsCfg{ + Config: tmp.Config, + Profiles: profiles, + ids: ids, + } + } + } + } + } + } + return ncfgs, nil +} + + +func NewNotificationsListCmd() *cobra.Command { var cmdNotificationsList = &cobra.Command{ Use: "list", Short: "List active notifications plugins", @@ -96,8 +172,12 @@ func NewNotificationsCmd() *cobra.Command { return nil }, } - cmdNotifications.AddCommand(cmdNotificationsList) + return cmdNotificationsList +} + + +func NewNotificationsInspectCmd() *cobra.Command { var cmdNotificationsInspect = &cobra.Command{ Use: "inspect", Short: "Inspect active notifications plugin configuration", @@ -142,9 +222,15 @@ func NewNotificationsCmd() *cobra.Command { return nil }, } - cmdNotifications.AddCommand(cmdNotificationsInspect) + + return cmdNotificationsInspect +} + + +func NewNotificationsReinjectCmd() *cobra.Command { var remediation bool var alertOverride string + var cmdNotificationsReinject = &cobra.Command{ Use: "reinject", Short: "reinject alert into notifications system", @@ -264,69 +350,6 @@ cscli notifications reinject -a '{"remediation": true,"scenario":"not } cmdNotificationsReinject.Flags().BoolVarP(&remediation, "remediation", "r", false, "Set Alert.Remediation to false in the reinjected alert (see your profile filter configuration)") 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)") - cmdNotifications.AddCommand(cmdNotificationsReinject) - return cmdNotifications -} - -func getNotificationsConfiguration() (map[string]NotificationsCfg, error) { - pcfgs := map[string]csplugin.PluginConfig{} - wf := func(path string, info fs.FileInfo, err error) error { - if info == nil { - return errors.Wrapf(err, "error while traversing directory %s", path) - } - name := filepath.Join(csConfig.ConfigPaths.NotificationDir, info.Name()) //Avoid calling info.Name() twice - if (strings.HasSuffix(name, "yaml") || strings.HasSuffix(name, "yml")) && !(info.IsDir()) { - ts, err := csplugin.ParsePluginConfigFile(name) - if err != nil { - return errors.Wrapf(err, "Loading notifification plugin configuration with %s", name) - } - for _, t := range ts { - pcfgs[t.Name] = t - } - } - return nil - } - - if err := filepath.Walk(csConfig.ConfigPaths.NotificationDir, wf); err != nil { - return nil, errors.Wrap(err, "Loading notifification plugin configuration") - } - - // A bit of a tricky stuf now: reconcile profiles and notification plugins - ncfgs := map[string]NotificationsCfg{} - profiles, err := csprofiles.NewProfile(csConfig.API.Server.Profiles) - if err != nil { - return nil, errors.Wrap(err, "Cannot extract profiles from configuration") - } - for profileID, profile := range profiles { - loop: - for _, notif := range profile.Cfg.Notifications { - for name, pc := range pcfgs { - if notif == name { - if _, ok := ncfgs[pc.Name]; !ok { - ncfgs[pc.Name] = NotificationsCfg{ - Config: pc, - Profiles: []*csconfig.ProfileCfg{profile.Cfg}, - ids: []uint{uint(profileID)}, - } - continue loop - } - tmp := ncfgs[pc.Name] - for _, pr := range tmp.Profiles { - var profiles []*csconfig.ProfileCfg - if pr.Name == profile.Cfg.Name { - continue - } - profiles = append(tmp.Profiles, profile.Cfg) - ids := append(tmp.ids, uint(profileID)) - ncfgs[pc.Name] = NotificationsCfg{ - Config: tmp.Config, - Profiles: profiles, - ids: ids, - } - } - } - } - } - } - return ncfgs, nil + + return cmdNotificationsReinject } diff --git a/cmd/crowdsec-cli/parsers.go b/cmd/crowdsec-cli/parsers.go index 973b60e00..9b810238b 100644 --- a/cmd/crowdsec-cli/parsers.go +++ b/cmd/crowdsec-cli/parsers.go @@ -10,6 +10,7 @@ import ( "github.com/crowdsecurity/crowdsec/pkg/cwhub" ) + func NewParsersCmd() *cobra.Command { var cmdParsers = &cobra.Command{ Use: "parsers [action] [config]", @@ -49,7 +50,19 @@ cscli parsers remove crowdsecurity/sshd-logs }, } + cmdParsers.AddCommand(NewParsersInstallCmd()) + cmdParsers.AddCommand(NewParsersRemoveCmd()) + cmdParsers.AddCommand(NewParsersUpgradeCmd()) + cmdParsers.AddCommand(NewParsersInspectCmd()) + cmdParsers.AddCommand(NewParsersListCmd()) + + return cmdParsers +} + + +func NewParsersInstallCmd() *cobra.Command { var ignoreError bool + var cmdParsersInstall = &cobra.Command{ Use: "install [config]", Short: "Install given parser(s)", @@ -81,8 +94,12 @@ cscli parsers remove crowdsecurity/sshd-logs cmdParsersInstall.PersistentFlags().BoolVarP(&downloadOnly, "download-only", "d", false, "Only download packages, don't enable") cmdParsersInstall.PersistentFlags().BoolVar(&forceAction, "force", false, "Force install : Overwrite tainted and outdated files") cmdParsersInstall.PersistentFlags().BoolVar(&ignoreError, "ignore", false, "Ignore errors when installing multiple parsers") - cmdParsers.AddCommand(cmdParsersInstall) + return cmdParsersInstall +} + + +func NewParsersRemoveCmd() *cobra.Command { var cmdParsersRemove = &cobra.Command{ Use: "remove [config]", Short: "Remove given parser(s)", @@ -111,8 +128,12 @@ cscli parsers remove crowdsecurity/sshd-logs cmdParsersRemove.PersistentFlags().BoolVar(&purge, "purge", false, "Delete source file too") cmdParsersRemove.PersistentFlags().BoolVar(&forceAction, "force", false, "Force remove : Remove tainted and outdated files") cmdParsersRemove.PersistentFlags().BoolVar(&all, "all", false, "Delete all the parsers") - cmdParsers.AddCommand(cmdParsersRemove) + return cmdParsersRemove +} + + +func NewParsersUpgradeCmd() *cobra.Command { var cmdParsersUpgrade = &cobra.Command{ Use: "upgrade [config]", Short: "Upgrade given parser(s)", @@ -137,8 +158,12 @@ cscli parsers remove crowdsecurity/sshd-logs } cmdParsersUpgrade.PersistentFlags().BoolVar(&all, "all", false, "Upgrade all the parsers") cmdParsersUpgrade.PersistentFlags().BoolVar(&forceAction, "force", false, "Force upgrade : Overwrite tainted and outdated files") - cmdParsers.AddCommand(cmdParsersUpgrade) + return cmdParsersUpgrade +} + + +func NewParsersInspectCmd() *cobra.Command { var cmdParsersInspect = &cobra.Command{ Use: "inspect [name]", Short: "Inspect given parser", @@ -154,8 +179,12 @@ cscli parsers remove crowdsecurity/sshd-logs }, } cmdParsersInspect.PersistentFlags().StringVarP(&prometheusURL, "url", "u", "", "Prometheus url") - cmdParsers.AddCommand(cmdParsersInspect) + return cmdParsersInspect +} + + +func NewParsersListCmd() *cobra.Command { var cmdParsersList = &cobra.Command{ Use: "list [name]", Short: "List all parsers or given one", @@ -168,7 +197,6 @@ cscli parser list crowdsecurity/xxx`, }, } cmdParsersList.PersistentFlags().BoolVarP(&all, "all", "a", false, "List disabled items as well") - cmdParsers.AddCommand(cmdParsersList) - return cmdParsers + return cmdParsersList } diff --git a/cmd/crowdsec-cli/scenarios.go b/cmd/crowdsec-cli/scenarios.go index cc892b2ca..a5b433228 100644 --- a/cmd/crowdsec-cli/scenarios.go +++ b/cmd/crowdsec-cli/scenarios.go @@ -12,7 +12,6 @@ import ( ) func NewScenariosCmd() *cobra.Command { - var cmdScenarios = &cobra.Command{ Use: "scenarios [action] [config]", Short: "Install/Remove/Upgrade/Inspect scenario(s) from hub", @@ -52,7 +51,18 @@ cscli scenarios remove crowdsecurity/ssh-bf }, } + cmdScenarios.AddCommand(NewCmdScenariosInstall()) + cmdScenarios.AddCommand(NewCmdScenariosRemove()) + cmdScenarios.AddCommand(NewCmdScenariosUpgrade()) + cmdScenarios.AddCommand(NewCmdScenariosInspect()) + cmdScenarios.AddCommand(NewCmdScenariosList()) + + return cmdScenarios +} + +func NewCmdScenariosInstall() *cobra.Command { var ignoreError bool + var cmdScenariosInstall = &cobra.Command{ Use: "install [config]", Short: "Install given scenario(s)", @@ -84,8 +94,11 @@ cscli scenarios remove crowdsecurity/ssh-bf cmdScenariosInstall.PersistentFlags().BoolVarP(&downloadOnly, "download-only", "d", false, "Only download packages, don't enable") cmdScenariosInstall.PersistentFlags().BoolVar(&forceAction, "force", false, "Force install : Overwrite tainted and outdated files") cmdScenariosInstall.PersistentFlags().BoolVar(&ignoreError, "ignore", false, "Ignore errors when installing multiple scenarios") - cmdScenarios.AddCommand(cmdScenariosInstall) + return cmdScenariosInstall +} + +func NewCmdScenariosRemove() *cobra.Command { var cmdScenariosRemove = &cobra.Command{ Use: "remove [config]", Short: "Remove given scenario(s)", @@ -114,8 +127,11 @@ cscli scenarios remove crowdsecurity/ssh-bf cmdScenariosRemove.PersistentFlags().BoolVar(&purge, "purge", false, "Delete source file too") cmdScenariosRemove.PersistentFlags().BoolVar(&forceAction, "force", false, "Force remove : Remove tainted and outdated files") cmdScenariosRemove.PersistentFlags().BoolVar(&all, "all", false, "Delete all the scenarios") - cmdScenarios.AddCommand(cmdScenariosRemove) + return cmdScenariosRemove +} + +func NewCmdScenariosUpgrade() *cobra.Command { var cmdScenariosUpgrade = &cobra.Command{ Use: "upgrade [config]", Short: "Upgrade given scenario(s)", @@ -140,8 +156,11 @@ cscli scenarios remove crowdsecurity/ssh-bf } cmdScenariosUpgrade.PersistentFlags().BoolVarP(&all, "all", "a", false, "Upgrade all the scenarios") cmdScenariosUpgrade.PersistentFlags().BoolVar(&forceAction, "force", false, "Force upgrade : Overwrite tainted and outdated files") - cmdScenarios.AddCommand(cmdScenariosUpgrade) + return cmdScenariosUpgrade +} + +func NewCmdScenariosInspect() *cobra.Command { var cmdScenariosInspect = &cobra.Command{ Use: "inspect [config]", Short: "Inspect given scenario", @@ -157,8 +176,11 @@ cscli scenarios remove crowdsecurity/ssh-bf }, } cmdScenariosInspect.PersistentFlags().StringVarP(&prometheusURL, "url", "u", "", "Prometheus url") - cmdScenarios.AddCommand(cmdScenariosInspect) + return cmdScenariosInspect +} + +func NewCmdScenariosList() *cobra.Command { var cmdScenariosList = &cobra.Command{ Use: "list [config]", Short: "List all scenario(s) or given one", @@ -171,7 +193,6 @@ cscli scenarios list crowdsecurity/xxx`, }, } cmdScenariosList.PersistentFlags().BoolVarP(&all, "all", "a", false, "List disabled items as well") - cmdScenarios.AddCommand(cmdScenariosList) - return cmdScenarios + return cmdScenariosList } diff --git a/cmd/crowdsec-cli/simulation.go b/cmd/crowdsec-cli/simulation.go index 456f5ef3e..743712d31 100644 --- a/cmd/crowdsec-cli/simulation.go +++ b/cmd/crowdsec-cli/simulation.go @@ -127,7 +127,16 @@ cscli simulation disable crowdsecurity/ssh-bf`, cmdSimulation.Flags().SortFlags = false cmdSimulation.PersistentFlags().SortFlags = false + cmdSimulation.AddCommand(NewSimulationEnableCmd()) + cmdSimulation.AddCommand(NewSimulationDisableCmd()) + cmdSimulation.AddCommand(NewSimulationStatusCmd()) + + return cmdSimulation +} + +func NewSimulationEnableCmd() *cobra.Command { var forceGlobalSimulation bool + var cmdSimulationEnable = &cobra.Command{ Use: "enable [scenario] [-global]", Short: "Enable the simulation, globally or on specified scenarios", @@ -186,7 +195,12 @@ cscli simulation disable crowdsecurity/ssh-bf`, }, } cmdSimulationEnable.Flags().BoolVarP(&forceGlobalSimulation, "global", "g", false, "Enable global simulation (reverse mode)") - cmdSimulation.AddCommand(cmdSimulationEnable) + + return cmdSimulationEnable +} + +func NewSimulationDisableCmd() *cobra.Command { + var forceGlobalSimulation bool var cmdSimulationDisable = &cobra.Command{ Use: "disable [scenario]", @@ -230,8 +244,11 @@ cscli simulation disable crowdsecurity/ssh-bf`, }, } cmdSimulationDisable.Flags().BoolVarP(&forceGlobalSimulation, "global", "g", false, "Disable global simulation (reverse mode)") - cmdSimulation.AddCommand(cmdSimulationDisable) + return cmdSimulationDisable +} + +func NewSimulationStatusCmd() *cobra.Command { var cmdSimulationStatus = &cobra.Command{ Use: "status", Short: "Show simulation mode status", @@ -245,7 +262,6 @@ cscli simulation disable crowdsecurity/ssh-bf`, PersistentPostRun: func(cmd *cobra.Command, args []string) { }, } - cmdSimulation.AddCommand(cmdSimulationStatus) - return cmdSimulation + return cmdSimulationStatus }