2020-11-30 09:37:17 +00:00
package csconfig
2021-03-24 17:16:17 +00:00
import (
2024-03-04 13:22:53 +00:00
"errors"
2021-03-24 17:16:17 +00:00
"fmt"
2022-06-08 14:05:52 +00:00
"time"
2021-03-24 17:16:17 +00:00
2022-12-12 16:08:19 +00:00
"entgo.io/ent/dialect"
2021-03-24 17:16:17 +00:00
log "github.com/sirupsen/logrus"
2023-06-01 14:31:56 +00:00
2023-07-28 14:35:08 +00:00
"github.com/crowdsecurity/go-cs-lib/ptr"
2021-03-24 17:16:17 +00:00
)
2020-11-30 09:37:17 +00:00
2023-09-04 12:21:45 +00:00
const (
2023-10-09 09:10:51 +00:00
DEFAULT_MAX_OPEN_CONNS = 100
2023-09-04 12:21:45 +00:00
defaultDecisionBulkSize = 1000
// we need an upper bound due to the sqlite limit of 32k variables in a query
// we have 15 variables per decision, so 32768/15 = 2184.5333
2023-10-09 09:10:51 +00:00
maxDecisionBulkSize = 2000
2023-09-04 12:21:45 +00:00
)
2023-08-25 15:05:17 +00:00
2020-11-30 09:37:17 +00:00
type DatabaseCfg struct {
2023-08-25 15:05:17 +00:00
User string ` yaml:"user" `
Password string ` yaml:"password" `
DbName string ` yaml:"db_name" `
Sslmode string ` yaml:"sslmode" `
Host string ` yaml:"host" `
Port int ` yaml:"port" `
DbPath string ` yaml:"db_path" `
Type string ` yaml:"type" `
Flush * FlushDBCfg ` yaml:"flush" `
LogLevel * log . Level ` yaml:"log_level" `
MaxOpenConns * int ` yaml:"max_open_conns,omitempty" `
UseWal * bool ` yaml:"use_wal,omitempty" `
DecisionBulkSize int ` yaml:"decision_bulk_size,omitempty" `
2020-11-30 09:37:17 +00:00
}
2022-06-08 14:05:52 +00:00
type AuthGCCfg struct {
Cert * string ` yaml:"cert,omitempty" `
CertDuration * time . Duration
Api * string ` yaml:"api_key,omitempty" `
ApiDuration * time . Duration
LoginPassword * string ` yaml:"login_password,omitempty" `
LoginPasswordDuration * time . Duration
}
2020-11-30 09:37:17 +00:00
type FlushDBCfg struct {
2022-06-08 14:05:52 +00:00
MaxItems * int ` yaml:"max_items,omitempty" `
2024-03-04 13:22:53 +00:00
// We could unmarshal as time.Duration, but alert filters right now are a map of strings
2022-06-08 14:05:52 +00:00
MaxAge * string ` yaml:"max_age,omitempty" `
BouncersGC * AuthGCCfg ` yaml:"bouncers_autodelete,omitempty" `
AgentsGC * AuthGCCfg ` yaml:"agents_autodelete,omitempty" `
2020-11-30 09:37:17 +00:00
}
2021-03-24 17:16:17 +00:00
2024-01-30 10:07:53 +00:00
func ( c * Config ) LoadDBConfig ( inCli bool ) error {
2021-03-24 17:16:17 +00:00
if c . DbConfig == nil {
2024-03-04 13:22:53 +00:00
return errors . New ( "no database configuration provided" )
2021-03-24 17:16:17 +00:00
}
if c . Cscli != nil {
c . Cscli . DbConfig = c . DbConfig
}
if c . API != nil && c . API . Server != nil {
c . API . Server . DbConfig = c . DbConfig
}
2022-02-17 16:52:04 +00:00
if c . DbConfig . MaxOpenConns == nil {
2023-06-01 14:31:56 +00:00
c . DbConfig . MaxOpenConns = ptr . Of ( DEFAULT_MAX_OPEN_CONNS )
2022-02-17 16:52:04 +00:00
}
2022-11-07 15:36:39 +00:00
2023-08-25 15:05:17 +00:00
if c . DbConfig . DecisionBulkSize == 0 {
log . Tracef ( "No decision_bulk_size value provided, using default value of %d" , defaultDecisionBulkSize )
c . DbConfig . DecisionBulkSize = defaultDecisionBulkSize
}
2023-09-04 12:21:45 +00:00
if c . DbConfig . DecisionBulkSize > maxDecisionBulkSize {
log . Warningf ( "decision_bulk_size too high (%d), setting to the maximum value of %d" , c . DbConfig . DecisionBulkSize , maxDecisionBulkSize )
c . DbConfig . DecisionBulkSize = maxDecisionBulkSize
}
2024-01-30 10:07:53 +00:00
if ! inCli && c . DbConfig . Type == "sqlite" && c . DbConfig . UseWal == nil {
log . Warning ( "You are using sqlite without WAL, this can have a performance impact. If you do not store the database in a network share, set db_config.use_wal to true. Set explicitly to false to disable this warning." )
2022-11-07 15:36:39 +00:00
}
2021-03-24 17:16:17 +00:00
return nil
}
2022-12-12 16:08:19 +00:00
func ( d * DatabaseCfg ) ConnectionString ( ) string {
connString := ""
2024-03-04 13:22:53 +00:00
2022-12-12 16:08:19 +00:00
switch d . Type {
case "sqlite" :
var sqliteConnectionStringParameters string
if d . UseWal != nil && * d . UseWal {
sqliteConnectionStringParameters = "_busy_timeout=100000&_fk=1&_journal_mode=WAL"
} else {
sqliteConnectionStringParameters = "_busy_timeout=100000&_fk=1"
}
2024-03-04 13:22:53 +00:00
2022-12-12 16:08:19 +00:00
connString = fmt . Sprintf ( "file:%s?%s" , d . DbPath , sqliteConnectionStringParameters )
case "mysql" :
if d . isSocketConfig ( ) {
connString = fmt . Sprintf ( "%s:%s@unix(%s)/%s?parseTime=True" , d . User , d . Password , d . DbPath , d . DbName )
} else {
connString = fmt . Sprintf ( "%s:%s@tcp(%s:%d)/%s?parseTime=True" , d . User , d . Password , d . Host , d . Port , d . DbName )
}
case "postgres" , "postgresql" , "pgx" :
if d . isSocketConfig ( ) {
connString = fmt . Sprintf ( "host=%s user=%s dbname=%s password=%s" , d . DbPath , d . User , d . DbName , d . Password )
} else {
connString = fmt . Sprintf ( "host=%s port=%d user=%s dbname=%s password=%s sslmode=%s" , d . Host , d . Port , d . User , d . DbName , d . Password , d . Sslmode )
}
}
2024-03-04 13:22:53 +00:00
2022-12-12 16:08:19 +00:00
return connString
}
func ( d * DatabaseCfg ) ConnectionDialect ( ) ( string , string , error ) {
switch d . Type {
case "sqlite" :
return "sqlite3" , dialect . SQLite , nil
case "mysql" :
return "mysql" , dialect . MySQL , nil
2023-03-16 10:02:31 +00:00
case "pgx" , "postgresql" , "postgres" :
if d . Type != "pgx" {
log . Debugf ( "database type '%s' is deprecated, switching to 'pgx' instead" , d . Type )
}
2024-03-04 13:22:53 +00:00
2022-12-12 16:08:19 +00:00
return "pgx" , dialect . Postgres , nil
}
2024-03-04 13:22:53 +00:00
2022-12-12 16:08:19 +00:00
return "" , "" , fmt . Errorf ( "unknown database type '%s'" , d . Type )
}
func ( d * DatabaseCfg ) isSocketConfig ( ) bool {
return d . Host == "" && d . Port == 0 && d . DbPath != ""
}