diff --git a/docs/content/getting-started/faq.md b/docs/content/getting-started/faq.md index 087504452..01b33f639 100644 --- a/docs/content/getting-started/faq.md +++ b/docs/content/getting-started/faq.md @@ -157,3 +157,27 @@ By default, the following headers are automatically added when proxying requests For more details, please check out the [forwarded header](../routing/entrypoints.md#forwarded-headers) documentation. + +## What does the "field not found" error mean? + +```shell +error: field not found, node: -badField- +``` + +The "field not found" error occurs, when an unknown property is encountered in the dynamic or static configuration. + +One easy way to check whether a configuration file is well-formed, is to validate it with: + +- [JSON Schema of the static configuration](https://json.schemastore.org/traefik-v2.json) +- [JSON Schema of the dynamic configuration](https://json.schemastore.org/traefik-v2-file-provider.json) + +## Why are some resources (routers, middlewares, services...) not created/applied? + +As a common tip, if a resource is dropped/not created by Traefik after the dynamic configuration was evaluated, +one should look for an error in the logs. + +If found, the error obviously confirms that something went wrong while creating the resource, +and the message should help in figuring out the mistake(s) in the configuration, and how to fix it. + +When using the file provider, +one easy way to check if the dynamic configuration is well-formed is to validate it with the [JSON Schema of the dynamic configuration](https://json.schemastore.org/traefik-v2-file-provider.json). diff --git a/docs/content/routing/routers/index.md b/docs/content/routing/routers/index.md index d5ef084a6..3a5045a27 100644 --- a/docs/content/routing/routers/index.md +++ b/docs/content/routing/routers/index.md @@ -233,18 +233,18 @@ If the rule is verified, the router becomes active, calls middlewares, and then The table below lists all the available matchers: -| Rule | Description | -|------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------| -| ```Headers(`key`, `value`)``` | Check if there is a key `key`defined in the headers, with the value `value` | -| ```HeadersRegexp(`key`, `regexp`)``` | Check if there is a key `key`defined in the headers, with a value that matches the regular expression `regexp` | -| ```Host(`example.com`, ...)``` | Check if the request domain (host header value) targets one of the given `domains`. | -| ```HostHeader(`example.com`, ...)``` | Same as `Host`, only exists for historical reasons. | -| ```HostRegexp(`example.com`, `{subdomain:[a-z]+}.example.com`, ...)``` | Match the request domain. See "Regexp Syntax" below. | -| ```Method(`GET`, ...)``` | Check if the request method is one of the given `methods` (`GET`, `POST`, `PUT`, `DELETE`, `PATCH`, `HEAD`) | -| ```Path(`/path`, `/articles/{cat:[a-z]+}/{id:[0-9]+}`, ...)``` | Match exact request path. See "Regexp Syntax" below. | -| ```PathPrefix(`/products/`, `/articles/{cat:[a-z]+}/{id:[0-9]+}`)``` | Match request prefix path. See "Regexp Syntax" below. | -| ```Query(`foo=bar`, `bar=baz`)``` | Match Query String parameters. It accepts a sequence of key=value pairs. | -| ```ClientIP(`10.0.0.0/16`, `::1`)``` | Match if the request client IP is one of the given IP/CIDR. It accepts IPv4, IPv6 and CIDR formats. | +| Rule | Description | +|--------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------| +| ```Headers(`key`, `value`)``` | Check if there is a key `key`defined in the headers, with the value `value` | +| ```HeadersRegexp(`key`, `regexp`)``` | Check if there is a key `key`defined in the headers, with a value that matches the regular expression `regexp` | +| ```Host(`example.com`, ...)``` | Check if the request domain (host header value) targets one of the given `domains`. | +| ```HostHeader(`example.com`, ...)``` | Same as `Host`, only exists for historical reasons. | +| ```HostRegexp(`example.com`, `{subdomain:[a-z]+}.example.com`, ...)``` | Match the request domain. See "Regexp Syntax" below. | +| ```Method(`GET`, ...)``` | Check if the request method is one of the given `methods` (`GET`, `POST`, `PUT`, `DELETE`, `PATCH`, `HEAD`) | +| ```Path(`/path`, `/articles/{cat:[a-z]+}/{id:[0-9]+}`, ...)``` | Match exact request path. See "Regexp Syntax" below. | +| ```PathPrefix(`/products/`, `/articles/{cat:[a-z]+}/{id:[0-9]+}`)``` | Match request prefix path. See "Regexp Syntax" below. | +| ```Query(`foo=bar`, `bar=baz`)``` | Match Query String parameters. It accepts a sequence of key=value pairs. | +| ```ClientIP(`10.0.0.0/16`, `::1`)``` | Match if the request client IP is one of the given IP/CIDR. It accepts IPv4, IPv6 and CIDR formats. | !!! important "Non-ASCII Domain Names" @@ -259,6 +259,7 @@ The table below lists all the available matchers: The regexp name (`name` in the above example) is an arbitrary value, that exists only for historical reasons. Any `regexp` supported by [Go's regexp package](https://golang.org/pkg/regexp/) may be used. + For example, here is a case insensitive path matcher syntax: ```Path(`/{path:(?i:Products)}`)```. !!! info "Combining Matchers Using Operators and Parenthesis" diff --git a/pkg/plugins/middlewares.go b/pkg/plugins/middlewares.go index 09edbc954..e46dbae34 100644 --- a/pkg/plugins/middlewares.go +++ b/pkg/plugins/middlewares.go @@ -84,6 +84,9 @@ func (p middlewareBuilder) createConfig(config map[string]interface{}) (reflect. } vConfig := results[0] + if len(config) == 0 { + return vConfig, nil + } cfg := &mapstructure.DecoderConfig{ DecodeHook: mapstructure.StringToSliceHookFunc(","), diff --git a/pkg/server/middleware/plugins.go b/pkg/server/middleware/plugins.go index a40179151..3a092f140 100644 --- a/pkg/server/middleware/plugins.go +++ b/pkg/server/middleware/plugins.go @@ -2,7 +2,6 @@ package middleware import ( "errors" - "fmt" "github.com/traefik/traefik/v2/pkg/config/dynamic" "github.com/traefik/traefik/v2/pkg/plugins" @@ -30,9 +29,5 @@ func findPluginConfig(rawConfig map[string]dynamic.PluginConf) (string, map[stri return "", nil, errors.New("missing plugin type") } - if len(rawPluginConfig) == 0 { - return "", nil, fmt.Errorf("missing plugin configuration: %s", pluginType) - } - return pluginType, rawPluginConfig, nil }