main.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "path/filepath"
  6. "slices"
  7. "strings"
  8. "github.com/fatih/color"
  9. cc "github.com/ivanpirog/coloredcobra"
  10. log "github.com/sirupsen/logrus"
  11. "github.com/spf13/cobra"
  12. "github.com/spf13/cobra/doc"
  13. "github.com/crowdsecurity/crowdsec/pkg/csconfig"
  14. "github.com/crowdsecurity/crowdsec/pkg/cwhub"
  15. "github.com/crowdsecurity/crowdsec/pkg/cwversion"
  16. "github.com/crowdsecurity/crowdsec/pkg/database"
  17. "github.com/crowdsecurity/crowdsec/pkg/fflag"
  18. )
  19. var trace_lvl, dbg_lvl, nfo_lvl, wrn_lvl, err_lvl bool
  20. var ConfigFilePath string
  21. var csConfig *csconfig.Config
  22. var dbClient *database.Client
  23. var OutputFormat string
  24. var OutputColor string
  25. var downloadOnly bool
  26. var forceAction bool
  27. var purge bool
  28. var all bool
  29. var prometheusURL string
  30. var mergedConfig string
  31. func initConfig() {
  32. var err error
  33. if trace_lvl {
  34. log.SetLevel(log.TraceLevel)
  35. } else if dbg_lvl {
  36. log.SetLevel(log.DebugLevel)
  37. } else if nfo_lvl {
  38. log.SetLevel(log.InfoLevel)
  39. } else if wrn_lvl {
  40. log.SetLevel(log.WarnLevel)
  41. } else if err_lvl {
  42. log.SetLevel(log.ErrorLevel)
  43. }
  44. if !slices.Contains(NoNeedConfig, os.Args[1]) {
  45. log.Debugf("Using %s as configuration file", ConfigFilePath)
  46. csConfig, mergedConfig, err = csconfig.NewConfig(ConfigFilePath, false, false, true)
  47. if err != nil {
  48. log.Fatal(err)
  49. }
  50. if err := csConfig.LoadCSCLI(); err != nil {
  51. log.Fatal(err)
  52. }
  53. } else {
  54. csConfig = csconfig.NewDefaultConfig()
  55. }
  56. // recap of the enabled feature flags, because logging
  57. // was not enabled when we set them from envvars
  58. if fflist := csconfig.ListFeatureFlags(); fflist != "" {
  59. log.Debugf("Enabled feature flags: %s", fflist)
  60. }
  61. if csConfig.Cscli == nil {
  62. log.Fatalf("missing 'cscli' configuration in '%s', exiting", ConfigFilePath)
  63. }
  64. if cwhub.HubBranch == "" && csConfig.Cscli.HubBranch != "" {
  65. cwhub.HubBranch = csConfig.Cscli.HubBranch
  66. }
  67. if OutputFormat != "" {
  68. csConfig.Cscli.Output = OutputFormat
  69. if OutputFormat != "json" && OutputFormat != "raw" && OutputFormat != "human" {
  70. log.Fatalf("output format %s unknown", OutputFormat)
  71. }
  72. }
  73. if csConfig.Cscli.Output == "" {
  74. csConfig.Cscli.Output = "human"
  75. }
  76. if csConfig.Cscli.Output == "json" {
  77. log.SetFormatter(&log.JSONFormatter{})
  78. log.SetLevel(log.ErrorLevel)
  79. } else if csConfig.Cscli.Output == "raw" {
  80. log.SetLevel(log.ErrorLevel)
  81. }
  82. if OutputColor != "" {
  83. csConfig.Cscli.Color = OutputColor
  84. if OutputColor != "yes" && OutputColor != "no" && OutputColor != "auto" {
  85. log.Fatalf("output color %s unknown", OutputColor)
  86. }
  87. }
  88. }
  89. var validArgs = []string{
  90. "scenarios", "parsers", "collections", "capi", "lapi", "postoverflows", "machines",
  91. "metrics", "bouncers", "alerts", "decisions", "simulation", "hub", "dashboard",
  92. "config", "completion", "version", "console", "notifications", "support",
  93. }
  94. func prepender(filename string) string {
  95. const header = `---
  96. id: %s
  97. title: %s
  98. ---
  99. `
  100. name := filepath.Base(filename)
  101. base := strings.TrimSuffix(name, filepath.Ext(name))
  102. return fmt.Sprintf(header, base, strings.ReplaceAll(base, "_", " "))
  103. }
  104. func linkHandler(name string) string {
  105. return fmt.Sprintf("/cscli/%s", name)
  106. }
  107. var (
  108. NoNeedConfig = []string{
  109. "help",
  110. "completion",
  111. "version",
  112. "hubtest",
  113. }
  114. )
  115. func main() {
  116. // set the formatter asap and worry about level later
  117. logFormatter := &log.TextFormatter{TimestampFormat: "2006-01-02 15:04:05", FullTimestamp: true}
  118. log.SetFormatter(logFormatter)
  119. if err := fflag.RegisterAllFeatures(); err != nil {
  120. log.Fatalf("failed to register features: %s", err)
  121. }
  122. if err := csconfig.LoadFeatureFlagsEnv(log.StandardLogger()); err != nil {
  123. log.Fatalf("failed to set feature flags from env: %s", err)
  124. }
  125. var rootCmd = &cobra.Command{
  126. Use: "cscli",
  127. Short: "cscli allows you to manage crowdsec",
  128. Long: `cscli is the main command to interact with your crowdsec service, scenarios & db.
  129. It is meant to allow you to manage bans, parsers/scenarios/etc, api and generally manage you crowdsec setup.`,
  130. ValidArgs: validArgs,
  131. DisableAutoGenTag: true,
  132. SilenceErrors: true,
  133. SilenceUsage: true,
  134. /*TBD examples*/
  135. }
  136. cc.Init(&cc.Config{
  137. RootCmd: rootCmd,
  138. Headings: cc.Yellow,
  139. Commands: cc.Green + cc.Bold,
  140. CmdShortDescr: cc.Cyan,
  141. Example: cc.Italic,
  142. ExecName: cc.Bold,
  143. Aliases: cc.Bold + cc.Italic,
  144. FlagsDataType: cc.White,
  145. Flags: cc.Green,
  146. FlagsDescr: cc.Cyan,
  147. })
  148. rootCmd.SetOut(color.Output)
  149. var cmdDocGen = &cobra.Command{
  150. Use: "doc",
  151. Short: "Generate the documentation in `./doc/`. Directory must exist.",
  152. Args: cobra.ExactArgs(0),
  153. Hidden: true,
  154. DisableAutoGenTag: true,
  155. RunE: func(cmd *cobra.Command, args []string) error {
  156. if err := doc.GenMarkdownTreeCustom(rootCmd, "./doc/", prepender, linkHandler); err != nil {
  157. return fmt.Errorf("Failed to generate cobra doc: %s", err)
  158. }
  159. return nil
  160. },
  161. }
  162. rootCmd.AddCommand(cmdDocGen)
  163. /*usage*/
  164. var cmdVersion = &cobra.Command{
  165. Use: "version",
  166. Short: "Display version",
  167. Args: cobra.ExactArgs(0),
  168. DisableAutoGenTag: true,
  169. Run: func(cmd *cobra.Command, args []string) {
  170. cwversion.Show()
  171. },
  172. }
  173. rootCmd.AddCommand(cmdVersion)
  174. rootCmd.PersistentFlags().StringVarP(&ConfigFilePath, "config", "c", csconfig.DefaultConfigPath("config.yaml"), "path to crowdsec config file")
  175. rootCmd.PersistentFlags().StringVarP(&OutputFormat, "output", "o", "", "Output format: human, json, raw")
  176. rootCmd.PersistentFlags().StringVarP(&OutputColor, "color", "", "auto", "Output color: yes, no, auto")
  177. rootCmd.PersistentFlags().BoolVar(&dbg_lvl, "debug", false, "Set logging to debug")
  178. rootCmd.PersistentFlags().BoolVar(&nfo_lvl, "info", false, "Set logging to info")
  179. rootCmd.PersistentFlags().BoolVar(&wrn_lvl, "warning", false, "Set logging to warning")
  180. rootCmd.PersistentFlags().BoolVar(&err_lvl, "error", false, "Set logging to error")
  181. rootCmd.PersistentFlags().BoolVar(&trace_lvl, "trace", false, "Set logging to trace")
  182. rootCmd.PersistentFlags().StringVar(&cwhub.HubBranch, "branch", "", "Override hub branch on github")
  183. if err := rootCmd.PersistentFlags().MarkHidden("branch"); err != nil {
  184. log.Fatalf("failed to hide flag: %s", err)
  185. }
  186. // Look for "-c /path/to/config.yaml"
  187. // This duplicates the logic in cobra, but we need to do it before
  188. // because feature flags can change which subcommands are available.
  189. for i, arg := range os.Args {
  190. if arg == "-c" || arg == "--config" {
  191. if len(os.Args) > i+1 {
  192. ConfigFilePath = os.Args[i+1]
  193. }
  194. }
  195. }
  196. if err := csconfig.LoadFeatureFlagsFile(ConfigFilePath, log.StandardLogger()); err != nil {
  197. log.Fatal(err)
  198. }
  199. if len(os.Args) > 1 {
  200. cobra.OnInitialize(initConfig)
  201. }
  202. /*don't sort flags so we can enforce order*/
  203. rootCmd.Flags().SortFlags = false
  204. rootCmd.PersistentFlags().SortFlags = false
  205. rootCmd.AddCommand(NewConfigCmd())
  206. rootCmd.AddCommand(NewHubCmd())
  207. rootCmd.AddCommand(NewMetricsCmd())
  208. rootCmd.AddCommand(NewDashboardCmd())
  209. rootCmd.AddCommand(NewDecisionsCmd())
  210. rootCmd.AddCommand(NewAlertsCmd())
  211. rootCmd.AddCommand(NewSimulationCmds())
  212. rootCmd.AddCommand(NewBouncersCmd())
  213. rootCmd.AddCommand(NewMachinesCmd())
  214. rootCmd.AddCommand(NewParsersCmd())
  215. rootCmd.AddCommand(NewScenariosCmd())
  216. rootCmd.AddCommand(NewCollectionsCmd())
  217. rootCmd.AddCommand(NewPostOverflowsCmd())
  218. rootCmd.AddCommand(NewCapiCmd())
  219. rootCmd.AddCommand(NewLapiCmd())
  220. rootCmd.AddCommand(NewCompletionCmd())
  221. rootCmd.AddCommand(NewConsoleCmd())
  222. rootCmd.AddCommand(NewExplainCmd())
  223. rootCmd.AddCommand(NewHubTestCmd())
  224. rootCmd.AddCommand(NewNotificationsCmd())
  225. rootCmd.AddCommand(NewSupportCmd())
  226. if fflag.CscliSetup.IsEnabled() {
  227. rootCmd.AddCommand(NewSetupCmd())
  228. }
  229. if fflag.PapiClient.IsEnabled() {
  230. rootCmd.AddCommand(NewPapiCmd())
  231. }
  232. if err := rootCmd.Execute(); err != nil {
  233. log.Fatal(err)
  234. }
  235. }