Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load config from both env and yaml #162

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions cmd/icinga-kubernetes/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,20 @@ const expectedSchemaVersion = "0.2.0"
func main() {
runtime.ReallyCrash = true

var configLocation string
var glue daemon.ConfigFlagGlue
var showVersion bool
var clusterName string

klog.InitFlags(nil)
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()
Expand Down Expand Up @@ -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")
Expand Down
101 changes: 83 additions & 18 deletions doc/03-Configuration.md
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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. |
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
16 changes: 8 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down Expand Up @@ -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=
Expand Down Expand Up @@ -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=
Expand Down Expand Up @@ -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=
Expand Down
35 changes: 31 additions & 4 deletions pkg/daemon/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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 != ""
}
6 changes: 3 additions & 3 deletions pkg/metrics/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
8 changes: 4 additions & 4 deletions pkg/notifications/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@

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.
func (c *Config) Validate() error {
if c.Url != "" || c.Username != "" || c.Password != "" {
if c.Url == "" || c.Username == "" || c.Password == "" {
return errors.New("if one of 'url', 'username', or 'password' is set, all must be set")

Check failure on line 21 in pkg/notifications/config.go

View workflow job for this annotation

GitHub Actions / build-and-test

inlining call to errors.New
}

usernameValid, err := regexp.MatchString(`^source-\d+$`, c.Username)
Expand Down
Loading