return an error for multiple use of some plugins (#1559)

* plugins: Return error for multiple use of some

Return plugin.ErrOnce when a plugin that doesn't support it, is called
mutliple times.

This now adds it for: cache, dnssec, errors, forward, hosts, nsid.
And changes it slightly in kubernetes, pprof, reload, root.

* more tests
This commit is contained in:
Miek Gieben 2018-02-28 18:16:05 -08:00 committed by GitHub
parent 5faa9e7bc1
commit f697b33283
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 150 additions and 95 deletions

View file

@ -10,6 +10,8 @@ With *cache* enabled, all records except zone transfers and metadata records wil
3600s. Caching is mostly useful in a scenario when fetching data from the backend (upstream,
database, etc.) is expensive.
This plugin can only be used once per Server Block.
## Syntax
~~~ txt

10
plugin/cache/setup.go vendored
View file

@ -61,7 +61,13 @@ func setup(c *caddy.Controller) error {
func cacheParse(c *caddy.Controller) (*Cache, error) {
ca := New()
j := 0
for c.Next() {
if j > 0 {
return nil, plugin.ErrOnce
}
j++
// cache [ttl] [zones..]
origins := make([]string, len(c.ServerBlockKeys))
copy(origins, c.ServerBlockKeys)
@ -180,9 +186,7 @@ func cacheParse(c *caddy.Controller) (*Cache, error) {
ca.pcache = cache.New(ca.pcap)
ca.ncache = cache.New(ca.ncap)
}
return ca, nil
}
return nil, nil
}

View file

@ -60,6 +60,8 @@ func TestSetup(t *testing.T) {
{`cache 1 example.nl {
prefetch 0 blurp
}`, true, defaultCap, defaultCap, maxTTL, maxTTL, 0},
{`cache
cache`, true, defaultCap, defaultCap, maxTTL, maxTTL, 0},
}
for i, test := range tests {
c := caddy.NewTestController("dns", test.input)

View file

@ -10,6 +10,8 @@ With *dnssec* any reply that doesn't (or can't) do DNSSEC will get signed on the
denial of existence is implemented with NSEC black lies. Using ECDSA as an algorithm is preferred as
this leads to smaller signatures (compared to RSA). NSEC3 is *not* supported.
This plugin can only be used once per Server Block.
## Syntax
~~~
@ -74,20 +76,3 @@ cluster.local {
}
}
~~~
## Bugs
Multiple *dnssec* plugins inside one server stanza will silently overwrite earlier ones, here
`example.org` will overwrite the one for `cluster.local`.
~~~
. {
kubernetes cluster.local
dnssec cluster.local {
key file Kcluster.local+013+45129
}
dnssec example.org {
key file Kexample.org.+013+45330
}
}
~~~

View file

@ -59,7 +59,14 @@ func dnssecParse(c *caddy.Controller) ([]string, []*DNSKEY, int, error) {
keys := []*DNSKEY{}
capacity := defaultCap
i := 0
for c.Next() {
if i > 0 {
return nil, nil, 0, plugin.ErrOnce
}
i++
// dnssec [zones...]
zones = make([]string, len(c.ServerBlockKeys))
copy(zones, c.ServerBlockKeys)
@ -69,7 +76,8 @@ func dnssecParse(c *caddy.Controller) ([]string, []*DNSKEY, int, error) {
}
for c.NextBlock() {
switch c.Val() {
switch x := c.Val(); x {
case "key":
k, e := keyParse(c)
if e != nil {
@ -86,6 +94,8 @@ func dnssecParse(c *caddy.Controller) ([]string, []*DNSKEY, int, error) {
return nil, nil, 0, err
}
capacity = cacheCap
default:
return nil, nil, 0, c.Errf("unknown property '%s'", x)
}
}

View file

@ -61,6 +61,8 @@ func TestSetupDnssec(t *testing.T) {
key file
}`, true, []string{"example.org."}, nil, defaultCap, "argument count",
},
{`dnssec
dnssec`, true, nil, nil, defaultCap, ""},
}
for i, test := range tests {

View file

@ -8,6 +8,8 @@
Any errors encountered during the query processing will be printed to standard output.
This plugin can only be used once per Server Block.
## Syntax
~~~

View file

@ -37,7 +37,13 @@ func setup(c *caddy.Controller) error {
func errorsParse(c *caddy.Controller) (errorHandler, error) {
handler := errorHandler{}
i := 0
for c.Next() {
if i > 0 {
return handler, plugin.ErrOnce
}
i++
args := c.RemainingArgs()
switch len(args) {
case 0:

View file

@ -12,21 +12,14 @@ func TestErrorsParse(t *testing.T) {
shouldErr bool
expectedErrorHandler errorHandler
}{
{`errors`, false, errorHandler{
LogFile: "stdout",
}},
{`errors stdout`, false, errorHandler{
LogFile: "stdout",
}},
{`errors errors.txt`, true, errorHandler{
LogFile: "",
}},
{`errors visible`, true, errorHandler{
LogFile: "",
}},
{`errors { log visible }`, true, errorHandler{
LogFile: "stdout",
}},
{`errors`, false, errorHandler{LogFile: "stdout"}},
{`errors stdout`, false, errorHandler{LogFile: "stdout"}},
{`errors errors.txt`, true, errorHandler{LogFile: ""}},
{`errors visible`, true, errorHandler{LogFile: ""}},
{`errors { log visible }`, true, errorHandler{LogFile: "stdout"}},
{`errors
errors `, true, errorHandler{LogFile: "stdout"}},
{`errors a b`, true, errorHandler{LogFile: ""}},
}
for i, test := range tests {
c := caddy.NewTestController("dns", test.inputErrorsRules)

View file

@ -19,6 +19,8 @@ is performed and upstreams will always be considered healthy.
When *all* upstreams are down it assumes health checking as a mechanism has failed and will try to
connect to a random upstream (which may or may not work).
This plugin can only be used once per Server Block.
## Syntax
In its most basic form, a simple forwarder uses this syntax:

View file

@ -84,7 +84,13 @@ func parseForward(c *caddy.Controller) (*Forward, error) {
protocols := map[int]int{}
i := 0
for c.Next() {
if i > 0 {
return nil, plugin.ErrOnce
}
i++
if !c.Args(&f.from) {
return f, c.ArgErr()
}

View file

@ -30,6 +30,8 @@ func TestSetup(t *testing.T) {
// negative
{"forward . a27.0.0.1", true, "", nil, 0, false, "not an IP"},
{"forward . 127.0.0.1 {\nblaatl\n}\n", true, "", nil, 0, false, "unknown property"},
{`forward . ::1
forward com ::2`, true, "", nil, 0, false, "plugin"},
}
for i, test := range tests {

View file

@ -11,6 +11,8 @@ file that exists on disk. It checks the file for changes and updates the zones a
plugin only supports A, AAAA, and PTR records. The hosts plugin can be used with readily
available hosts files that block access to advertising servers.
This plugin can only be used once per Server Block.
## Syntax
~~~

View file

@ -69,7 +69,13 @@ func hostsParse(c *caddy.Controller) (Hosts, error) {
config := dnsserver.GetConfig(c)
inline := []string{}
i := 0
for c.Next() {
if i > 0 {
return h, plugin.ErrOnce
}
i++
args := c.RemainingArgs()
if len(args) >= 1 {
h.path = args[0]

View file

@ -57,6 +57,15 @@ func TestHostsParse(t *testing.T) {
}`,
false, "/etc/hosts", []string{"miek.nl.", "10.in-addr.arpa."}, fall.Root,
},
{
`hosts /etc/hosts {
fallthrough
}
hosts /etc/hosts {
fallthrough
}`,
true, "/etc/hosts", nil, fall.Root,
},
}
for i, test := range tests {

View file

@ -16,6 +16,8 @@ to deploy CoreDNS in Kubernetes](https://github.com/coredns/deployment/tree/mast
[stubDomains and upstreamNameservers](http://blog.kubernetes.io/2017/04/configuring-private-dns-zones-upstream-nameservers-kubernetes.html)
are implemented via the *proxy* plugin and kubernetes *upstream*. See example below.
This plugin can only be used once per Server Block.
## Syntax
~~~

View file

@ -71,12 +71,18 @@ func (k *Kubernetes) RegisterKubeCache(c *caddy.Controller) {
}
func kubernetesParse(c *caddy.Controller) (*Kubernetes, error) {
var k8s *Kubernetes
var err error
for i := 1; c.Next(); i++ {
if i > 1 {
return nil, fmt.Errorf("only one kubernetes section allowed per server block")
var (
k8s *Kubernetes
err error
)
i := 0
for c.Next() {
if i > 0 {
return nil, plugin.ErrOnce
}
i++
k8s, err = ParseStanza(c)
if err != nil {
return k8s, err

View file

@ -388,7 +388,7 @@ func TestKubernetesParse(t *testing.T) {
`kubernetes coredns.local
kubernetes cluster.local`,
true,
"only one kubernetes section allowed per server block",
"this plugin",
-1,
0,
defaultResyncPeriod,

View file

@ -6,9 +6,12 @@
## Description
This plugin implements RFC 5001 and adds an EDNS0 OPT resource record to replies that uniquely
identify the server. This is useful in anycast setups to see which server was responsible for
generating the reply and for debugging.
This plugin implements [RFC 5001](https://tools.ietf.org/html/rfc5001) and adds an EDNS0 OPT
resource record to replies that uniquely identify the server. This is useful in anycast setups to
see which server was responsible for generating the reply and for debugging.
This plugin can only be used once per Server Block.
## Syntax
@ -48,3 +51,7 @@ And now a client with NSID support will see an OPT record with the NSID option:
;; QUESTION SECTION:
;whoami.example.org. IN A
~~~
## Also See
[RFC 5001](https://tools.ietf.org/html/rfc5001)

View file

@ -36,13 +36,16 @@ func nsidParse(c *caddy.Controller) (string, error) {
if err != nil {
nsid = "localhost"
}
i := 0
for c.Next() {
if i > 0 {
return nsid, plugin.ErrOnce
}
i++
args := c.RemainingArgs()
if len(args) == 0 {
return nsid, nil
}
if len(args) > 0 {
nsid = strings.Join(args, " ")
return nsid, nil
}
}
return nsid, nil
}

View file

@ -19,18 +19,12 @@ func TestSetupNsid(t *testing.T) {
expectedData string
expectedErrContent string // substring from the expected error. Empty for positive cases.
}{
{
`nsid`, false, defaultNsid, "",
},
{
`nsid "ps0"`, false, "ps0", "",
},
{
`nsid "worker1"`, false, "worker1", "",
},
{
`nsid "tf 2"`, false, "tf 2", "",
},
{`nsid`, false, defaultNsid, ""},
{`nsid "ps0"`, false, "ps0", ""},
{`nsid "worker1"`, false, "worker1", ""},
{`nsid "tf 2"`, false, "tf 2", ""},
{`nsid
nsid`, true, "", "plugin"},
}
for i, test := range tests {

View file

@ -104,3 +104,6 @@ const Namespace = "coredns"
// TimeBuckets is based on Prometheus client_golang prometheus.DefBuckets
var TimeBuckets = prometheus.ExponentialBuckets(0.00025, 2, 16) // from 0.25ms to 8 seconds
// ErrOnce is returned when a plugin doesn't support multiple setups per server.
var ErrOnce = errors.New("this plugin can only be used once per Server Block")

View file

@ -16,6 +16,8 @@ For more information, please see [Go's pprof
documentation](https://golang.org/pkg/net/http/pprof/) and read
[Profiling Go Programs](https://blog.golang.org/profiling-go-programs).
This plugin can only be used once per Server Block.
## Syntax
~~~

View file

@ -19,12 +19,15 @@ func init() {
}
func setup(c *caddy.Controller) error {
found := false
h := &handler{addr: defaultAddr}
i := 0
for c.Next() {
if found {
return plugin.Error("pprof", c.Err("pprof can only be specified once"))
if i > 0 {
return plugin.Error("pprof", plugin.ErrOnce)
}
i++
args := c.RemainingArgs()
if len(args) == 1 {
h.addr = args[0]
@ -39,7 +42,6 @@ func setup(c *caddy.Controller) error {
if c.NextBlock() {
return plugin.Error("pprof", c.ArgErr())
}
found = true
}
pprofOnce.Do(func() {

View file

@ -26,6 +26,8 @@ reloads are graceful, and can be disabled by setting the jitter to `0s`.
Jitter is re-calculated whenever the Corefile is reloaded.
This plugin can only be used once per Server Block.
## Syntax
~~~ txt

View file

@ -9,6 +9,8 @@
The default root is the current working directory of CoreDNS. The *root* plugin allows you to change
this. A relative root path is relative to the current working directory.
This plugin can only be used once per Server Block.
## Syntax
~~~ txt

View file

@ -6,9 +6,8 @@
## Description
The route53 plugin is useful for serving zones from resource record sets in AWS route53.
This plugin only supports A and AAAA records. The route53 plugin can be used when
coredns is deployed on AWS.
The route53 plugin is useful for serving zones from resource record sets in AWS route53. This plugin
only supports A and AAAA records. The route53 plugin can be used when coredns is deployed on AWS.
## Syntax