plugin/cache: add a new keepttl option (#5879)
adds a new option `keepttl` to the cache plugin Signed-off-by: Arthur Outhenin-Chalandre <arthur.outhenin-chalandre@proton.ch>
This commit is contained in:
parent
d3e4fc78c3
commit
bf7c2cf37b
6 changed files with 87 additions and 1 deletions
8
plugin/cache/README.md
vendored
8
plugin/cache/README.md
vendored
|
@ -39,6 +39,7 @@ cache [TTL] [ZONES...] {
|
|||
serve_stale [DURATION] [REFRESH_MODE]
|
||||
servfail DURATION
|
||||
disable success|denial [ZONES...]
|
||||
keepttl
|
||||
}
|
||||
~~~
|
||||
|
||||
|
@ -69,6 +70,11 @@ cache [TTL] [ZONES...] {
|
|||
greater than 5 minutes.
|
||||
* `disable` disable the success or denial cache for the listed **ZONES**. If no **ZONES** are given, the specified
|
||||
cache will be disabled for all zones.
|
||||
* `keepttl` do not age TTL when serving responses from cache. The entry will still be removed from cache
|
||||
when the TTL expires as normal, but until it expires responses will include the original TTL instead
|
||||
of the remaining TTL. This can be useful if CoreDNS is used as an authoritative server and you want
|
||||
to serve a consistent TTL to downstream clients. This is **NOT** recommended when CoreDNS is caching
|
||||
records it is not authoritative for because it could result in downstream clients using stale answers.
|
||||
|
||||
## Capacity and Eviction
|
||||
|
||||
|
@ -135,4 +141,4 @@ example.org {
|
|||
disable denial sub.example.org
|
||||
}
|
||||
}
|
||||
~~~
|
||||
~~~
|
||||
|
|
3
plugin/cache/cache.go
vendored
3
plugin/cache/cache.go
vendored
|
@ -48,6 +48,9 @@ type Cache struct {
|
|||
pexcept []string
|
||||
nexcept []string
|
||||
|
||||
// Keep ttl option
|
||||
keepttl bool
|
||||
|
||||
// Testing.
|
||||
now func() time.Time
|
||||
}
|
||||
|
|
38
plugin/cache/cache_test.go
vendored
38
plugin/cache/cache_test.go
vendored
|
@ -690,6 +690,44 @@ func TestCacheWildcardMetadata(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestCacheKeepTTL(t *testing.T) {
|
||||
defaultTtl := 60
|
||||
|
||||
c := New()
|
||||
c.Next = ttlBackend(defaultTtl)
|
||||
|
||||
req := new(dns.Msg)
|
||||
req.SetQuestion("cached.org.", dns.TypeA)
|
||||
ctx := context.TODO()
|
||||
|
||||
// Cache cached.org. with 60s TTL
|
||||
rec := dnstest.NewRecorder(&test.ResponseWriter{})
|
||||
c.keepttl = true
|
||||
c.ServeDNS(ctx, rec, req)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
futureSeconds int
|
||||
}{
|
||||
{"cached.org.", 0},
|
||||
{"cached.org.", 30},
|
||||
{"uncached.org.", 60},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
rec := dnstest.NewRecorder(&test.ResponseWriter{})
|
||||
c.now = func() time.Time { return time.Now().Add(time.Duration(tt.futureSeconds) * time.Second) }
|
||||
r := req.Copy()
|
||||
r.SetQuestion(tt.name, dns.TypeA)
|
||||
c.ServeDNS(ctx, rec, r)
|
||||
|
||||
recTtl := rec.Msg.Answer[0].Header().Ttl
|
||||
if defaultTtl != int(recTtl) {
|
||||
t.Errorf("Test %d: expecting TTL=%d, got TTL=%d", i, defaultTtl, recTtl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// wildcardMetadataBackend mocks a backend that reponds with a response for qname synthesized by wildcard
|
||||
// and sets the zone/wildcard metadata value
|
||||
func wildcardMetadataBackend(qname, wildcard string) plugin.Handler {
|
||||
|
|
5
plugin/cache/handler.go
vendored
5
plugin/cache/handler.go
vendored
|
@ -71,6 +71,11 @@ func (c *Cache) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
|
|||
})
|
||||
}
|
||||
|
||||
if c.keepttl {
|
||||
// If keepttl is enabled we fake the current time to the stored
|
||||
// one so that we always get the original TTL
|
||||
now = i.stored
|
||||
}
|
||||
resp := i.toMsg(r, now, do, ad)
|
||||
w.WriteMsg(resp)
|
||||
return dns.RcodeSuccess, nil
|
||||
|
|
5
plugin/cache/setup.go
vendored
5
plugin/cache/setup.go
vendored
|
@ -240,6 +240,11 @@ func cacheParse(c *caddy.Controller) (*Cache, error) {
|
|||
default:
|
||||
return nil, fmt.Errorf("cache type for disable must be %q or %q", Success, Denial)
|
||||
}
|
||||
case "keepttl":
|
||||
if len(args) != 0 {
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
ca.keepttl = true
|
||||
default:
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
|
|
29
plugin/cache/setup_test.go
vendored
29
plugin/cache/setup_test.go
vendored
|
@ -231,3 +231,32 @@ func TestDisable(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeepttl(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
shouldErr bool
|
||||
}{
|
||||
// positive
|
||||
{"keepttl", false},
|
||||
// negative
|
||||
{"keepttl arg1", true},
|
||||
}
|
||||
for i, test := range tests {
|
||||
c := caddy.NewTestController("dns", fmt.Sprintf("cache {\n%s\n}", test.input))
|
||||
ca, err := cacheParse(c)
|
||||
if test.shouldErr && err == nil {
|
||||
t.Errorf("Test %v: Expected error but found nil", i)
|
||||
continue
|
||||
} else if !test.shouldErr && err != nil {
|
||||
t.Errorf("Test %v: Expected no error but found error: %v", i, err)
|
||||
continue
|
||||
}
|
||||
if test.shouldErr {
|
||||
continue
|
||||
}
|
||||
if !ca.keepttl {
|
||||
t.Errorf("Test %v: Expected keepttl enabled but disabled", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue