diff --git a/config/config_source.go b/config/config_source.go index d68bc7ad8..8c6c88418 100644 --- a/config/config_source.go +++ b/config/config_source.go @@ -16,6 +16,7 @@ import ( "github.com/pomerium/pomerium/internal/log" "github.com/pomerium/pomerium/internal/telemetry/metrics" "github.com/pomerium/pomerium/pkg/netutil" + "github.com/pomerium/pomerium/pkg/slices" ) // A ChangeListener is called when configuration changes. @@ -132,7 +133,9 @@ func NewFileOrEnvironmentSource( watcher: fileutil.NewWatcher(), config: cfg, } - src.watcher.Watch(ctx, []string{configFile}) + if configFile != "" { + src.watcher.Watch(ctx, []string{configFile}) + } ch := src.watcher.Bind() go func() { for range ch { @@ -227,6 +230,8 @@ func (src *FileWatcherSource) onConfigChange(ctx context.Context, cfg *Config) { // store the config and trigger an update src.cfg = cfg.Clone() + src.hash = getAllConfigFilePathsHash(src.cfg) + log.Info(ctx).Uint64("hash", src.hash).Msg("config/filewatchersource: underlying config change, triggering update") src.Trigger(ctx, src.cfg) } @@ -234,9 +239,23 @@ func (src *FileWatcherSource) onFileChange(ctx context.Context) { src.mu.Lock() defer src.mu.Unlock() + hash := getAllConfigFilePathsHash(src.cfg) + + if hash == src.hash { + log.Info(ctx).Uint64("hash", src.hash).Msg("config/filewatchersource: no change detected") + } else { + // if the hash changed, trigger an update + // the actual config will be identical + src.hash = hash + log.Info(ctx).Uint64("hash", src.hash).Msg("config/filewatchersource: change detected, triggering update") + src.Trigger(ctx, src.cfg) + } +} + +func getAllConfigFilePathsHash(cfg *Config) uint64 { // read all the config files and build a hash from their contents h := xxhash.New() - for _, f := range getAllConfigFilePaths(src.cfg) { + for _, f := range getAllConfigFilePaths(cfg) { _, _ = h.Write([]byte{0}) f, err := os.Open(f) if err == nil { @@ -244,17 +263,7 @@ func (src *FileWatcherSource) onFileChange(ctx context.Context) { _ = f.Close() } } - hash := h.Sum64() - - if hash == src.hash { - log.Info(ctx).Msg("config/filewatchersource: no change detected") - } else { - // if the hash changed, trigger an update - // the actual config will be identical - log.Info(ctx).Msg("config/filewatchersource: change detected") - src.hash = hash - src.Trigger(ctx, src.cfg) - } + return h.Sum64() } func getAllConfigFilePaths(cfg *Config) []string { @@ -292,5 +301,9 @@ func getAllConfigFilePaths(cfg *Config) []string { ) } + fs = slices.Filter(fs, func(s string) bool { + return s != "" + }) + return fs } diff --git a/internal/fileutil/watcher.go b/internal/fileutil/watcher.go index bf55a2fb9..568ce125e 100644 --- a/internal/fileutil/watcher.go +++ b/internal/fileutil/watcher.go @@ -54,29 +54,37 @@ func (watcher *Watcher) Watch(ctx context.Context, filePaths []string) { } for _, filePath := range add { + watcher.watching[filePath] = struct{}{} + if watcher.eventWatcher != nil { - if err := watcher.eventWatcher.Add(filePath); err != nil { - log.Error(ctx).Msg("fileutil/watcher: failed to add file to event-based file watcher") + err := watcher.eventWatcher.Add(filePath) + if err != nil { + log.Error(ctx).Err(err).Str("file", filePath).Msg("fileutil/watcher: failed to add file to polling-based file watcher") } } if watcher.pollingWatcher != nil { - if err := watcher.pollingWatcher.Add(filePath); err != nil { - log.Error(ctx).Msg("fileutil/watcher: failed to add file to polling-based file watcher") + err := watcher.pollingWatcher.Add(filePath) + if err != nil { + log.Error(ctx).Err(err).Str("file", filePath).Msg("fileutil/watcher: failed to add file to polling-based file watcher") } } } for _, filePath := range remove { + delete(watcher.watching, filePath) + if watcher.eventWatcher != nil { - if err := watcher.eventWatcher.Remove(filePath); err != nil { - log.Error(ctx).Msg("fileutil/watcher: failed to remove file from event-based file watcher") + err := watcher.eventWatcher.Remove(filePath) + if err != nil { + log.Error(ctx).Err(err).Str("file", filePath).Msg("fileutil/watcher: failed to remove file from event-based file watcher") } } if watcher.pollingWatcher != nil { - if err := watcher.pollingWatcher.Remove(filePath); err != nil { - log.Error(ctx).Msg("fileutil/watcher: failed to remove file from polling-based file watcher") + err := watcher.pollingWatcher.Remove(filePath) + if err != nil { + log.Error(ctx).Err(err).Str("file", filePath).Msg("fileutil/watcher: failed to remove file from polling-based file watcher") } } } @@ -91,7 +99,7 @@ func (watcher *Watcher) initLocked(ctx context.Context) { var err error watcher.eventWatcher, err = filenotify.NewEventWatcher() if err != nil { - log.Error(ctx).Msg("fileutil/watcher: failed to create event-based file watcher") + log.Error(ctx).Err(err).Msg("fileutil/watcher: failed to create event-based file watcher") } } if watcher.pollingWatcher == nil {