inspect symlinks to auto-reload k8s secrets

This commit is contained in:
Julien Laffaye 2020-09-11 10:56:32 -04:00 committed by Matthew Silverman
parent 87aa96b468
commit d280a344c4
2 changed files with 94 additions and 4 deletions

View file

@ -18,7 +18,9 @@ package watch
import ( import (
"log" "log"
"os"
"path" "path"
"path/filepath"
"strings" "strings"
"github.com/fsnotify/fsnotify" "github.com/fsnotify/fsnotify"
@ -60,15 +62,31 @@ func (f *OSFileWatcher) watch() error {
} }
f.watcher = watcher f.watcher = watcher
realFile, err := filepath.EvalSymlinks(f.file)
if err != nil {
return err
}
dir, file := path.Split(f.file) dir, file := path.Split(f.file)
go func(file string) { go func(file string) {
for { for {
select { select {
case event := <-watcher.Events: case event := <-watcher.Events:
if (event.Op&fsnotify.Write == fsnotify.Write || if event.Op&fsnotify.Create == fsnotify.Create ||
event.Op&fsnotify.Create == fsnotify.Create) && event.Op&fsnotify.Write == fsnotify.Write {
strings.HasSuffix(event.Name, file) { if finfo, err := os.Lstat(event.Name); err != nil {
log.Printf("can not lstat file: %v\n", err)
} else if finfo.Mode()&os.ModeSymlink != 0 {
if currentRealFile, err := filepath.EvalSymlinks(f.file); err == nil &&
currentRealFile != realFile {
f.onEvent() f.onEvent()
realFile = currentRealFile
}
continue
}
if strings.HasSuffix(event.Name, file) {
f.onEvent()
}
} }
case err := <-watcher.Errors: case err := <-watcher.Errors:
if err != nil { if err != nil {

View file

@ -19,6 +19,8 @@ package watch
import ( import (
"io/ioutil" "io/ioutil"
"os" "os"
"path"
"path/filepath"
"testing" "testing"
"time" "time"
@ -67,3 +69,73 @@ func TestFileWatcher(t *testing.T) {
t.Fatalf("expected an event shortly after writing a file") t.Fatalf("expected an event shortly after writing a file")
} }
} }
func TestFileWatcherWithNestedSymlink(t *testing.T) {
target1, err := ioutil.TempFile("", "t1")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
defer target1.Close()
defer os.Remove(target1.Name())
dir := path.Dir(target1.Name())
innerLink := path.Join(dir, "innerLink")
if err = os.Symlink(target1.Name(), innerLink); err != nil {
t.Fatalf("unexpected error: %v", err)
}
defer os.Remove(innerLink)
mainLink := path.Join(dir, "mainLink")
if err = os.Symlink(innerLink, mainLink); err != nil {
t.Fatalf("unexpected error: %v", err)
}
defer os.Remove(mainLink)
targetName, err := filepath.EvalSymlinks(mainLink)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if targetName != target1.Name() {
t.Fatalf("expected symlink to point to %v, not %v", target1.Name(), targetName)
}
count := 0
events := make(chan bool, 10)
fw, err := NewFileWatcher(mainLink, func() {
count++
if count != 1 {
t.Fatalf("expected 1 but returned %v", count)
}
if targetName, err = filepath.EvalSymlinks(mainLink); err != nil {
t.Fatalf("unexpected error: %v", err)
}
events <- true
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
defer fw.Close()
target2, err := ioutil.TempFile("", "t2")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
defer target2.Close()
defer os.Remove(target2.Name())
if err = os.Remove(innerLink); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if err = os.Symlink(target2.Name(), innerLink); err != nil {
t.Fatalf("unexpected error: %v", err)
}
timeoutChan := prepareTimeout()
select {
case <-events:
case <-timeoutChan:
t.Fatalf("expected an event shortly after creating a file and relinking")
}
if targetName != target2.Name() {
t.Fatalf("expected symlink to point to %v, not %v", target2.Name(), targetName)
}
}