database.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. package database
  2. import (
  3. "context"
  4. "fmt"
  5. "os"
  6. "time"
  7. "github.com/crowdsecurity/crowdsec/pkg/csconfig"
  8. "github.com/crowdsecurity/crowdsec/pkg/database/ent"
  9. "github.com/crowdsecurity/crowdsec/pkg/types"
  10. "github.com/go-co-op/gocron"
  11. _ "github.com/go-sql-driver/mysql"
  12. _ "github.com/lib/pq"
  13. _ "github.com/mattn/go-sqlite3"
  14. "github.com/pkg/errors"
  15. log "github.com/sirupsen/logrus"
  16. )
  17. type Client struct {
  18. Ent *ent.Client
  19. CTX context.Context
  20. Log *log.Logger
  21. CanFlush bool
  22. }
  23. func NewClient(config *csconfig.DatabaseCfg) (*Client, error) {
  24. var client *ent.Client
  25. var err error
  26. if config == nil {
  27. return &Client{}, fmt.Errorf("DB config is empty")
  28. }
  29. /*The logger that will be used by db operations*/
  30. clog := log.New()
  31. if err := types.ConfigureLogger(clog); err != nil {
  32. return nil, errors.Wrap(err, "while configuring db logger")
  33. }
  34. if config.LogLevel != nil {
  35. clog.SetLevel(*config.LogLevel)
  36. }
  37. entLogger := clog.WithField("context", "ent")
  38. entOpt := ent.Log(entLogger.Debug)
  39. switch config.Type {
  40. case "sqlite":
  41. /*if it's the first startup, we want to touch and chmod file*/
  42. if _, err := os.Stat(config.DbPath); os.IsNotExist(err) {
  43. f, err := os.OpenFile(config.DbPath, os.O_CREATE|os.O_RDWR, 0600)
  44. if err != nil {
  45. return &Client{}, errors.Wrapf(err, "failed to create SQLite database file %q", config.DbPath)
  46. }
  47. if err := f.Close(); err != nil {
  48. return &Client{}, errors.Wrapf(err, "failed to create SQLite database file %q", config.DbPath)
  49. }
  50. } else { /*ensure file perms*/
  51. if err := os.Chmod(config.DbPath, 0660); err != nil {
  52. return &Client{}, fmt.Errorf("unable to set perms on %s: %v", config.DbPath, err)
  53. }
  54. }
  55. client, err = ent.Open("sqlite3", fmt.Sprintf("file:%s?_busy_timeout=100000&_fk=1", config.DbPath), entOpt)
  56. if err != nil {
  57. return &Client{}, fmt.Errorf("failed opening connection to sqlite: %v", err)
  58. }
  59. case "mysql":
  60. client, err = ent.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?parseTime=True", config.User, config.Password, config.Host, config.Port, config.DbName), entOpt)
  61. if err != nil {
  62. return &Client{}, fmt.Errorf("failed opening connection to mysql: %v", err)
  63. }
  64. case "postgres", "postgresql":
  65. client, err = ent.Open("postgres", fmt.Sprintf("host=%s port=%d user=%s dbname=%s password=%s sslmode=%s", config.Host, config.Port, config.User, config.DbName, config.Password, config.Sslmode), entOpt)
  66. if err != nil {
  67. return &Client{}, fmt.Errorf("failed opening connection to postgres: %v", err)
  68. }
  69. default:
  70. return &Client{}, fmt.Errorf("unknown database type")
  71. }
  72. if config.LogLevel != nil && *config.LogLevel >= log.DebugLevel {
  73. clog.Debugf("Enabling request debug")
  74. client = client.Debug()
  75. }
  76. if err = client.Schema.Create(context.Background()); err != nil {
  77. return nil, fmt.Errorf("failed creating schema resources: %v", err)
  78. }
  79. return &Client{Ent: client, CTX: context.Background(), Log: clog, CanFlush: true}, nil
  80. }
  81. func (c *Client) StartFlushScheduler(config *csconfig.FlushDBCfg) (*gocron.Scheduler, error) {
  82. maxItems := 0
  83. maxAge := ""
  84. if config.MaxItems != nil && *config.MaxItems <= 0 {
  85. return nil, fmt.Errorf("max_items can't be zero or negative number")
  86. }
  87. if config.MaxItems != nil {
  88. maxItems = *config.MaxItems
  89. }
  90. if config.MaxAge != nil && *config.MaxAge != "" {
  91. maxAge = *config.MaxAge
  92. }
  93. // Init & Start cronjob every minute
  94. scheduler := gocron.NewScheduler(time.UTC)
  95. job, _ := scheduler.Every(1).Minute().Do(c.FlushAlerts, maxAge, maxItems)
  96. job.SingletonMode()
  97. scheduler.StartAsync()
  98. return scheduler, nil
  99. }