mirror of
https://github.com/coredns/coredns.git
synced 2025-11-24 12:44:05 -05:00
middleware/auto: add (#333)
Add auto-load middleware that automatically picks up zones. Every X seconds it will scan for new zones. Add tests and documentation. Make 'make test' use -race.
This commit is contained in:
@@ -22,8 +22,8 @@ type (
|
||||
|
||||
// Zones maps zone names to a *Zone.
|
||||
Zones struct {
|
||||
Z map[string]*Zone
|
||||
Names []string
|
||||
Z map[string]*Zone // A map mapping zone (origin) to the Zone's data
|
||||
Names []string // All the keys from the map Z as a string slice.
|
||||
}
|
||||
)
|
||||
|
||||
@@ -35,6 +35,7 @@ func (f File) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i
|
||||
return dns.RcodeServerFailure, errors.New("can only deal with ClassINET")
|
||||
}
|
||||
qname := state.Name()
|
||||
// TODO(miek): match the qname better in the map
|
||||
zone := middleware.Zones(f.Zones.Names).Matches(qname)
|
||||
if zone == "" {
|
||||
if f.Next != nil {
|
||||
@@ -49,6 +50,8 @@ func (f File) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i
|
||||
if z == nil {
|
||||
return dns.RcodeServerFailure, nil
|
||||
}
|
||||
|
||||
// This is only for when we are a secondary zones.
|
||||
if r.Opcode == dns.OpcodeNotify {
|
||||
if z.isNotify(state) {
|
||||
m := new(dns.Msg)
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/miekg/coredns/middleware/test"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
@@ -28,7 +29,7 @@ func TestZoneReload(t *testing.T) {
|
||||
t.Fatalf("failed to parse zone: %s", err)
|
||||
}
|
||||
|
||||
z.Reload(nil)
|
||||
z.Reload()
|
||||
|
||||
if _, _, _, res := z.Lookup("miek.nl.", dns.TypeSOA, false); res != Success {
|
||||
t.Fatalf("failed to lookup, got %d", res)
|
||||
|
||||
@@ -33,7 +33,7 @@ func setup(c *caddy.Controller) error {
|
||||
if len(z.TransferTo) > 0 {
|
||||
z.Notify()
|
||||
}
|
||||
z.Reload(nil)
|
||||
z.Reload()
|
||||
})
|
||||
return nil
|
||||
})
|
||||
@@ -99,7 +99,7 @@ func fileParse(c *caddy.Controller) (Zones, error) {
|
||||
case "no_reload":
|
||||
noReload = true
|
||||
}
|
||||
// discard from, here, maybe check and show log when we do?
|
||||
|
||||
for _, origin := range origins {
|
||||
if t != nil {
|
||||
z[origin].TransferTo = append(z[origin].TransferTo, t...)
|
||||
@@ -113,8 +113,6 @@ func fileParse(c *caddy.Controller) (Zones, error) {
|
||||
}
|
||||
|
||||
// TransferParse parses transfer statements: 'transfer to [address...]'.
|
||||
// Exported so secondary can use this as well. For the `file` middleware transfer from does
|
||||
// not make sense; make this an error.
|
||||
func TransferParse(c *caddy.Controller, secondary bool) (tos, froms []string, err error) {
|
||||
what := c.Val()
|
||||
if !c.NextArg() {
|
||||
|
||||
@@ -27,9 +27,9 @@ type Zone struct {
|
||||
TransferFrom []string
|
||||
Expired *bool
|
||||
|
||||
NoReload bool
|
||||
reloadMu sync.RWMutex
|
||||
// TODO: shutdown watcher channel
|
||||
NoReload bool
|
||||
reloadMu sync.RWMutex
|
||||
ReloadShutdown chan bool
|
||||
}
|
||||
|
||||
// Apex contains the apex records of a zone: SOA, NS and their potential signatures.
|
||||
@@ -42,7 +42,13 @@ type Apex struct {
|
||||
|
||||
// NewZone returns a new zone.
|
||||
func NewZone(name, file string) *Zone {
|
||||
z := &Zone{origin: dns.Fqdn(name), file: path.Clean(file), Tree: &tree.Tree{}, Expired: new(bool)}
|
||||
z := &Zone{
|
||||
origin: dns.Fqdn(name),
|
||||
file: path.Clean(file),
|
||||
Tree: &tree.Tree{},
|
||||
Expired: new(bool),
|
||||
ReloadShutdown: make(chan bool),
|
||||
}
|
||||
*z.Expired = false
|
||||
return z
|
||||
}
|
||||
@@ -138,7 +144,7 @@ func (z *Zone) All() []dns.RR {
|
||||
}
|
||||
|
||||
// Reload reloads a zone when it is changed on disk. If z.NoRoload is true, no reloading will be done.
|
||||
func (z *Zone) Reload(shutdown chan bool) error {
|
||||
func (z *Zone) Reload() error {
|
||||
if z.NoReload {
|
||||
return nil
|
||||
}
|
||||
@@ -156,7 +162,7 @@ func (z *Zone) Reload(shutdown chan bool) error {
|
||||
for {
|
||||
select {
|
||||
case event := <-watcher.Events:
|
||||
if path.Clean(event.Name) == z.file {
|
||||
if event.Op == fsnotify.Write && 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)
|
||||
@@ -176,7 +182,7 @@ func (z *Zone) Reload(shutdown chan bool) error {
|
||||
log.Printf("[INFO] Successfully reloaded zone `%s'", z.origin)
|
||||
z.Notify()
|
||||
}
|
||||
case <-shutdown:
|
||||
case <-z.ReloadShutdown:
|
||||
watcher.Close()
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user