plugin/secondary: fix a bunch of things and tests (#1406)

Fix the error handling. Log when we have an error during any of the
transfer state. And if there isn't an error transfer the zones.

Also fix the tests in test/ so we, at least, check the initial transfer.

Update the docs to show more about how errors are handled.

Ref #1400
This commit is contained in:
Miek Gieben 2018-01-23 10:35:10 +00:00 committed by GitHub
parent 7d371edb2d
commit 85457cf50d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 62 additions and 146 deletions

View file

@ -118,19 +118,6 @@ Restart:
retry := time.Second * time.Duration(z.Apex.SOA.Retry) retry := time.Second * time.Duration(z.Apex.SOA.Retry)
expire := time.Second * time.Duration(z.Apex.SOA.Expire) expire := time.Second * time.Duration(z.Apex.SOA.Expire)
if refresh < time.Hour {
refresh = time.Hour
}
if retry < time.Hour {
retry = time.Hour
}
if refresh > 24*time.Hour {
refresh = 24 * time.Hour
}
if retry > 12*time.Hour {
retry = 12 * time.Hour
}
refreshTicker := time.NewTicker(refresh) refreshTicker := time.NewTicker(refresh)
retryTicker := time.NewTicker(retry) retryTicker := time.NewTicker(retry)
expireTicker := time.NewTicker(expire) expireTicker := time.NewTicker(expire)
@ -151,7 +138,12 @@ Restart:
time.Sleep(jitter(2000)) // 2s randomize time.Sleep(jitter(2000)) // 2s randomize
ok, err := z.shouldTransfer() ok, err := z.shouldTransfer()
if err != nil && ok { if err != nil {
log.Printf("[WARNING] Failed retry check %s", err)
continue
}
if ok {
if err := z.TransferIn(); err != nil { if err := z.TransferIn(); err != nil {
// transfer failed, leave retryActive true // transfer failed, leave retryActive true
break break
@ -169,8 +161,13 @@ Restart:
time.Sleep(jitter(5000)) // 5s randomize time.Sleep(jitter(5000)) // 5s randomize
ok, err := z.shouldTransfer() ok, err := z.shouldTransfer()
retryActive = err != nil if err != nil {
if err != nil && ok { log.Printf("[WARNING] Failed refresh check %s", err)
retryActive = true
continue
}
if ok {
if err := z.TransferIn(); err != nil { if err := z.TransferIn(); err != nil {
// transfer failed // transfer failed
retryActive = true retryActive = true

View file

@ -35,6 +35,10 @@ secondary [zones...] {
normal authoritative serving you don't need *or* want to use this. **ADDRESS** can be an IP normal authoritative serving you don't need *or* want to use this. **ADDRESS** can be an IP
address, and IP:port or a string pointing to a file that is structured as /etc/resolv.conf. address, and IP:port or a string pointing to a file that is structured as /etc/resolv.conf.
When a zone is due to be refreshed (Refresh timer fires) a random jitter of 5 seconds is
applied, before fetching. In the case of retry this will be 2 seconds. If there are any errors
during the transfer the transfer fails; this will be logged.
## Examples ## Examples
Transfer `example.org` from 10.0.1.1, and if that fails try 10.1.2.1. Transfer `example.org` from 10.0.1.1, and if that fails try 10.1.2.1.

View file

@ -1,126 +0,0 @@
// +build net
package test
import (
"testing"
"github.com/miekg/dns"
)
func TestSecondaryZoneTransfer(t *testing.T) {
/*
Test will only work when there is a CoreDNS running on part 32054
with example.com and willing to transfer
coredns -conf Corefile -dns.port 32054
Corefile:
example.com {
file example.com {
transfer to 127.0.0.1:32053
}
}
example.com:
example.com. 3600 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2017042730 7200 3600 1209600 3600
example.com. 65118 IN NS a.iana-servers.net.
example.com. 65118 IN NS b.iana-servers.net.
cname.example.com. 434334 IN CNAME a.miek.nl.
*/
corefile := `example.com:32053 {
secondary {
transfer from 127.0.0.1:32054
}
}
`
sec, err := CoreDNSServer(corefile)
if err != nil {
t.Fatalf("Could not get CoreDNS serving instance: %s", err)
}
defer sec.Stop()
m := new(dns.Msg)
m.SetQuestion("cname.example.com.", dns.TypeCNAME)
r, err := dns.Exchange(m, "127.0.0.1:32053")
if err != nil {
t.Fatalf("Expected to receive reply, but didn't: %s", err)
}
if len(r.Answer) == 0 {
t.Fatalf("Expected answer section")
}
if r.Answer[0].(*dns.CNAME).Target != "a.miek.nl." {
t.Fatalf("Expected target of %s, got %s", "a.miek.nl.", r.Answer[0].(*dns.CNAME).Target)
}
m = new(dns.Msg)
m.SetQuestion("example.com.", dns.TypeSOA)
r, err = dns.Exchange(m, "127.0.0.1:32053")
if err != nil {
t.Fatalf("Expected to receive reply, but didn't: %s", err)
}
if len(r.Answer) == 0 {
t.Fatalf("Expected answer section")
}
if r.Answer[0].(*dns.SOA).Serial != 2017042730 {
t.Fatalf("Expected serial of %d, got %d", 2017042730, r.Answer[0].(*dns.SOA).Serial)
}
}
func TestSecondaryZoneTransferUpstream(t *testing.T) {
/*
Test will only work when there is a CoreDNS running on part 32054
with example.com and willing to transfer
coredns -conf Corefile -dns.port 32054
Corefile:
example.com {
file example.com {
transfer to 127.0.0.1:32053
}
}
example.com:
example.com. 3600 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2017042730 7200 3600 1209600 3600
example.com. 65118 IN NS a.iana-servers.net.
example.com. 65118 IN NS b.iana-servers.net.
cname.example.com. 434334 IN CNAME a.miek.nl.
*/
corefile := `example.com:32053 {
secondary {
transfer from 127.0.0.1:32054
upstream 8.8.8.8
}
}
`
sec, err := CoreDNSServer(corefile)
if err != nil {
t.Fatalf("Could not get CoreDNS serving instance: %s", err)
}
defer sec.Stop()
m := new(dns.Msg)
m.SetQuestion("cname.example.com.", dns.TypeA)
r, err := dns.Exchange(m, "127.0.0.1:32053")
if err != nil {
t.Fatalf("Expected to receive reply, but didn't: %s", err)
}
if len(r.Answer) != 2 {
t.Fatalf("Expected answer section, with 2 records, got %d", len(r.Answer))
}
if r.Answer[0].(*dns.CNAME).Target != "a.miek.nl." {
t.Fatalf("Expected target of %s, got %s", "a.miek.nl.", r.Answer[0].(*dns.CNAME).Target)
}
if r.Answer[1].Header().Name != "a.miek.nl." {
t.Fatalf("Expected name of %s, got %s", "a.miek.nl.", r.Answer[1].Header().Name)
}
}

View file

@ -1,8 +1,6 @@
package test package test
import ( import (
"io/ioutil"
"log"
"testing" "testing"
"github.com/coredns/coredns/plugin/proxy" "github.com/coredns/coredns/plugin/proxy"
@ -27,8 +25,6 @@ func TestEmptySecondaryZone(t *testing.T) {
} }
defer i.Stop() defer i.Stop()
log.SetOutput(ioutil.Discard)
p := proxy.NewLookup([]string{udp}) p := proxy.NewLookup([]string{udp})
state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)} state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)}
@ -40,3 +36,48 @@ func TestEmptySecondaryZone(t *testing.T) {
t.Fatalf("Expected reply to be a SERVFAIL, got %d", resp.Rcode) t.Fatalf("Expected reply to be a SERVFAIL, got %d", resp.Rcode)
} }
} }
func TestSecondaryZoneTransfer(t *testing.T) {
name, rm, err := test.TempFile(".", exampleOrg)
if err != nil {
t.Fatalf("failed to create zone: %s", err)
}
defer rm()
corefile := `example.org:0 {
file ` + name + ` {
transfer to *
}
}
`
i, _, tcp, err := CoreDNSServerAndPorts(corefile)
if err != nil {
t.Fatalf("Could not get CoreDNS serving instance: %s", err)
}
defer i.Stop()
corefile = `example.org:0 {
secondary {
transfer from ` + tcp + `
}
}
`
i1, udp, _, err := CoreDNSServerAndPorts(corefile)
if err != nil {
t.Fatalf("Could not get CoreDNS serving instance: %s", err)
}
defer i1.Stop()
m := new(dns.Msg)
m.SetQuestion("example.org.", dns.TypeSOA)
r, err := dns.Exchange(m, udp)
if err != nil {
t.Fatalf("Expected to receive reply, but didn't: %s", err)
}
if len(r.Answer) == 0 {
t.Fatalf("Expected answer section")
}
}