From f5fbe4a200105af8b84a47467addc4253a7c0c1b Mon Sep 17 00:00:00 2001 From: mmetc <92726601+mmetc@users.noreply.github.com> Date: Thu, 1 Feb 2024 17:27:15 +0100 Subject: [PATCH] refact "cscli dashboard" (#2803) --- cmd/crowdsec-cli/dashboard.go | 102 ++++++++++++---------- cmd/crowdsec-cli/dashboard_unsupported.go | 12 ++- cmd/crowdsec-cli/main.go | 2 +- 3 files changed, 65 insertions(+), 51 deletions(-) diff --git a/cmd/crowdsec-cli/dashboard.go b/cmd/crowdsec-cli/dashboard.go index a3701c4db..f32b9f061 100644 --- a/cmd/crowdsec-cli/dashboard.go +++ b/cmd/crowdsec-cli/dashboard.go @@ -43,14 +43,17 @@ var ( // information needed to set up a random password on user's behalf ) -type cliDashboard struct{} - -func NewCLIDashboard() *cliDashboard { - return &cliDashboard{} +type cliDashboard struct{ + cfg configGetter } -func (cli cliDashboard) NewCommand() *cobra.Command { - /* ---- UPDATE COMMAND */ +func NewCLIDashboard(getconfig configGetter) *cliDashboard { + return &cliDashboard{ + cfg: getconfig, + } +} + +func (cli *cliDashboard) NewCommand() *cobra.Command { cmd := &cobra.Command{ Use: "dashboard [command]", Short: "Manage your metabase dashboard container [requires local API]", @@ -65,8 +68,9 @@ cscli dashboard start cscli dashboard stop cscli dashboard remove `, - PersistentPreRunE: func(cmd *cobra.Command, args []string) error { - if err := require.LAPI(csConfig); err != nil { + PersistentPreRunE: func(_ *cobra.Command, _ []string) error { + cfg := cli.cfg() + if err := require.LAPI(cfg); err != nil { return err } @@ -74,13 +78,13 @@ cscli dashboard remove return err } - metabaseConfigFolderPath := filepath.Join(csConfig.ConfigPaths.ConfigDir, metabaseConfigFolder) + metabaseConfigFolderPath := filepath.Join(cfg.ConfigPaths.ConfigDir, metabaseConfigFolder) metabaseConfigPath = filepath.Join(metabaseConfigFolderPath, metabaseConfigFile) if err := os.MkdirAll(metabaseConfigFolderPath, os.ModePerm); err != nil { return err } - if err := require.DB(csConfig); err != nil { + if err := require.DB(cfg); err != nil { return err } @@ -99,16 +103,16 @@ cscli dashboard remove }, } - cmd.AddCommand(cli.NewSetupCmd()) - cmd.AddCommand(cli.NewStartCmd()) - cmd.AddCommand(cli.NewStopCmd()) - cmd.AddCommand(cli.NewShowPasswordCmd()) - cmd.AddCommand(cli.NewRemoveCmd()) + cmd.AddCommand(cli.newSetupCmd()) + cmd.AddCommand(cli.newStartCmd()) + cmd.AddCommand(cli.newStopCmd()) + cmd.AddCommand(cli.newShowPasswordCmd()) + cmd.AddCommand(cli.newRemoveCmd()) return cmd } -func (cli cliDashboard) NewSetupCmd() *cobra.Command { +func (cli *cliDashboard) newSetupCmd() *cobra.Command { var force bool cmd := &cobra.Command{ @@ -122,9 +126,9 @@ cscli dashboard setup cscli dashboard setup --listen 0.0.0.0 cscli dashboard setup -l 0.0.0.0 -p 443 --password `, - RunE: func(cmd *cobra.Command, args []string) error { + RunE: func(_ *cobra.Command, _ []string) error { if metabaseDbPath == "" { - metabaseDbPath = csConfig.ConfigPaths.DataDir + metabaseDbPath = cli.cfg().ConfigPaths.DataDir } if metabasePassword == "" { @@ -145,10 +149,10 @@ cscli dashboard setup -l 0.0.0.0 -p 443 --password if err != nil { return err } - if err = chownDatabase(dockerGroup.Gid); err != nil { + if err = cli.chownDatabase(dockerGroup.Gid); err != nil { return err } - mb, err := metabase.SetupMetabase(csConfig.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 { return err } @@ -164,26 +168,28 @@ cscli dashboard setup -l 0.0.0.0 -p 443 --password return nil }, } - cmd.Flags().BoolVarP(&force, "force", "f", false, "Force setup : override existing files") - cmd.Flags().StringVarP(&metabaseDbPath, "dir", "d", "", "Shared directory with metabase container") - cmd.Flags().StringVarP(&metabaseListenAddress, "listen", "l", metabaseListenAddress, "Listen address of container") - cmd.Flags().StringVar(&metabaseImage, "metabase-image", metabaseImage, "Metabase image to use") - cmd.Flags().StringVarP(&metabaseListenPort, "port", "p", metabaseListenPort, "Listen port of container") - cmd.Flags().BoolVarP(&forceYes, "yes", "y", false, "force yes") - //cmd.Flags().StringVarP(&metabaseUser, "user", "u", "crowdsec@crowdsec.net", "metabase user") - cmd.Flags().StringVar(&metabasePassword, "password", "", "metabase password") + + flags := cmd.Flags() + flags.BoolVarP(&force, "force", "f", false, "Force setup : override existing files") + flags.StringVarP(&metabaseDbPath, "dir", "d", "", "Shared directory with metabase container") + flags.StringVarP(&metabaseListenAddress, "listen", "l", metabaseListenAddress, "Listen address of container") + flags.StringVar(&metabaseImage, "metabase-image", metabaseImage, "Metabase image to use") + flags.StringVarP(&metabaseListenPort, "port", "p", metabaseListenPort, "Listen port of container") + flags.BoolVarP(&forceYes, "yes", "y", false, "force yes") + //flags.StringVarP(&metabaseUser, "user", "u", "crowdsec@crowdsec.net", "metabase user") + flags.StringVar(&metabasePassword, "password", "", "metabase password") return cmd } -func (cli cliDashboard) NewStartCmd() *cobra.Command { +func (cli *cliDashboard) newStartCmd() *cobra.Command { cmd := &cobra.Command{ Use: "start", Short: "Start the metabase container.", Long: `Stats the metabase container using docker.`, Args: cobra.ExactArgs(0), DisableAutoGenTag: true, - RunE: func(cmd *cobra.Command, args []string) error { + RunE: func(_ *cobra.Command, _ []string) error { mb, err := metabase.NewMetabase(metabaseConfigPath, metabaseContainerID) if err != nil { return err @@ -200,19 +206,20 @@ func (cli cliDashboard) NewStartCmd() *cobra.Command { return nil }, } + cmd.Flags().BoolVarP(&forceYes, "yes", "y", false, "force yes") return cmd } -func (cli cliDashboard) NewStopCmd() *cobra.Command { +func (cli *cliDashboard) newStopCmd() *cobra.Command { cmd := &cobra.Command{ Use: "stop", Short: "Stops the metabase container.", Long: `Stops the metabase container using docker.`, Args: cobra.ExactArgs(0), DisableAutoGenTag: true, - RunE: func(cmd *cobra.Command, args []string) error { + RunE: func(_ *cobra.Command, _ []string) error { if err := metabase.StopContainer(metabaseContainerID); err != nil { return fmt.Errorf("unable to stop container '%s': %s", metabaseContainerID, err) } @@ -223,12 +230,12 @@ func (cli cliDashboard) NewStopCmd() *cobra.Command { return cmd } -func (cli cliDashboard) NewShowPasswordCmd() *cobra.Command { +func (cli *cliDashboard) newShowPasswordCmd() *cobra.Command { cmd := &cobra.Command{Use: "show-password", Short: "displays password of metabase.", Args: cobra.ExactArgs(0), DisableAutoGenTag: true, - RunE: func(cmd *cobra.Command, args []string) error { + RunE: func(_ *cobra.Command, _ []string) error { m := metabase.Metabase{} if err := m.LoadConfig(metabaseConfigPath); err != nil { return err @@ -241,7 +248,7 @@ func (cli cliDashboard) NewShowPasswordCmd() *cobra.Command { return cmd } -func (cli cliDashboard) NewRemoveCmd() *cobra.Command { +func (cli *cliDashboard) newRemoveCmd() *cobra.Command { var force bool cmd := &cobra.Command{ @@ -254,7 +261,7 @@ func (cli cliDashboard) NewRemoveCmd() *cobra.Command { cscli dashboard remove cscli dashboard remove --force `, - RunE: func(cmd *cobra.Command, args []string) error { + RunE: func(_ *cobra.Command, _ []string) error { if !forceYes { var answer bool prompt := &survey.Confirm{ @@ -291,8 +298,8 @@ cscli dashboard remove --force } log.Infof("container %s stopped & removed", metabaseContainerID) } - log.Debugf("Removing metabase db %s", csConfig.ConfigPaths.DataDir) - if err := metabase.RemoveDatabase(csConfig.ConfigPaths.DataDir); err != nil { + log.Debugf("Removing metabase db %s", cli.cfg().ConfigPaths.DataDir) + if err := metabase.RemoveDatabase(cli.cfg().ConfigPaths.DataDir); err != nil { log.Warnf("failed to remove metabase internal db : %s", err) } if force { @@ -309,8 +316,10 @@ cscli dashboard remove --force return nil }, } - cmd.Flags().BoolVarP(&force, "force", "f", false, "Remove also the metabase image") - cmd.Flags().BoolVarP(&forceYes, "yes", "y", false, "force yes") + + flags := cmd.Flags() + flags.BoolVarP(&force, "force", "f", false, "Remove also the metabase image") + flags.BoolVarP(&forceYes, "yes", "y", false, "force yes") return cmd } @@ -431,22 +440,23 @@ func checkGroups(forceYes *bool) (*user.Group, error) { return user.LookupGroup(crowdsecGroup) } -func chownDatabase(gid string) error { +func (cli *cliDashboard) chownDatabase(gid string) error { + cfg := cli.cfg() intID, err := strconv.Atoi(gid) if err != nil { return fmt.Errorf("unable to convert group ID to int: %s", err) } - if stat, err := os.Stat(csConfig.DbConfig.DbPath); !os.IsNotExist(err) { + if stat, err := os.Stat(cfg.DbConfig.DbPath); !os.IsNotExist(err) { info := stat.Sys() - if err := os.Chown(csConfig.DbConfig.DbPath, int(info.(*syscall.Stat_t).Uid), intID); err != nil { - return fmt.Errorf("unable to chown sqlite db file '%s': %s", csConfig.DbConfig.DbPath, err) + if err := os.Chown(cfg.DbConfig.DbPath, int(info.(*syscall.Stat_t).Uid), intID); err != nil { + return fmt.Errorf("unable to chown sqlite db file '%s': %s", cfg.DbConfig.DbPath, err) } } - if csConfig.DbConfig.Type == "sqlite" && csConfig.DbConfig.UseWal != nil && *csConfig.DbConfig.UseWal { + if cfg.DbConfig.Type == "sqlite" && cfg.DbConfig.UseWal != nil && *cfg.DbConfig.UseWal { for _, ext := range []string{"-wal", "-shm"} { - file := csConfig.DbConfig.DbPath + ext + file := cfg.DbConfig.DbPath + ext if stat, err := os.Stat(file); !os.IsNotExist(err) { info := stat.Sys() if err := os.Chown(file, int(info.(*syscall.Stat_t).Uid), intID); err != nil { diff --git a/cmd/crowdsec-cli/dashboard_unsupported.go b/cmd/crowdsec-cli/dashboard_unsupported.go index 072ff525b..4cf8e18b5 100644 --- a/cmd/crowdsec-cli/dashboard_unsupported.go +++ b/cmd/crowdsec-cli/dashboard_unsupported.go @@ -9,17 +9,21 @@ import ( "github.com/spf13/cobra" ) -type cliDashboard struct{} +type cliDashboard struct{ + cfg configGetter +} -func NewCLIDashboard() *cliDashboard { - return &cliDashboard{} +func NewCLIDashboard(getconfig configGetter) *cliDashboard { + return &cliDashboard{ + cfg: getconfig, + } } func (cli cliDashboard) NewCommand() *cobra.Command { cmd := &cobra.Command{ Use: "dashboard", DisableAutoGenTag: true, - Run: func(cmd *cobra.Command, args []string) { + Run: func(_ *cobra.Command, _ []string) { log.Infof("Dashboard command is disabled on %s", runtime.GOOS) }, } diff --git a/cmd/crowdsec-cli/main.go b/cmd/crowdsec-cli/main.go index a64209876..055c38e27 100644 --- a/cmd/crowdsec-cli/main.go +++ b/cmd/crowdsec-cli/main.go @@ -196,7 +196,7 @@ It is meant to allow you to manage bans, parsers/scenarios/etc, api and generall cmd.AddCommand(NewConfigCmd()) cmd.AddCommand(NewCLIHub(getconfig).NewCommand()) cmd.AddCommand(NewMetricsCmd()) - cmd.AddCommand(NewCLIDashboard().NewCommand()) + cmd.AddCommand(NewCLIDashboard(getconfig).NewCommand()) cmd.AddCommand(NewCLIDecisions().NewCommand()) cmd.AddCommand(NewCLIAlerts().NewCommand()) cmd.AddCommand(NewCLISimulation(getconfig).NewCommand())