Skip to content

Commit

Permalink
cmd/icingadb: if --config-from-env given, load config from env vars
Browse files Browse the repository at this point in the history
  • Loading branch information
Al2Klimov committed May 23, 2024
1 parent 1d6c63b commit f9338dc
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 41 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/icinga/icingadb
go 1.22

require (
github.com/caarlos0/env/v11 v11.0.1
github.com/creasty/defaults v1.7.0
github.com/go-sql-driver/mysql v1.8.1
github.com/goccy/go-yaml v1.11.3
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/caarlos0/env/v11 v11.0.1 h1:A8dDt9Ub9ybqRSUF3fQc/TA/gTam2bKT4Pit+cwrsPs=
github.com/caarlos0/env/v11 v11.0.1/go.mod h1:2RC3HQu8BQqtEK3V4iHPxj0jOdWdbPpWJ6pOueeU1xM=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/creasty/defaults v1.7.0 h1:eNdqZvc5B509z18lD8yc212CAqJNvfT1Jq6L8WowdBA=
Expand Down
8 changes: 7 additions & 1 deletion internal/command/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,13 @@ func New() *Command {
os.Exit(0)
}

cfg, err := config.FromYAMLFile(flags.Config)
var cfg *config.Config
if flags.ConfigFromEnv {
cfg, err = config.FromEnv()
} else {
cfg, err = config.FromYAMLFile(flags.Config)
}

if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(2)
Expand Down
40 changes: 31 additions & 9 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package config
import (
"crypto/tls"
"crypto/x509"
"github.com/caarlos0/env/v11"
"github.com/creasty/defaults"
"github.com/goccy/go-yaml"
"github.com/jessevdk/go-flags"
Expand All @@ -12,10 +13,10 @@ import (

// Config defines Icinga DB config.
type Config struct {
Database Database `yaml:"database"`
Redis Redis `yaml:"redis"`
Logging Logging `yaml:"logging"`
Retention Retention `yaml:"retention"`
Database Database `yaml:"database" envPrefix:"DATABASE_"`
Redis Redis `yaml:"redis" envPrefix:"REDIS_"`
Logging Logging `yaml:"logging" envPrefix:"LOGGING_"`
Retention Retention `yaml:"retention" envPrefix:"RETENTION_"`
}

// Validate checks constraints in the supplied configuration and returns an error if they are violated.
Expand All @@ -40,6 +41,8 @@ func (c *Config) Validate() error {
type Flags struct {
// Version decides whether to just print the version and exit.
Version bool `long:"version" description:"print version and exit"`
// ConfigFromEnv decides whether to load the config from environment variables.
ConfigFromEnv bool `long:"config-from-env" description:"load config from env vars"`
// Config is the path to the config file
Config string `short:"c" long:"config" description:"path to config file" required:"true" default:"/etc/icingadb/config.yml"`
}
Expand Down Expand Up @@ -70,6 +73,25 @@ func FromYAMLFile(name string) (*Config, error) {
return c, nil
}

// FromEnv returns a new Config value created from environment variables.
func FromEnv() (*Config, error) {
c := &Config{}

if err := defaults.Set(c); err != nil {
return nil, errors.Wrap(err, "can't set config defaults")
}

if err := env.ParseWithOptions(c, env.Options{Prefix: "ICINGADB_"}); err != nil {
return nil, errors.Wrap(err, "can't parse env vars")
}

if err := c.Validate(); err != nil {
return nil, errors.Wrap(err, "invalid configuration")
}

return c, nil
}

// ParseFlags parses CLI flags and
// returns a Flags value created from them.
func ParseFlags() (*Flags, error) {
Expand All @@ -85,11 +107,11 @@ func ParseFlags() (*Flags, error) {

// TLS provides TLS configuration options for Redis and Database.
type TLS struct {
Enable bool `yaml:"tls"`
Cert string `yaml:"cert"`
Key string `yaml:"key"`
Ca string `yaml:"ca"`
Insecure bool `yaml:"insecure"`
Enable bool `yaml:"tls" env:"TLS"`
Cert string `yaml:"cert" env:"CERT"`
Key string `yaml:"key" env:"KEY"`
Ca string `yaml:"ca" env:"CA"`
Insecure bool `yaml:"insecure" env:"INSECURE"`
}

// MakeConfig assembles a tls.Config from t and serverName.
Expand Down
14 changes: 7 additions & 7 deletions pkg/config/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ import (

// Database defines database client configuration.
type Database struct {
Type string `yaml:"type" default:"mysql"`
Host string `yaml:"host"`
Port int `yaml:"port"`
Database string `yaml:"database"`
User string `yaml:"user"`
Password string `yaml:"password"`
Type string `yaml:"type" env:"TYPE" default:"mysql"`
Host string `yaml:"host" env:"HOST"`
Port int `yaml:"port" env:"PORT"`
Database string `yaml:"database" env:"DATABASE"`
User string `yaml:"user" env:"USER"`
Password string `yaml:"password" env:"PASSWORD"`
TlsOptions TLS `yaml:",inline"`
Options icingadb.Options `yaml:"options"`
Options icingadb.Options `yaml:"options" envPrefix:"OPTIONS_"`
}

// Open prepares the DSN string and driver configuration,
Expand Down
10 changes: 5 additions & 5 deletions pkg/config/history_retention.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import (

// Retention defines configuration for history retention.
type Retention struct {
HistoryDays uint64 `yaml:"history-days"`
SlaDays uint64 `yaml:"sla-days"`
Interval time.Duration `yaml:"interval" default:"1h"`
Count uint64 `yaml:"count" default:"5000"`
Options history.RetentionOptions `yaml:"options"`
HistoryDays uint64 `yaml:"history-days" env:"HISTORY_DAYS"`
SlaDays uint64 `yaml:"sla-days" env:"SLA_DAYS"`
Interval time.Duration `yaml:"interval" env:"INTERVAL" default:"1h"`
Count uint64 `yaml:"count" env:"COUNT" default:"5000"`
Options history.RetentionOptions `yaml:"options" env:"OPTIONS"`
}

// Validate checks constraints in the supplied retention configuration and
Expand Down
8 changes: 4 additions & 4 deletions pkg/config/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ import (
// Logging defines Logger configuration.
type Logging struct {
// zapcore.Level at 0 is for info level.
Level zapcore.Level `yaml:"level" default:"0"`
Output string `yaml:"output"`
Level zapcore.Level `yaml:"level" env:"LEVEL" default:"0"`
Output string `yaml:"output" env:"OUTPUT"`
// Interval for periodic logging.
Interval time.Duration `yaml:"interval" default:"20s"`
Interval time.Duration `yaml:"interval" env:"INTERVAL" default:"20s"`

logging.Options `yaml:"options"`
logging.Options `yaml:"options" env:"OPTIONS"`
}

// Validate checks constraints in the supplied Logging configuration and returns an error if they are violated.
Expand Down
8 changes: 4 additions & 4 deletions pkg/config/redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ import (

// Redis defines Redis client configuration.
type Redis struct {
Host string `yaml:"host"`
Port int `yaml:"port" default:"6380"`
Password string `yaml:"password"`
Host string `yaml:"host" env:"HOST"`
Port int `yaml:"port" env:"PORT" default:"6380"`
Password string `yaml:"password" env:"PASSWORD"`
TlsOptions TLS `yaml:",inline"`
Options icingaredis.Options `yaml:"options"`
Options icingaredis.Options `yaml:"options" envPrefix:"OPTIONS_"`
}

type ctxDialerFunc = func(ctx context.Context, network, addr string) (net.Conn, error)
Expand Down
10 changes: 5 additions & 5 deletions pkg/icingadb/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,29 +37,29 @@ type DB struct {
// Options define user configurable database options.
type Options struct {
// Maximum number of open connections to the database.
MaxConnections int `yaml:"max_connections" default:"16"`
MaxConnections int `yaml:"max_connections" env:"MAX_CONNECTIONS" default:"16"`

// Maximum number of connections per table,
// regardless of what the connection is actually doing,
// e.g. INSERT, UPDATE, DELETE.
MaxConnectionsPerTable int `yaml:"max_connections_per_table" default:"8"`
MaxConnectionsPerTable int `yaml:"max_connections_per_table" env:"MAX_CONNECTIONS_PER_TABLE" default:"8"`

// MaxPlaceholdersPerStatement defines the maximum number of placeholders in an
// INSERT, UPDATE or DELETE statement. Theoretically, MySQL can handle up to 2^16-1 placeholders,
// but this increases the execution time of queries and thus reduces the number of queries
// that can be executed in parallel in a given time.
// The default is 2^13, which in our tests showed the best performance in terms of execution time and parallelism.
MaxPlaceholdersPerStatement int `yaml:"max_placeholders_per_statement" default:"8192"`
MaxPlaceholdersPerStatement int `yaml:"max_placeholders_per_statement" env:"MAX_PLACEHOLDERS_PER_STATEMENT" default:"8192"`

// MaxRowsPerTransaction defines the maximum number of rows per transaction.
// The default is 2^13, which in our tests showed the best performance in terms of execution time and parallelism.
MaxRowsPerTransaction int `yaml:"max_rows_per_transaction" default:"8192"`
MaxRowsPerTransaction int `yaml:"max_rows_per_transaction" env:"MAX_ROWS_PER_TRANSACTION" default:"8192"`

// WsrepSyncWait enforces Galera cluster nodes to perform strict cluster-wide causality checks
// before executing specific SQL queries determined by the number you provided.
// Please refer to the below link for a detailed description.
// https://icinga.com/docs/icinga-db/latest/doc/03-Configuration/#galera-cluster
WsrepSyncWait int `yaml:"wsrep_sync_wait" default:"7"`
WsrepSyncWait int `yaml:"wsrep_sync_wait" env:"WSREP_SYNC_WAIT" default:"7"`
}

// Validate checks constraints in the supplied database options and returns an error if they are violated.
Expand Down
12 changes: 6 additions & 6 deletions pkg/icingaredis/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ type Client struct {

// Options define user configurable Redis options.
type Options struct {
BlockTimeout time.Duration `yaml:"block_timeout" default:"1s"`
HMGetCount int `yaml:"hmget_count" default:"4096"`
HScanCount int `yaml:"hscan_count" default:"4096"`
MaxHMGetConnections int `yaml:"max_hmget_connections" default:"8"`
Timeout time.Duration `yaml:"timeout" default:"30s"`
XReadCount int `yaml:"xread_count" default:"4096"`
BlockTimeout time.Duration `yaml:"block_timeout" env:"BLOCK_TIMEOUT" default:"1s"`
HMGetCount int `yaml:"hmget_count" env:"HMGET_COUNT" default:"4096"`
HScanCount int `yaml:"hscan_count" env:"HSCAN_COUNT" default:"4096"`
MaxHMGetConnections int `yaml:"max_hmget_connections" env:"MAX_HMGET_CONNECTIONS" default:"8"`
Timeout time.Duration `yaml:"timeout" env:"TIMEOUT" default:"30s"`
XReadCount int `yaml:"xread_count" env:"XREAD_COUNT" default:"4096"`
}

// Validate checks constraints in the supplied Redis options and returns an error if they are violated.
Expand Down

0 comments on commit f9338dc

Please sign in to comment.