diff --git a/plugin/auto/walk.go b/plugin/auto/walk.go index ade9914a4..1aa1b1b2c 100644 --- a/plugin/auto/walk.go +++ b/plugin/auto/walk.go @@ -14,12 +14,20 @@ import ( func (a Auto) Walk() error { // TODO(miek): should add something so that we don't stomp on each other. + // Resolve symlinks in the directory path so filepath.Walk will traverse it. + // filepath.Walk uses os.Lstat on the root and won't enter a symlinked directory. + // This is needed when DIR itself is a symlink (e.g., Kubernetes ConfigMap mounts). + dir := a.directory + if resolved, err := filepath.EvalSymlinks(a.directory); err == nil { + dir = resolved + } + toDelete := make(map[string]bool) for _, n := range a.Names() { toDelete[n] = true } - filepath.Walk(a.directory, func(path string, info os.FileInfo, e error) error { + filepath.Walk(dir, func(path string, info os.FileInfo, e error) error { if e != nil { log.Warningf("error reading %v: %v", path, e) } diff --git a/plugin/auto/walk_test.go b/plugin/auto/walk_test.go index 551708579..7c62eab92 100644 --- a/plugin/auto/walk_test.go +++ b/plugin/auto/walk_test.go @@ -45,6 +45,41 @@ func TestWalk(t *testing.T) { } } +func TestWalkSymlinkedDirectory(t *testing.T) { + t.Parallel() + tempdir, err := createFiles(t) + if err != nil { + t.Fatal(err) + } + + // Create a symlink to the directory containing zone files, + // simulating a Kubernetes ConfigMap mount where the directory + // itself is a symlink. + symlinkDir := filepath.Join(t.TempDir(), "zones") + if err := os.Symlink(tempdir, symlinkDir); err != nil { + t.Fatal(err) + } + + ldr := loader{ + directory: symlinkDir, + re: regexp.MustCompile(`db\.(.*)`), + template: `${1}`, + } + + a := Auto{ + loader: ldr, + Zones: &Zones{}, + } + + a.Walk() + + for _, name := range []string{"example.com.", "example.org."} { + if _, ok := a.Z[name]; !ok { + t.Errorf("%s should have been added when directory is a symlink", name) + } + } +} + func TestWalkNonExistent(t *testing.T) { t.Parallel() nonExistingDir := "highly_unlikely_to_exist_dir" diff --git a/plugin/auto/watcher_test.go b/plugin/auto/watcher_test.go index eb524678a..1b55d4123 100644 --- a/plugin/auto/watcher_test.go +++ b/plugin/auto/watcher_test.go @@ -56,6 +56,13 @@ func TestSymlinks(t *testing.T) { if err != nil { t.Fatal(err) } + // Resolve tempdir to handle platforms where temp paths contain symlinks + // (e.g., macOS where /var -> /private/var). Walk resolves the directory + // via EvalSymlinks, so stored paths use the resolved prefix. + tempdir, err = filepath.EvalSymlinks(tempdir) + if err != nil { + t.Fatal(err) + } ldr := loader{ directory: tempdir,