diff --git a/cmd/icinga-kubernetes/main.go b/cmd/icinga-kubernetes/main.go index 56a13564..58a3a728 100644 --- a/cmd/icinga-kubernetes/main.go +++ b/cmd/icinga-kubernetes/main.go @@ -50,7 +50,7 @@ const expectedSchemaVersion = "0.2.0" func main() { runtime.ReallyCrash = true - var configLocation string + var glue daemon.ConfigFlagGlue var showVersion bool var clusterName string @@ -58,7 +58,12 @@ func main() { pflag.CommandLine.AddGoFlagSet(flag.CommandLine) pflag.BoolVar(&showVersion, "version", false, "print version and exit") - pflag.StringVar(&configLocation, "config", "./config.yml", "path to the config file") + pflag.StringVar( + &glue.Config, + "config", + "", + fmt.Sprintf("path to the config file (default: %s)", daemon.DefaultConfigPath), + ) pflag.StringVar(&clusterName, "cluster-name", "", "name of the current cluster") loadingRules := kclientcmd.NewDefaultClientConfigLoadingRules() @@ -99,9 +104,12 @@ func main() { log := klog.NewKlogr() var cfg daemon.Config - err = config.FromYAMLFile(configLocation, &cfg) - if err != nil { - klog.Fatal(errors.Wrap(err, "cannot create configuration")) + + if err = config.Load(&cfg, config.LoadOptions{ + Flags: glue, + EnvOptions: config.EnvOptions{Prefix: "ICINGA_FOR_KUBERNETES_"}, + }); err != nil { + klog.Fatal(errors.Wrap(err, "can't create configuration")) } dbLog := log.WithName("database") diff --git a/doc/03-Configuration.md b/doc/03-Configuration.md index 1134fd64..207b3eff 100644 --- a/doc/03-Configuration.md +++ b/doc/03-Configuration.md @@ -1,4 +1,4 @@ -# Configuration +# Configuration via YAML File The configuration is stored in `/etc/icinga-kubernetes/config.yml`. See [config.example.yml](../config.example.yml) for an example configuration. @@ -9,26 +9,91 @@ Connection configuration for the database to which Icinga for Kubernetes synchro This is also the database used in [Icinga for Kubernetes Web](https://icinga.com/docs/icinga-kubernetes-web) to view and work with the data. -| Option | Description | -|----------|--------------------------------------------------------------------| -| type | **Optional.** Only `mysql` is supported yet which is the default. | -| host | **Required.** Database host or absolute Unix socket path. | -| port | **Optional.** Database port. By default, the MySQL port. | -| database | **Required.** Database name. | -| user | **Required.** Database username. | -| password | **Optional.** Database password. | -| tls | **Optional.** Whether to use TLS. | -| cert | **Optional.** Path to TLS client certificate. | -| key | **Optional.** Path to TLS private key. | -| ca | **Optional.** Path to TLS CA certificate. | -| insecure | **Optional.** Whether not to verify the peer. | +| Option | Description | +|----------|-------------------------------------------------------------------| +| type | **Optional.** Only `mysql` is supported yet which is the default. | +| host | **Required.** Database host or absolute Unix socket path. | +| port | **Optional.** Database port. By default, the MySQL port. | +| database | **Required.** Database name. | +| user | **Required.** Database username. | +| password | **Optional.** Database password. | +| tls | **Optional.** Whether to use TLS. | +| cert | **Optional.** Path to TLS client certificate. | +| key | **Optional.** Path to TLS private key. | +| ca | **Optional.** Path to TLS CA certificate. | +| insecure | **Optional.** Whether not to verify the peer. | + +## Logging Configuration + +| Env | Description | +|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| level | **Optional.** Default logging level. Can be set to `fatal`, `error`, `warn`, `info` or `debug`. If not set, defaults to `info`. | +| output | **Optional.** Logging output. Can be set to `console` (stderr) or `systemd-journald`. If not set, logs to systemd-journald when running under systemd, otherwise stderr. | +| interval | **Optional.** Interval for periodic logging defined as duration string. Valid units are `ms`, `s`, `m`, `h`. Defaults to `20s`. | + +## Notifications Configuration + +Connection configuration for [Icinga Notifications](https://github.com/icinga/icinga-notifications) daemon. +If one of `url`, `username`, or `password` is set, **all** must be set. +Defined in the `notifications` section of the configuration file. + +| Option | Description | +|--------------------|-------------------------------------------------------------------------------------------------------| +| url | **Optional.** Icinga Notifications daemon URL. If not set, notifications are disabled | +| username | **Optional.** Username for authenticating the Icinga for Kubernetes source in Icinga Notifications. | +| password | **Optional.** Password for authenticating the Icinga for Kubernetes source in Icinga Notifications. | +| kubernetes_web_url | **Optional.** The base URL of Icinga for Kubernetes Web used in generated Icinga Notification events. | ## Prometheus Configuration Connection configuration for a Prometheus instance that collects metrics from your Kubernetes cluster, from which Icinga for Kubernetes [synchronizes predefined metrics](01-About.md#metric-sync) to display charts in the UI. -Defined in the `prometheus` section of the configuration file. +Defined in the `prometheus` section of the configuration file. If one of username or password is set, both must be set. + +| Option | Description | +|----------|--------------------------------------------------------------------------------------| +| url | **Optional.** Prometheus server URL. If not set, metric synchronization is disabled. | +| username | **Optional.** Prometheus username. | +| password | **Optional.** Prometheus password. | + +# Configuration via Environment Variables + +**All** environment variables are prefixed with `ICINGA_FOR_KUBERNETES_`. +The database type would therefore be `ICINGA_FOR_KUBERNETES_DATABASE_TYPE`. +The configurations set by environment variables override the ones set by YAML. + +## Database Configuration + +| Env | Description | +|-------------------|-------------------------------------------------------------------| +| DATABASE_TYPE | **Optional.** Only `mysql` is supported yet which is the default. | +| DATABASE_HOST | **Required.** Database host or absolute Unix socket path. | +| DATABASE_PORT | **Optional.** Database port. By default, the MySQL port. | +| DATABASE_DATABASE | **Required.** Database name. | +| DATABASE_USER | **Required.** Database username. | +| DATABASE_PASSWORD | **Optional.** Database password. | + +## Logging Configuration + +| Env | Description | +|------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| LOGGING_LEVEL | **Optional.** Default logging level. Can be set to `fatal`, `error`, `warn`, `info` or `debug`. If not set, defaults to `info`. | +| LOGGING_OUTPUT | **Optional.** Logging output. Can be set to `console` (stderr) or `systemd-journald`. If not set, logs to systemd-journald when running under systemd, otherwise stderr. | +| LOGGING_INTERVAL | **Optional.** Interval for periodic logging defined as duration string. Valid units are `ms`, `s`, `m`, `h`. Defaults to `20s`. | + +## Notifications Configuration + +| Env | Description | +|----------------------------------|-------------------------------------------------------------------------------------------------------| +| NOTIFICATIONS_URL | **Optional.** Icinga Notifications daemon URL. If not set, notifications are disabled | +| NOTIFICATIONS_USERNAME | **Optional.** Username for authenticating the Icinga for Kubernetes source in Icinga Notifications. | +| NOTIFICATIONS_PASSWORD | **Optional.** Password for authenticating the Icinga for Kubernetes source in Icinga Notifications. | +| NOTIFICATIONS_KUBERNETES_WEB_URL | **Optional.** The base URL of Icinga for Kubernetes Web used in generated Icinga Notification events. | + +## Prometheus Configuration -| Option | Description | -|--------|--------------------------------------------------------------------------------------| -| url | **Optional.** Prometheus server URL. If not set, metric synchronization is disabled. | +| Env | Description | +|---------------------|--------------------------------------------------------------------------------------| +| PROMETHEUS_URL | **Optional.** Prometheus server URL. If not set, metric synchronization is disabled. | +| PROMETHEUS_USERNAME | **Optional.** Prometheus username. | +| PROMETHEUS_PASSWORD | **Optional.** Prometheus password. | diff --git a/go.mod b/go.mod index ac7f5cbb..22b59757 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/go-logr/logr v1.4.2 github.com/go-sql-driver/mysql v1.8.1 github.com/google/uuid v1.6.0 - github.com/icinga/icinga-go-library v0.3.2-0.20241118194934-1a19cd696d37 + github.com/icinga/icinga-go-library v0.5.1-0.20250115065315-113387df7fbe github.com/jmoiron/sqlx v1.4.0 github.com/lib/pq v1.10.9 github.com/okzk/sdnotify v0.0.0-20240725214427-1c1fdd37c5ac @@ -17,7 +17,7 @@ require ( github.com/spf13/pflag v1.0.5 go.uber.org/zap v1.27.0 golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 - golang.org/x/sync v0.9.0 + golang.org/x/sync v0.10.0 k8s.io/api v0.31.1 k8s.io/apimachinery v0.31.1 k8s.io/client-go v0.31.1 @@ -27,7 +27,7 @@ require ( require ( filippo.io/edwards25519 v1.1.0 // indirect - github.com/caarlos0/env/v11 v11.2.2 // indirect + github.com/caarlos0/env/v11 v11.3.1 // indirect github.com/creasty/defaults v1.8.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.12.1 // indirect diff --git a/go.sum b/go.sum index fedc8b37..d33ccde2 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/caarlos0/env/v11 v11.2.2 h1:95fApNrUyueipoZN/EhA8mMxiNxrBwDa+oAZrMWl3Kg= -github.com/caarlos0/env/v11 v11.2.2/go.mod h1:JBfcdeQiBoI3Zh1QRAWfe+tpiNTmDtcCj/hHHHMx0vc= +github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA= +github.com/caarlos0/env/v11 v11.3.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -60,8 +60,8 @@ github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73 github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/icinga/icinga-go-library v0.3.2-0.20241118194934-1a19cd696d37 h1:b1xWtyFSPlCBTgP7sajx4fb+zecPh0LOXnXsJ7n3r9o= -github.com/icinga/icinga-go-library v0.3.2-0.20241118194934-1a19cd696d37/go.mod h1:zBVLixVxt+FIxOct/DDTBzbu02BlvPZ0Mhcq8t6ErxE= +github.com/icinga/icinga-go-library v0.5.1-0.20250115065315-113387df7fbe h1:oVsEcC7QGKGhiWapuKqC9kWLoIRoGOoicfqeum8ZMh8= +github.com/icinga/icinga-go-library v0.5.1-0.20250115065315-113387df7fbe/go.mod h1:0PTW/N+Xio77P0QnxxMQeqRrETsJ8cVoFs88V4nDA3M= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4= @@ -144,8 +144,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -179,8 +179,8 @@ golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbht golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/pkg/daemon/config.go b/pkg/daemon/config.go index 9fd47258..3174c942 100644 --- a/pkg/daemon/config.go +++ b/pkg/daemon/config.go @@ -7,12 +7,16 @@ import ( "github.com/icinga/icinga-kubernetes/pkg/notifications" ) +// DefaultConfigPath specifies the default location of Icinga for Kubernetes's config.yml +// if not set via command line flag. +const DefaultConfigPath = "./config.yml" + // Config defines Icinga Kubernetes config. type Config struct { - Database database.Config `yaml:"database"` - Logging logging.Config `yaml:"logging"` - Notifications notifications.Config `yaml:"notifications"` - Prometheus metrics.PrometheusConfig `yaml:"prometheus"` + Database database.Config `yaml:"database" envPrefix:"DATABASE_"` + Logging logging.Config `yaml:"logging" envPrefix:"LOGGING_"` + Notifications notifications.Config `yaml:"notifications" envPrefix:"NOTIFICATIONS_"` + Prometheus metrics.PrometheusConfig `yaml:"prometheus" envPrefix:"PROMETHEUS_"` } // Validate checks constraints in the supplied configuration and returns an error if they are violated. @@ -31,3 +35,26 @@ func (c *Config) Validate() error { return c.Notifications.Validate() } + +// ConfigFlagGlue provides a glue struct for the CLI config flag. +// +// ConfigFlagGlue implements the [github.com/icinga/icinga-go-library/config.Flags] interface. +type ConfigFlagGlue struct { + // Config is the path to the config file + Config string +} + +// GetConfigPath retrieves the path to the configuration file. +// It returns the path specified via the command line, or DefaultConfigPath if none is provided. +func (f ConfigFlagGlue) GetConfigPath() string { + if f.Config == "" { + return DefaultConfigPath + } + + return f.Config +} + +// IsExplicitConfigPath indicates whether the configuration file path was explicitly set. +func (f ConfigFlagGlue) IsExplicitConfigPath() bool { + return f.Config != "" +} diff --git a/pkg/metrics/config.go b/pkg/metrics/config.go index 933894c6..c9c0950d 100644 --- a/pkg/metrics/config.go +++ b/pkg/metrics/config.go @@ -6,9 +6,9 @@ import ( // PrometheusConfig defines Prometheus configuration. type PrometheusConfig struct { - Url string `yaml:"url"` - Username string `yaml:"username"` - Password string `yaml:"password"` + Url string `yaml:"url" env:"URL"` + Username string `yaml:"username" env:"USERNAME"` + Password string `yaml:"password" env:"PASSWORD"` } // Validate checks constraints in the supplied Prometheus configuration and returns an error if they are violated. diff --git a/pkg/notifications/config.go b/pkg/notifications/config.go index 301c0993..96eb75d4 100644 --- a/pkg/notifications/config.go +++ b/pkg/notifications/config.go @@ -8,10 +8,10 @@ import ( type Config struct { // If URL is the empty string, notifications are disabled. - Url string `yaml:"url"` - Username string `yaml:"username"` - Password string `yaml:"password"` - KubernetesWebUrl string `yaml:"kubernetes_web_url" default:"http://localhost/icingaweb2/kubernetes"` + Url string `yaml:"url" env:"URL"` + Username string `yaml:"username" env:"USERNAME"` + Password string `yaml:"password" env:"PASSWORD"` + KubernetesWebUrl string `yaml:"kubernetes_web_url" env:"KUBERNETES_WEB_URL" default:"http://localhost/icingaweb2/kubernetes"` } // Validate checks constraints in the supplied configuration and returns an error if they are violated.