root: config: implement config watching

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
This commit is contained in:
Marc 'risson' Schmitt 2023-04-29 00:54:52 +02:00
parent 2a15004232
commit 969ec188a7
No known key found for this signature in database
GPG key ID: 9C3FA22FABF1AA8D
3 changed files with 77 additions and 0 deletions

1
go.mod
View file

@ -42,6 +42,7 @@ require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/felixge/httpsnoop v1.0.1 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
github.com/go-http-utils/fresh v0.0.0-20161124030543-7231e26a4b27 // indirect
github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a // indirect

3
go.sum
View file

@ -66,6 +66,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/garyburd/redigo v1.6.4 h1:LFu2R3+ZOPgSMWMOL+saa/zXRjw0ID2G8FepO53BGlg=
github.com/garyburd/redigo v1.6.4/go.mod h1:rTb6epsqigu3kYKBnaF028A7Tf/Aw5s0cqA47doKKqw=
github.com/getsentry/sentry-go v0.20.0 h1:bwXW98iMRIWxn+4FgPW7vMrjmbym6HblXALmhjHmQaQ=
@ -486,6 +488,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View file

@ -8,8 +8,10 @@ import (
"path/filepath"
"reflect"
"strings"
"time"
env "github.com/Netflix/go-env"
"github.com/fsnotify/fsnotify"
log "github.com/sirupsen/logrus"
"gopkg.in/yaml.v2"
)
@ -53,6 +55,71 @@ func getConfigPaths() []string {
return computedConfigPaths
}
func WatchChanges(callback func()) (*fsnotify.Watcher, error) {
configPaths := getConfigPaths()
w, err := fsnotify.NewWatcher()
if err != nil {
return nil, err
}
// Start listening for events
go func() {
reload := false
for {
select {
// Read from errors
case err, ok := <-w.Errors:
if !ok {
// Channel was closed (i.e. Watcher.Close() was called)
return
}
log.WithError(err).Warning("failed to watch for file changes")
// Read from events
case ev, ok := <-w.Events:
if !ok {
// Channel was closed (i.e. Watcher.Close() was called)
return
}
// Ignores files we're not interested in
// We get the whole list again in case a file in a directory we're watching was created
// and that file is of interest
for _, f := range getConfigPaths() {
if f == ev.Name {
reload = true
log.Debugf("%s file change, setting configuration to be reloaded", ev.Name)
}
}
default:
if reload {
log.Infof("configuration files changed, reloading configuration")
Reload()
callback()
// Cooldown after configuration reloading
time.Sleep(14 * time.Second)
}
// Otherwise `select` fires all of the time
time.Sleep(1 * time.Second)
reload = false
}
}
}()
// Register the files to be watch
for _, p := range configPaths {
// Actually, watch the directory, not the files, as that's how fsnotify works
// We assume we're only getting valid files as getConfigPaths already handles all the necessary checks
err = w.Add(filepath.Dir(p))
log.Warningf("watching for changes for file %s in dir %s", p, filepath.Dir(p))
if err != nil {
return w, err
}
}
return w, nil
}
func Get() *Config {
if cfg == nil {
c := &Config{}
@ -62,6 +129,12 @@ func Get() *Config {
return cfg
}
func Reload() {
c := &Config{}
c.Setup(getConfigPaths()...)
cfg = c
}
func (c *Config) Setup(paths ...string) {
for _, path := range paths {
err := c.LoadConfig(path)