improve config file watcher to support k8s configmap reloads
The config file watcher assumed a simple configuration where the existing configuration file is overwritten by a text editor. In practice this does not detect some more complex configuration change scenarios such as : * The configuration file is behind a symlink and the symlink is updated * The configuration file is behind a double symlink (k8s configmap update) * The configuration file is not updated but removed the re-created In order to fix these cases : * Watch the configuration file parent directory instead of the file itself, this lets us grab events event if the file was removed and a new file is used. * In addition to read/write event matching, watch for any change in the configuration file path. This handles the symlink case where the file itself hasn't changed but its location did v2: - apply gofmt
This commit is contained in:
parent
05e835e48c
commit
f5dc53e0f2
|
@ -14,7 +14,8 @@ const (
|
|||
|
||||
// ConfWatcher is a configuration file watcher.
|
||||
type ConfWatcher struct {
|
||||
inner *fsnotify.Watcher
|
||||
inner *fsnotify.Watcher
|
||||
watchedPath string
|
||||
|
||||
// out
|
||||
signal chan struct{}
|
||||
|
@ -30,17 +31,19 @@ func New(confPath string) (*ConfWatcher, error) {
|
|||
|
||||
// use absolute path to support Darwin
|
||||
absolutePath, _ := filepath.Abs(confPath)
|
||||
parentPath := filepath.Dir(absolutePath)
|
||||
|
||||
err = inner.Add(absolutePath)
|
||||
err = inner.Add(parentPath)
|
||||
if err != nil {
|
||||
inner.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
w := &ConfWatcher{
|
||||
inner: inner,
|
||||
signal: make(chan struct{}),
|
||||
done: make(chan struct{}),
|
||||
inner: inner,
|
||||
watchedPath: absolutePath,
|
||||
signal: make(chan struct{}),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
|
||||
go w.run()
|
||||
|
@ -61,6 +64,7 @@ func (w *ConfWatcher) run() {
|
|||
defer close(w.done)
|
||||
|
||||
var lastCalled time.Time
|
||||
previousWatchedPath, _ := filepath.EvalSymlinks(w.watchedPath)
|
||||
|
||||
outer:
|
||||
for {
|
||||
|
@ -70,10 +74,19 @@ outer:
|
|||
continue
|
||||
}
|
||||
|
||||
if (event.Op&fsnotify.Write) == fsnotify.Write ||
|
||||
(event.Op&fsnotify.Create) == fsnotify.Create {
|
||||
currentWatchedPath, _ := filepath.EvalSymlinks(w.watchedPath)
|
||||
eventPath, _ := filepath.Abs(event.Name)
|
||||
|
||||
if currentWatchedPath == "" {
|
||||
// Watched file was removed wait for write event to trigger reload
|
||||
previousWatchedPath = ""
|
||||
} else if currentWatchedPath != previousWatchedPath ||
|
||||
(eventPath == currentWatchedPath &&
|
||||
((event.Op&fsnotify.Write) == fsnotify.Write ||
|
||||
(event.Op&fsnotify.Create) == fsnotify.Create)) {
|
||||
// wait some additional time to allow the writer to complete its job
|
||||
time.Sleep(additionalWait)
|
||||
previousWatchedPath = currentWatchedPath
|
||||
|
||||
lastCalled = time.Now()
|
||||
w.signal <- struct{}{}
|
||||
|
|
Loading…
Reference in New Issue