diff --git a/pkg/config/database.go b/pkg/config/database.go index 5ef8c3dc..0f57f579 100644 --- a/pkg/config/database.go +++ b/pkg/config/database.go @@ -2,8 +2,6 @@ package config import ( "fmt" - "github.com/creasty/defaults" - "github.com/icinga/icingadb/internal" "github.com/icinga/icingadb/pkg/driver" "github.com/icinga/icingadb/pkg/icingadb" "github.com/icinga/icingadb/pkg/utils" @@ -18,12 +16,12 @@ var registerDriverOnce sync.Once // Database defines database client configuration. type Database struct { - Host string `yaml:"host"` - Port int `yaml:"port"` - Database string `yaml:"database"` - User string `yaml:"user"` - Password string `yaml:"password"` - icingadb.Options `yaml:",inline"` + Host string `yaml:"host"` + Port int `yaml:"port"` + Database string `yaml:"database"` + User string `yaml:"user"` + Password string `yaml:"password"` + Options icingadb.Options `yaml:"options"` } // Open prepares the DSN string and driver configuration, @@ -42,8 +40,8 @@ func (d *Database) Open(logger *zap.SugaredLogger) (*icingadb.DB, error) { return nil, errors.Wrap(err, "can't open database") } - db.SetMaxIdleConns(d.MaxConnections / 3) - db.SetMaxOpenConns(d.MaxConnections) + db.SetMaxIdleConns(d.Options.MaxConnections / 3) + db.SetMaxOpenConns(d.Options.MaxConnections) db.Mapper = reflectx.NewMapperFunc("db", func(s string) string { return utils.Key(s, '_') @@ -51,21 +49,3 @@ func (d *Database) Open(logger *zap.SugaredLogger) (*icingadb.DB, error) { return icingadb.NewDb(db, logger, &d.Options), nil } - -// UnmarshalYAML implements the yaml.Unmarshaler interface. -func (d *Database) UnmarshalYAML(unmarshal func(interface{}) error) error { - if err := defaults.Set(d); err != nil { - return errors.Wrap(err, "can't set default database config") - } - // Prevent recursion. - type self Database - if err := unmarshal((*self)(d)); err != nil { - return internal.CantUnmarshalYAML(err, d) - } - - if d.MaxConnectionsPerTable < 1 { - return errors.New("max_connections_per_table must be at least 1") - } - - return nil -} diff --git a/pkg/config/redis.go b/pkg/config/redis.go index 717f5624..f11412b5 100644 --- a/pkg/config/redis.go +++ b/pkg/config/redis.go @@ -2,9 +2,7 @@ package config import ( "context" - "github.com/creasty/defaults" "github.com/go-redis/redis/v8" - "github.com/icinga/icingadb/internal" "github.com/icinga/icingadb/pkg/backoff" "github.com/icinga/icingadb/pkg/icingaredis" "github.com/icinga/icingadb/pkg/retry" @@ -19,9 +17,9 @@ import ( // Redis defines Redis client configuration. type Redis struct { - Address string `yaml:"address"` - Password string `yaml:"password"` - icingaredis.Options `yaml:",inline"` + Address string `yaml:"address"` + Password string `yaml:"password"` + Options icingaredis.Options `yaml:"options"` } // NewClient prepares Redis client configuration, @@ -32,7 +30,7 @@ func (r *Redis) NewClient(logger *zap.SugaredLogger) (*icingaredis.Client, error Dialer: dialWithLogging(logger), Password: r.Password, DB: 0, // Use default DB, - ReadTimeout: r.Timeout, + ReadTimeout: r.Options.Timeout, }) opts := c.Options() @@ -76,27 +74,3 @@ func dialWithLogging(logger *zap.SugaredLogger) func(context.Context, string, st return } } - -// UnmarshalYAML implements the yaml.Unmarshaler interface. -func (r *Redis) UnmarshalYAML(unmarshal func(interface{}) error) error { - if err := defaults.Set(r); err != nil { - return errors.Wrapf(err, "can't set defaults %#v", r) - } - // Prevent recursion. - type self Redis - if err := unmarshal((*self)(r)); err != nil { - return internal.CantUnmarshalYAML(err, r) - } - - if r.MaxHMGetConnections < 1 { - return errors.New("max_hmget_connections must be at least 1") - } - if r.HMGetCount < 1 { - return errors.New("hmget_count must be at least 1") - } - if r.HScanCount < 1 { - return errors.New("hscan_count must be at least 1") - } - - return nil -} diff --git a/pkg/icingadb/db.go b/pkg/icingadb/db.go index e471d6dc..51ff8b9e 100644 --- a/pkg/icingadb/db.go +++ b/pkg/icingadb/db.go @@ -4,6 +4,7 @@ import ( "context" "database/sql/driver" "fmt" + "github.com/creasty/defaults" "github.com/go-sql-driver/mysql" "github.com/icinga/icingadb/internal" "github.com/icinga/icingadb/pkg/backoff" @@ -55,6 +56,27 @@ type Options struct { MaxRowsPerTransaction int `yaml:"MaxRowsPerTransaction" default:"8192"` } +// UnmarshalYAML implements the yaml.Unmarshaler interface. +func (o *Options) UnmarshalYAML(unmarshal func(interface{}) error) error { + if err := defaults.Set(o); err != nil { + return errors.Wrap(err, "can't set default database config") + } + // Prevent recursion. + type self Options + if err := unmarshal((*self)(o)); err != nil { + return internal.CantUnmarshalYAML(err, o) + } + + if o.MaxConnections == 0 { + return errors.New("max_connections cannot be 0. Configure a value greater than zero, or use -1 for no connection limit") + } + if o.MaxConnectionsPerTable < 1 { + return errors.New("max_connections_per_table must be at least 1") + } + + return nil +} + // NewDb returns a new icingadb.DB wrapper for a pre-existing *sqlx.DB. func NewDb(db *sqlx.DB, logger *zap.SugaredLogger, options *Options) *DB { return &DB{ diff --git a/pkg/icingaredis/client.go b/pkg/icingaredis/client.go index 01a765d7..a56cb105 100644 --- a/pkg/icingaredis/client.go +++ b/pkg/icingaredis/client.go @@ -2,7 +2,9 @@ package icingaredis import ( "context" + "github.com/creasty/defaults" "github.com/go-redis/redis/v8" + "github.com/icinga/icingadb/internal" "github.com/icinga/icingadb/pkg/com" "github.com/icinga/icingadb/pkg/common" "github.com/icinga/icingadb/pkg/contracts" @@ -32,6 +34,33 @@ type Options struct { HScanCount int `yaml:"hscan_count" default:"4096"` } +// UnmarshalYAML implements the yaml.Unmarshaler interface. +func (o *Options) UnmarshalYAML(unmarshal func(interface{}) error) error { + if err := defaults.Set(o); err != nil { + return errors.Wrapf(err, "can't set defaults %#v", o) + } + // Prevent recursion. + type self Options + if err := unmarshal((*self)(o)); err != nil { + return internal.CantUnmarshalYAML(err, o) + } + + if o.Timeout == 0 { + return errors.New("timeout cannot be 0. Configure a value greater than zero, or use -1 for no timeout") + } + if o.MaxHMGetConnections < 1 { + return errors.New("max_hmget_connections must be at least 1") + } + if o.HMGetCount < 1 { + return errors.New("hmget_count must be at least 1") + } + if o.HScanCount < 1 { + return errors.New("hscan_count must be at least 1") + } + + return nil +} + // NewClient returns a new icingaredis.Client wrapper for a pre-existing *redis.Client. func NewClient(client *redis.Client, logger *zap.SugaredLogger, options *Options) *Client { return &Client{Client: client, logger: logger, options: options}