plugin/{file,auto}: drop fsnotify (#1090)

* plugin/{file,auto}: drop fsnotify

Reload every minute. This is more deterministic then fsnotify. Also
other thing cropped up: sharing zone files between zone; there is only
1 fsnotify event and we need to fan out the reload to all zone files.
This is a large rewrite (which could still be done), for now, poll the
zone file on disk.

Give serial no change a special error type so we can check for this.
Improve the logging for reloading:

2017/09/19 07:34:39 [INFO] Successfully reloaded zone "miek.nl." in "db.miek.nl" with serial 128263060
2017/09/19 07:34:45 [INFO] Successfully reloaded zone "miek.nl." in "db.miek.nl" with serial 128263059
2017/09/19 07:34:51 [INFO] Successfully reloaded zone "miek.nl." in "db.miek.nl" with serial 128263060

Fixes #1013

* typo
This commit is contained in:
Miek Gieben
2017-09-20 17:28:23 +01:00
committed by GitHub
parent cd5879f866
commit 36c7aa6437
6 changed files with 54 additions and 49 deletions

View File

@@ -3,56 +3,52 @@ package file
import (
"log"
"os"
"path"
"github.com/fsnotify/fsnotify"
"time"
)
// TickTime is the default time we use to reload zone. Exported to be tweaked in tests.
var TickTime = 1 * time.Minute
// Reload reloads a zone when it is changed on disk. If z.NoRoload is true, no reloading will be done.
func (z *Zone) Reload() error {
if z.NoReload {
return nil
}
watcher, err := fsnotify.NewWatcher()
if err != nil {
return err
}
err = watcher.Add(path.Dir(z.file))
if err != nil {
return err
}
tick := time.NewTicker(TickTime)
go func() {
// TODO(miek): needs to be killed on reload.
for {
select {
case event := <-watcher.Events:
if path.Clean(event.Name) == z.file {
reader, err := os.Open(z.file)
if err != nil {
log.Printf("[ERROR] Failed to open `%s' for `%s': %v", z.file, z.origin, err)
continue
}
serial := z.SOASerialIfDefined()
zone, err := Parse(reader, z.origin, z.file, serial)
if err != nil {
log.Printf("[WARNING] Parsing zone `%s': %v", z.origin, err)
continue
}
// copy elements we need
z.reloadMu.Lock()
z.Apex = zone.Apex
z.Tree = zone.Tree
z.reloadMu.Unlock()
log.Printf("[INFO] Successfully reloaded zone `%s'", z.origin)
z.Notify()
case <-tick.C:
reader, err := os.Open(z.file)
if err != nil {
log.Printf("[ERROR] Failed to open zone %q in %q: %v", z.origin, z.file, err)
continue
}
serial := z.SOASerialIfDefined()
zone, err := Parse(reader, z.origin, z.file, serial)
if err != nil {
if _, ok := err.(*serialErr); !ok {
log.Printf("[ERROR] Parsing zone %q: %v", z.origin, err)
}
continue
}
// copy elements we need
z.reloadMu.Lock()
z.Apex = zone.Apex
z.Tree = zone.Tree
z.reloadMu.Unlock()
log.Printf("[INFO] Successfully reloaded zone %q in %q with serial %d", z.origin, z.file, z.Apex.SOA.Serial)
z.Notify()
case <-z.ReloadShutdown:
watcher.Close()
tick.Stop()
return
}
}