inspect symlinks to auto-reload k8s secrets
This commit is contained in:
parent
87aa96b468
commit
d280a344c4
2 changed files with 94 additions and 4 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue