Support YAML for the dynamic configuration.

This commit is contained in:
Ludovic Fernandez 2019-06-26 18:18:04 +02:00 committed by Traefiker Bot
parent 96962dd21f
commit e69d4cba88
36 changed files with 1529 additions and 289 deletions

View file

@ -49,7 +49,12 @@ Once positioned, this option sets (and resets) all the default values of the sub
### Configuration File
At startup, Traefik searches for a file named `traefik.toml` in `/etc/traefik/`, `$XDG_CONFIG_HOME/`, `$HOME/.config/`, and `.` (_the working directory_).
At startup, Traefik searches for a file named `traefik.toml` (or `traefik.yml` or `traefik.yaml`) in:
- `/etc/traefik/`
- `$XDG_CONFIG_HOME/`
- `$HOME/.config/`
- `.` (_the working directory_).
You can override this using the `configFile` argument.

View file

@ -3,10 +3,10 @@
Good Old Configuration File
{: .subtitle }
The file provider lets you define the [dynamic configuration](./overview.md) in a `toml` file.
The file provider lets you define the [dynamic configuration](./overview.md) in a TOML or YAML file.
You can write these configuration elements:
* At the end of the main Traefik configuration file (by default: `traefik.toml`).
* At the end of the main Traefik configuration file (by default: `traefik.toml`/`traefik.yml`/`traefik.yaml`).
* In [a dedicated file](#filename)
* In [several dedicated files](#directory)
@ -20,10 +20,20 @@ You can write these configuration elements:
??? example "Declaring Routers, Middlewares & Services"
``` toml
# Enabling the file provider
[providers.file]
Enabling the file provider:
```toml tab="TOML"
[providers.file]
```
```yaml tab="YAML"
providers:
file: {}
```
Declaring Routers, Middlewares & Services:
```toml tab="TOML"
[http]
# Add the router
[http.routers]
@ -49,6 +59,32 @@ You can write these configuration elements:
[[http.services.service-foo.LoadBalancer.Servers]]
url = "http://bar/"
```
```yaml tab="YAML"
http:
routers:
router0:
entrypoints:
- web
middlewares:
- my-basic-auth
service: service-foo
rule: Path(`foo`)
middlewares:
my-basic-auth:
basicAuth:
users:
- test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/
- test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0
usersfile: etc/traefik/.htpasswd
headerfield: ""
services:
service-foo:
loadbalancer:
servers:
- url: http://foo/
- url: http://bar/
```
## Provider Configuration Options
@ -61,24 +97,36 @@ _Optional_
Defines the path of the configuration file.
```toml
```toml tab="TOML"
[providers]
[providers.file]
filename = "rules.toml"
```
```yaml tab="YAML"
providers:
file:
filename: rules.yaml
```
### `directory`
_Optional_
Defines the directory that contains the configuration files.
```toml
```toml tab="TOML"
[providers]
[providers.file]
directory = "/path/to/config"
```
```yaml tab="YAML"
providers:
file:
directory: /path/to/config
```
### `watch`
_Optional_
@ -86,24 +134,32 @@ _Optional_
Set the `watch` option to `true` to allow Traefik to automatically watch for file changes.
It works with both the `filename` and the `directory` options.
```toml
```toml tab="TOML"
[providers]
[providers.file]
filename = "rules.toml"
watch = true
```
### TOML Templating
```yaml tab="YAML"
providers:
file:
filename: rules.yml
watch: true
```
### Go Templating
!!! warning
TOML templating only works along with dedicated configuration files. Templating does not work in the Traefik main configuration file.
Go Templating only works along with dedicated configuration files.
Templating does not work in the Traefik main configuration file.
Traefik allows using TOML templating.
Traefik allows using Go templating.
Thus, it's possible to define easily lot of routers, services and TLS certificates as described in the file `template-rules.toml` :
??? example "Configuring Using Templating"
```toml
```toml tab="TOML"
# template-rules.toml
[http]
@ -149,3 +205,43 @@ Thus, it's possible to define easily lot of routers, services and TLS certificat
# ...
{{ end }}
```
```yaml tab="YAML"
http:
{{range $i, $e := until 100 }}
routers:
router{{ $e }:
# ...
{{end}}
{{range $i, $e := until 100 }}
services:
application{{ $e }}:
# ...
{{end}}
tcp:
{{range $i, $e := until 100 }}
routers:
router{{ $e }:
# ...
{{end}}
{{range $i, $e := until 100 }}
services:
service{{ $e }}:
# ...
{{end}}
{{ range $i, $e := until 10 }}
tls:
store:
- "my-store-foo-{{ $e }}"
- "my-store-bar-{{ $e }}"
certificate:
certfile: "/etc/traefik/cert-{{ $e }}.pem"
keyfile: "/etc/traefik/cert-{{ $e }}.key"
{{end}}
```

View file

@ -1,8 +1,12 @@
# File Configuration Reference
Dynamic configuration with toml files
Dynamic configuration with files
{: .subtitle }
```toml
```toml tab="TOML"
--8<-- "content/reference/dynamic-configuration/file.toml"
```
```yml tab="YAML"
--8<-- "content/reference/dynamic-configuration/file.yaml"
```

View file

@ -0,0 +1,294 @@
http:
routers:
Router0:
entrypoints:
- foobar
- foobar
middlewares:
- foobar
- foobar
service: foobar
rule: foobar
priority: 42
tls:
options: TLS0
middlewares:
Middleware0:
addPrefix:
prefix: foobar
Middleware1:
stripPrefix:
prefixes:
- foobar
- foobar
Middleware2:
stripPrefixRegex:
regex:
- foobar
- foobar
Middleware3:
replacePath:
path: foobar
Middleware4:
replacePathRegex:
regex: foobar
replacement: foobar
Middleware5:
chain:
middlewares:
- foobar
- foobar
Middleware6:
ipWhiteList:
sourcerange:
- foobar
- foobar
ipstrategy: null
Middleware7:
ipWhiteList:
sourcerange: []
ipstrategy:
depth: 42
excludedips:
- foobar
- foobar
Middleware8:
headers:
customrequestheaders:
name0: foobar
name1: foobar
customresponseheaders:
name0: foobar
name1: foobar
accesscontrolallowcredentials: true
accesscontrolallowheaders:
- foobar
- foobar
accesscontrolallowmethods:
- foobar
- foobar
accesscontrolalloworigin: foobar
accesscontrolexposeheaders:
- foobar
- foobar
accesscontrolmaxage: 42
addvaryheader: true
allowedhosts:
- foobar
- foobar
hostsproxyheaders:
- foobar
- foobar
sslredirect: true
ssltemporaryredirect: true
sslhost: foobar
sslproxyheaders:
name0: foobar
name1: foobar
sslforcehost: true
stsseconds: 42
stsincludesubdomains: true
stspreload: true
forcestsheader: true
framedeny: true
customframeoptionsvalue: foobar
contenttypenosniff: true
browserxssfilter: true
custombrowserxssvalue: foobar
contentsecuritypolicy: foobar
publickey: foobar
referrerpolicy: foobar
isdevelopment: true
Middleware9:
errors:
status:
- foobar
- foobar
service: foobar
query: foobar
Middleware10:
rateLimit:
rateset:
Rate0:
period: 42000000000
average: 42
burst: 42
Rate1:
period: 42000000000
average: 42
burst: 42
extractorfunc: foobar
Middleware11:
redirectRegex:
regex: foobar
replacement: foobar
permanent: true
Middleware12:
redirectScheme:
scheme: foobar
port: foobar
permanent: true
Middleware13:
basicAuth:
users:
- foobar
- foobar
usersfile: foobar
realm: foobar
removeheader: true
headerfield: foobar
Middleware14:
digestAuth:
users:
- foobar
- foobar
usersfile: foobar
removeheader: true
realm: foobar
headerfield: foobar
Middleware15:
forwardAuth:
address: foobar
tls:
ca: foobar
caoptional: true
cert: foobar
key: foobar
insecureskipverify: true
trustforwardheader: true
authresponseheaders:
- foobar
- foobar
Middleware16:
maxConn:
amount: 42
extractorfunc: foobar
Middleware17:
buffering:
maxrequestbodybytes: 42
memrequestbodybytes: 42
maxresponsebodybytes: 42
memresponsebodybytes: 42
retryexpression: foobar
Middleware18:
circuitBreaker:
expression: foobar
Middleware19:
compress: {}
Middleware20:
passTLSClientCert:
pem: true
info:
notafter: true
notbefore: true
sans: true
subject:
country: true
province: true
locality: true
organization: true
commonname: true
serialnumber: true
domaincomponent: true
issuer:
country: true
province: true
locality: true
organization: true
commonname: true
serialnumber: true
domaincomponent: true
Middleware21:
retry:
attempts: 42
services:
Service0:
loadbalancer:
stickiness:
cookiename: foobar
securecookie: false
httponlycookie: false
servers:
- url: foobar
scheme: ""
port: ""
- url: foobar
scheme: ""
port: ""
healthcheck:
scheme: foobar
path: foobar
port: 42
interval: foobar
timeout: foobar
hostname: foobar
headers:
name0: foobar
name1: foobar
passhostheader: true
responseforwarding:
flushinterval: foobar
tcp:
routers:
TCPRouter0:
entrypoints:
- foobar
- foobar
service: foobar
rule: foobar
tls:
passthrough: true
options: TLS1
services:
TCPService0:
loadbalancer:
servers:
- address: foobar
port: ""
- address: foobar
port: ""
tls:
- stores:
- foobar
- foobar
certificate:
certfile: foobar
keyfile: foobar
- stores:
- foobar
- foobar
certificate:
certfile: foobar
keyfile: foobar
tlsoptions:
TLS0:
minversion: foobar
ciphersuites:
- foobar
- foobar
clientca:
files:
- foobar
- foobar
optional: true
snistrict: true
TLS1:
minversion: foobar
ciphersuites:
- foobar
- foobar
clientca:
files:
- foobar
- foobar
optional: true
snistrict: true
tlsstores:
Store0:
defaultcertificate:
certfile: foobar
keyfile: foobar
Store1:
defaultcertificate:
certfile: foobar
keyfile: foobar

View file

@ -1,7 +1,9 @@
# Static Configuration: File
## TOML
```toml
```toml tab="TOML"
--8<-- "content/reference/static-configuration/file.toml"
```
```yml tab="YAML"
--8<-- "content/reference/static-configuration/file.yaml"
```

View file

@ -133,16 +133,16 @@
[Metrics.Datadog]
Address = "foobar"
PushInterval = "foobar"
PushInterval = "10s"
[Metrics.StatsD]
Address = "foobar"
PushInterval = "foobar"
PushInterval = "10s"
[Metrics.InfluxDB]
Address = "foobar"
Protocol = "foobar"
PushInterval = "foobar"
PushInterval = "10s"
Database = "foobar"
RetentionPolicy = "foobar"
Username = "foobar"

View file

@ -0,0 +1,240 @@
global:
checknewversion: true
sendanonymoususage: true
serverstransport:
insecureskipverify: true
rootcas:
- foobar
- foobar
maxidleconnsperhost: 42
forwardingtimeouts:
dialtimeout: 42000000000
responseheadertimeout: 42000000000
entrypoints:
EntryPoint0:
address: foobar
transport:
lifecycle:
requestacceptgracetimeout: 42000000000
gracetimeout: 42000000000
respondingtimeouts:
readtimeout: 42000000000
writetimeout: 42000000000
idletimeout: 42000000000
proxyprotocol:
insecure: true
trustedips:
- foobar
- foobar
forwardedheaders:
insecure: true
trustedips:
- foobar
- foobar
providers:
providersthrottleduration: 42000000000
docker:
constraints: foobar
watch: true
endpoint: foobar
defaultrule: foobar
tls:
ca: foobar
caoptional: true
cert: foobar
key: foobar
insecureskipverify: true
exposedbydefault: true
usebindportip: true
swarmmode: true
network: foobar
swarmmoderefreshseconds: 42000000000
file:
directory: foobar
watch: true
filename: foobar
debugloggeneratedtemplate: true
traefikfile: foobar
marathon:
constraints: foobar
trace: true
watch: true
endpoint: foobar
defaultrule: foobar
exposedbydefault: true
dcostoken: foobar
tls:
ca: foobar
caoptional: true
cert: foobar
key: foobar
insecureskipverify: true
dialertimeout: 42000000000
responseheadertimeout: 42000000000
tlshandshaketimeout: 42000000000
keepalive: 42000000000
forcetaskhostname: true
basic:
httpbasicauthuser: foobar
httpbasicpassword: foobar
respectreadinesschecks: true
kubernetes:
endpoint: foobar
token: foobar
certauthfilepath: foobar
disablepasshostheaders: true
namespaces:
- foobar
- foobar
labelselector: foobar
ingressclass: foobar
ingressendpoint:
ip: foobar
hostname: foobar
publishedservice: foobar
kubernetescrd:
endpoint: foobar
token: foobar
certauthfilepath: foobar
disablepasshostheaders: true
namespaces:
- foobar
- foobar
labelselector: foobar
ingressclass: foobar
rest:
entrypoint: foobar
rancher:
constraints: foobar
watch: true
defaultrule: foobar
exposedbydefault: true
enableservicehealthfilter: true
refreshseconds: 42
intervalpoll: true
prefix: foobar
api:
entrypoint: foobar
dashboard: true
debug: false
statistics:
recenterrors: 42
middlewares:
- foobar
- foobar
dashboardassets: null
metrics:
prometheus:
buckets:
- 42
- 42
entrypoint: foobar
middlewares:
- foobar
- foobar
datadog:
address: foobar
pushinterval: 10000000000
statsd:
address: foobar
pushinterval: 10000000000
influxdb:
address: foobar
protocol: foobar
pushinterval: 10000000000
database: foobar
retentionpolicy: foobar
username: foobar
password: foobar
ping:
entrypoint: foobar
middlewares:
- foobar
- foobar
log:
level: foobar
filepath: foobar
format: foobar
accesslog:
filepath: foobar
format: foobar
filters:
statuscodes:
- foobar
- foobar
retryattempts: true
minduration: 42000000000
fields:
defaultmode: foobar
names:
name0: foobar
name1: foobar
headers:
defaultmode: foobar
names:
name0: foobar
name1: foobar
bufferingsize: 42
tracing:
backend: foobar
servicename: foobar
spannamelimit: 42
jaeger:
samplingserverurl: foobar
samplingtype: foobar
samplingparam: 42
localagenthostport: foobar
gen128bit: true
propagation: foobar
tracecontextheadername: foobar
zipkin:
httpendpoint: foobar
samespan: true
id128bit: true
debug: true
samplerate: 42
datadog:
localagenthostport: foobar
globaltag: foobar
debug: true
prioritysampling: true
traceidheadername: foobar
parentidheadername: foobar
samplingpriorityheadername: foobar
bagageprefixheadername: foobar
instana:
localagenthost: foobar
localagentport: 42
loglevel: foobar
haystack: null
hostresolver:
cnameflattening: true
resolvconfig: foobar
resolvdepth: 42
acme:
email: foobar
acmelogging: true
caserver: foobar
storage: foobar
entrypoint: foobar
keytype: foobar
onhostrule: true
dnschallenge:
provider: foobar
delaybeforecheck: 42000000000
resolvers:
- foobar
- foobar
disablepropagationcheck: true
httpchallenge:
entrypoint: foobar
tlschallenge: {}
domains:
- main: foobar
sans:
- foobar
- foobar
- main: foobar
sans:
- foobar
- foobar

View file

@ -24,29 +24,79 @@ If they do, the router might transform the request using pieces of [middleware](
Below is an example of a full configuration file for the [file provider](../providers/file.md) that forwards `http://domain/whoami/` requests to a service reachable on `http://private/whoami-service/`.
In the process, Traefik will make sure that the user is authenticated (using the [BasicAuth middleware](../middlewares/basicauth.md)).
```toml
Static configuration:
```toml tab="TOML"
[entryPoints]
[entryPoints.web]
address = ":8081" # Listen on port 8081 for incoming requests
[entryPoints.web]
# Listen on port 8081 for incoming requests
address = ":8081"
[providers]
[providers.file] # Enable the file provider to define routers / middlewares / services in a file
# Enable the file provider to define routers / middlewares / services in a file
[providers.file]
```
[http] # http routing section
[http.routers]
[http.routers.to-whoami] # Define a connection between requests and services
rule = "Host(domain) && PathPrefix(/whoami/)"
middlewares = ["test-user"] # If the rule matches, applies the middleware
service = "whoami" # If the rule matches, forward to the whoami service (declared below)
```yaml tab="YAML"
entrypoints:
web:
# Listen on port 8081 for incoming requests
address: :8081
providers:
# Enable the file provider to define routers / middlewares / services in a file
file: {}
```
[http.middlewares]
[http.middlewares.test-user.basicauth] # Define an authentication mechanism
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"]
Dynamic configuration:
[http.services]
[http.services.whoami.loadbalancer] # Define how to reach an existing service on our infrastructure
[[http.services.whoami.loadbalancer.servers]]
url = "http://private/whoami-service"
```toml tab="TOML"
# http routing section
[http]
[http.routers]
# Define a connection between requests and services
[http.routers.to-whoami]
rule = "Host(`domain`) && PathPrefix(`/whoami/`)"
# If the rule matches, applies the middleware
middlewares = ["test-user"]
# If the rule matches, forward to the whoami service (declared below)
service = "whoami"
[http.middlewares]
# Define an authentication mechanism
[http.middlewares.test-user.basicauth]
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"]
[http.services]
# Define how to reach an existing service on our infrastructure
[http.services.whoami.loadbalancer]
[[http.services.whoami.loadbalancer.servers]]
url = "http://private/whoami-service"
```
```yaml tab="YAML"
# http routing section
http:
routers:
# Define a connection between requests and services
to-whoami:
rule: "Host(`domain`) && PathPrefix(`/whoami/`)"
# If the rule matches, applies the middleware
middlewares:
- test-user
# If the rule matches, forward to the whoami service (declared below)
service: whoami
middlewares:
# Define an authentication mechanism
test-user:
basicAuth:
users:
- test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/
services:
# Define how to reach an existing service on our infrastructure
whoami:
loadbalancer:
servers:
- url: http://private/whoami-service
```
!!! note "The File Provider"
@ -61,27 +111,51 @@ In the process, Traefik will make sure that the user is authenticated (using the
??? example "Adding a TCP route for TLS requests on whoami.traefik.io"
```toml
Static configuration:
```toml tab="TOML"
[entryPoints]
[entryPoints.web]
address = ":8081" # Listen on port 8081 for incoming requests
# Listen on port 8081 for incoming requests
address = ":8081"
[providers]
[providers.file] # Enable the file provider to define routers / middlewares / services in a file
# Enable the file provider to define routers / middlewares / services in a file
[providers.file]
```
```yaml tab="YAML"
entrypoints:
web:
# Listen on port 8081 for incoming requests
address: :8081
providers:
# Enable the file provider to define routers / middlewares / services in a file
file: {}
```
Dynamic configuration:
[http] # http routing section
```toml tab="TOML"
# http routing section
[http]
[http.routers]
[http.routers.to-whoami] # Define a connection between requests and services
rule = "Host(`domain`) && PathPrefix(/whoami/)"
middlewares = ["test-user"] # If the rule matches, applies the middleware
service = "whoami" # If the rule matches, forward to the whoami service (declared below)
# Define a connection between requests and services
[http.routers.to-whoami]
rule = "Host(`domain`) && PathPrefix(`/whoami/`)"
# If the rule matches, applies the middleware
middlewares = ["test-user"]
# If the rule matches, forward to the whoami service (declared below)
service = "whoami"
[http.middlewares]
[http.middlewares.test-user.basicauth] # Define an authentication mechanism
# Define an authentication mechanism
[http.middlewares.test-user.basicauth]
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"]
[http.services]
[http.services.whoami.loadbalancer] # Define how to reach an existing service on our infrastructure
# Define how to reach an existing service on our infrastructure
[http.services.whoami.loadbalancer]
[[http.services.whoami.loadbalancer.servers]]
url = "http://private/whoami-service"
@ -97,3 +171,39 @@ In the process, Traefik will make sure that the user is authenticated (using the
[[tcp.services.whoami-tcp.loadbalancer.servers]]
address = "xx.xx.xx.xx:xx"
```
```yaml tab="YAML"
# http routing section
http:
routers:
# Define a connection between requests and services
to-whoami:
rule: Host(`domain`) && PathPrefix(`/whoami/`)
# If the rule matches, applies the middleware
middlewares:
- test-user
# If the rule matches, forward to the whoami service (declared below)
service: whoami
middlewares:
# Define an authentication mechanism
test-user:
basicAuth:
users:
- test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/
services:
# Define how to reach an existing service on our infrastructure
whoami:
loadbalancer:
servers:
- url: http://private/whoami-service
tcp:
routers:
to-whoami-tcp:
service: whoami-tcp
rule: HostSNI(`whoami-tcp.traefik.io`)
services:
whoami-tcp:
loadbalancer:
servers:
- address: xx.xx.xx.xx:xx
```

View file

@ -215,7 +215,7 @@ type Message struct {
type Configuration struct {
HTTP *HTTPConfiguration
TCP *TCPConfiguration
TLS []*traefiktls.Configuration `json:"-" label:"-"`
TLS []*traefiktls.Configuration `json:"-" label:"-" yaml:"tls"`
TLSOptions map[string]traefiktls.TLS
TLSStores map[string]traefiktls.Store
}

View file

@ -5,6 +5,7 @@ import (
"io/ioutil"
"path/filepath"
"reflect"
"strings"
"github.com/BurntSushi/toml"
"github.com/containous/traefik/pkg/config/parser"
@ -22,7 +23,7 @@ func decodeFileToNode(filePath string, filters ...string) (*parser.Node, error)
data := make(map[string]interface{})
switch filepath.Ext(filePath) {
switch strings.ToLower(filepath.Ext(filePath)) {
case ".toml":
err = toml.Unmarshal(content, &data)
if err != nil {
@ -30,14 +31,11 @@ func decodeFileToNode(filePath string, filters ...string) (*parser.Node, error)
}
case ".yml", ".yaml":
var err error
err = yaml.Unmarshal(content, data)
if err != nil {
return nil, err
}
return decodeRawToNode(data, parser.DefaultRootName, filters...)
default:
return nil, fmt.Errorf("unsupported file extension: %s", filePath)
}

View file

@ -9,27 +9,27 @@ import (
// Middleware holds the Middleware configuration.
type Middleware struct {
AddPrefix *AddPrefix `json:"addPrefix,omitempty"`
StripPrefix *StripPrefix `json:"stripPrefix,omitempty"`
StripPrefixRegex *StripPrefixRegex `json:"stripPrefixRegex,omitempty"`
ReplacePath *ReplacePath `json:"replacePath,omitempty"`
ReplacePathRegex *ReplacePathRegex `json:"replacePathRegex,omitempty"`
Chain *Chain `json:"chain,omitempty"`
IPWhiteList *IPWhiteList `json:"ipWhiteList,omitempty"`
Headers *Headers `json:"headers,omitempty"`
Errors *ErrorPage `json:"errors,omitempty"`
RateLimit *RateLimit `json:"rateLimit,omitempty"`
RedirectRegex *RedirectRegex `json:"redirectRegex,omitempty"`
RedirectScheme *RedirectScheme `json:"redirectScheme,omitempty"`
BasicAuth *BasicAuth `json:"basicAuth,omitempty"`
DigestAuth *DigestAuth `json:"digestAuth,omitempty"`
ForwardAuth *ForwardAuth `json:"forwardAuth,omitempty"`
MaxConn *MaxConn `json:"maxConn,omitempty"`
Buffering *Buffering `json:"buffering,omitempty"`
CircuitBreaker *CircuitBreaker `json:"circuitBreaker,omitempty"`
Compress *Compress `json:"compress,omitempty" label:"allowEmpty"`
PassTLSClientCert *PassTLSClientCert `json:"passTLSClientCert,omitempty"`
Retry *Retry `json:"retry,omitempty"`
AddPrefix *AddPrefix `json:"addPrefix,omitempty" yaml:"addPrefix,omitempty"`
StripPrefix *StripPrefix `json:"stripPrefix,omitempty" yaml:"stripPrefix,omitempty"`
StripPrefixRegex *StripPrefixRegex `json:"stripPrefixRegex,omitempty" yaml:"stripPrefixRegex,omitempty"`
ReplacePath *ReplacePath `json:"replacePath,omitempty" yaml:"replacePath,omitempty"`
ReplacePathRegex *ReplacePathRegex `json:"replacePathRegex,omitempty" yaml:"replacePathRegex,omitempty"`
Chain *Chain `json:"chain,omitempty" yaml:"chain,omitempty"`
IPWhiteList *IPWhiteList `json:"ipWhiteList,omitempty" yaml:"ipWhiteList,omitempty"`
Headers *Headers `json:"headers,omitempty" yaml:"headers,omitempty"`
Errors *ErrorPage `json:"errors,omitempty" yaml:"errors,omitempty"`
RateLimit *RateLimit `json:"rateLimit,omitempty" yaml:"rateLimit,omitempty"`
RedirectRegex *RedirectRegex `json:"redirectRegex,omitempty" yaml:"redirectRegex,omitempty"`
RedirectScheme *RedirectScheme `json:"redirectScheme,omitempty" yaml:"redirectScheme,omitempty"`
BasicAuth *BasicAuth `json:"basicAuth,omitempty" yaml:"basicAuth,omitempty"`
DigestAuth *DigestAuth `json:"digestAuth,omitempty" yaml:"digestAuth,omitempty"`
ForwardAuth *ForwardAuth `json:"forwardAuth,omitempty" yaml:"forwardAuth,omitempty"`
MaxConn *MaxConn `json:"maxConn,omitempty" yaml:"maxConn,omitempty"`
Buffering *Buffering `json:"buffering,omitempty" yaml:"buffering,omitempty"`
CircuitBreaker *CircuitBreaker `json:"circuitBreaker,omitempty" yaml:"circuitBreaker,omitempty"`
Compress *Compress `json:"compress,omitempty" label:"allowEmpty" yaml:"compress,omitempty" label:"allowEmpty"`
PassTLSClientCert *PassTLSClientCert `json:"passTLSClientCert,omitempty" yaml:"passTLSClientCert,omitempty"`
Retry *Retry `json:"retry,omitempty" yaml:"retry,omitempty"`
}
// +k8s:deepcopy-gen=true

View file

@ -7,7 +7,6 @@ import (
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"text/template"
@ -20,6 +19,7 @@ import (
"github.com/containous/traefik/pkg/safe"
"github.com/containous/traefik/pkg/tls"
"gopkg.in/fsnotify.v1"
"gopkg.in/yaml.v2"
)
const providerName = "file"
@ -170,28 +170,13 @@ func sendConfigToChannel(configurationChan chan<- config.Message, configuration
}
}
func readFile(filename string) (string, error) {
if len(filename) > 0 {
buf, err := ioutil.ReadFile(filename)
if err != nil {
return "", err
}
return string(buf), nil
}
return "", fmt.Errorf("invalid filename: %s", filename)
}
func (p *Provider) loadFileConfig(filename string, parseTemplate bool) (*config.Configuration, error) {
fileContent, err := readFile(filename)
if err != nil {
return nil, fmt.Errorf("error reading configuration file: %s - %s", filename, err)
}
var err error
var configuration *config.Configuration
if parseTemplate {
configuration, err = p.CreateConfiguration(fileContent, template.FuncMap{}, false)
configuration, err = p.CreateConfiguration(filename, template.FuncMap{}, false)
} else {
configuration, err = p.DecodeConfiguration(fileContent)
configuration, err = p.DecodeConfiguration(filename)
}
if err != nil {
return nil, err
@ -223,7 +208,6 @@ func (p *Provider) loadFileConfigFromDirectory(ctx context.Context, directory st
logger := log.FromContext(ctx)
fileList, err := ioutil.ReadDir(directory)
if err != nil {
return configuration, fmt.Errorf("unable to read directory %s: %v", directory, err)
}
@ -243,6 +227,7 @@ func (p *Provider) loadFileConfigFromDirectory(ctx context.Context, directory st
}
configTLSMaps := make(map[*tls.Configuration]struct{})
for _, item := range fileList {
if item.IsDir() {
@ -251,13 +236,17 @@ func (p *Provider) loadFileConfigFromDirectory(ctx context.Context, directory st
return configuration, fmt.Errorf("unable to load content configuration from subdirectory %s: %v", item, err)
}
continue
} else if !strings.HasSuffix(item.Name(), ".toml") && !strings.HasSuffix(item.Name(), ".tmpl") {
}
switch strings.ToLower(filepath.Ext(item.Name())) {
case ".toml", ".yaml", ".yml":
// noop
default:
continue
}
var c *config.Configuration
c, err = p.loadFileConfig(path.Join(directory, item.Name()), true)
c, err = p.loadFileConfig(filepath.Join(directory, item.Name()), true)
if err != nil {
return configuration, err
}
@ -318,7 +307,12 @@ func (p *Provider) loadFileConfigFromDirectory(ctx context.Context, directory st
}
// CreateConfiguration creates a provider configuration from content using templating.
func (p *Provider) CreateConfiguration(tmplContent string, funcMap template.FuncMap, templateObjects interface{}) (*config.Configuration, error) {
func (p *Provider) CreateConfiguration(filename string, funcMap template.FuncMap, templateObjects interface{}) (*config.Configuration, error) {
tmplContent, err := readFile(filename)
if err != nil {
return nil, fmt.Errorf("error reading configuration file: %s - %s", filename, err)
}
var defaultFuncMap = sprig.TxtFuncMap()
defaultFuncMap["normalize"] = provider.Normalize
defaultFuncMap["split"] = strings.Split
@ -328,7 +322,7 @@ func (p *Provider) CreateConfiguration(tmplContent string, funcMap template.Func
tmpl := template.New(p.Filename).Funcs(defaultFuncMap)
_, err := tmpl.Parse(tmplContent)
_, err = tmpl.Parse(tmplContent)
if err != nil {
return nil, err
}
@ -341,14 +335,25 @@ func (p *Provider) CreateConfiguration(tmplContent string, funcMap template.Func
var renderedTemplate = buffer.String()
if p.DebugLogGeneratedTemplate {
log.Debugf("Template content: %s", tmplContent)
log.Debugf("Rendering results: %s", renderedTemplate)
logger := log.WithoutContext().WithField(log.ProviderName, providerName)
logger.Debugf("Template content: %s", tmplContent)
logger.Debugf("Rendering results: %s", renderedTemplate)
}
return p.DecodeConfiguration(renderedTemplate)
return p.decodeConfiguration(filename, renderedTemplate)
}
// DecodeConfiguration Decodes a *types.Configuration from a content.
func (p *Provider) DecodeConfiguration(content string) (*config.Configuration, error) {
func (p *Provider) DecodeConfiguration(filename string) (*config.Configuration, error) {
content, err := readFile(filename)
if err != nil {
return nil, fmt.Errorf("error reading configuration file: %s - %s", filename, err)
}
return p.decodeConfiguration(filename, content)
}
func (p *Provider) decodeConfiguration(filePath string, content string) (*config.Configuration, error) {
configuration := &config.Configuration{
HTTP: &config.HTTPConfiguration{
Routers: make(map[string]*config.Router),
@ -363,8 +368,35 @@ func (p *Provider) DecodeConfiguration(content string) (*config.Configuration, e
TLSStores: make(map[string]tls.Store),
TLSOptions: make(map[string]tls.TLS),
}
if _, err := toml.Decode(content, configuration); err != nil {
return nil, err
switch strings.ToLower(filepath.Ext(filePath)) {
case ".toml":
_, err := toml.Decode(content, configuration)
if err != nil {
return nil, err
}
case ".yml", ".yaml":
var err error
err = yaml.Unmarshal([]byte(content), configuration)
if err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("unsupported file extension: %s", filePath)
}
return configuration, nil
}
func readFile(filename string) (string, error) {
if len(filename) > 0 {
buf, err := ioutil.ReadFile(filename)
if err != nil {
return "", err
}
return string(buf), nil
}
return "", fmt.Errorf("invalid filename: %s", filename)
}

View file

@ -2,10 +2,11 @@ package file
import (
"context"
"fmt"
"io"
"io/ioutil"
"os"
"path"
"path/filepath"
"strconv"
"testing"
"time"
@ -17,14 +18,62 @@ import (
type ProvideTestCase struct {
desc string
directoryContent []string
fileContent string
traefikFileContent string
directoryPaths []string
filePath string
traefikFilePath string
expectedNumRouter int
expectedNumService int
expectedNumTLSConf int
}
func TestTLSContent(t *testing.T) {
tempDir := createTempDir(t, "testdir")
defer os.RemoveAll(tempDir)
fileTLS, err := createTempFile("./fixtures/toml/tls_file.cert", tempDir)
require.NoError(t, err)
fileConfig, err := ioutil.TempFile(tempDir, "temp*.toml")
require.NoError(t, err)
content := `
[[tls]]
[tls.certificate]
certFile = "` + fileTLS.Name() + `"
keyFile = "` + fileTLS.Name() + `"
`
_, err = fileConfig.Write([]byte(content))
require.NoError(t, err)
provider := &Provider{}
configuration, err := provider.loadFileConfig(fileConfig.Name(), true)
require.NoError(t, err)
require.Equal(t, "CONTENT", configuration.TLS[0].Certificate.CertFile.String())
require.Equal(t, "CONTENT", configuration.TLS[0].Certificate.KeyFile.String())
}
func TestErrorWhenEmptyConfig(t *testing.T) {
provider := &Provider{}
configChan := make(chan config.Message)
errorChan := make(chan struct{})
go func() {
err := provider.Provide(configChan, safe.NewPool(context.Background()))
assert.Error(t, err)
close(errorChan)
}()
timeout := time.After(time.Second)
select {
case <-configChan:
t.Fatal("We should not receive config message")
case <-timeout:
t.Fatal("timeout while waiting for config")
case <-errorChan:
}
}
func TestProvideWithoutWatch(t *testing.T) {
for _, test := range getTestCases() {
t.Run(test.desc+" without watch", func(t *testing.T) {
@ -74,21 +123,20 @@ func TestProvideWithWatch(t *testing.T) {
t.Errorf("timeout while waiting for config")
}
if len(test.fileContent) > 0 {
if err := ioutil.WriteFile(provider.Filename, []byte(test.fileContent), 0755); err != nil {
t.Error(err)
}
if len(test.filePath) > 0 {
err := copyFile(test.filePath, provider.Filename)
require.NoError(t, err)
}
if len(test.traefikFileContent) > 0 {
if err := ioutil.WriteFile(provider.TraefikFile, []byte(test.traefikFileContent), 0755); err != nil {
t.Error(err)
}
if len(test.traefikFilePath) > 0 {
err := copyFile(test.traefikFilePath, provider.TraefikFile)
require.NoError(t, err)
}
if len(test.directoryContent) > 0 {
for _, fileContent := range test.directoryContent {
createRandomFile(t, provider.Directory, fileContent)
if len(test.directoryPaths) > 0 {
for i, filePath := range test.directoryPaths {
err := copyFile(filePath, filepath.Join(provider.Directory, strconv.Itoa(i)+filepath.Ext(filePath)))
require.NoError(t, err)
}
}
@ -114,62 +162,86 @@ func TestProvideWithWatch(t *testing.T) {
}
}
func TestErrorWhenEmptyConfig(t *testing.T) {
provider := &Provider{}
configChan := make(chan config.Message)
errorChan := make(chan struct{})
go func() {
err := provider.Provide(configChan, safe.NewPool(context.Background()))
assert.Error(t, err)
close(errorChan)
}()
timeout := time.After(time.Second)
select {
case <-configChan:
t.Fatal("We should not receive config message")
case <-timeout:
t.Fatal("timeout while waiting for config")
case <-errorChan:
}
}
func getTestCases() []ProvideTestCase {
return []ProvideTestCase{
{
desc: "simple file",
fileContent: createRoutersConfiguration(3) + createServicesConfiguration(6) + createTLS(5),
filePath: "./fixtures/toml/simple_file_01.toml",
expectedNumRouter: 3,
expectedNumService: 6,
expectedNumTLSConf: 5,
},
{
desc: "simple file and a traefik file",
fileContent: createRoutersConfiguration(4) + createServicesConfiguration(8) + createTLS(4),
traefikFileContent: `
debug=true
`,
desc: "simple file yaml",
filePath: "./fixtures/yaml/simple_file_01.yml",
expectedNumRouter: 3,
expectedNumService: 6,
expectedNumTLSConf: 5,
},
{
desc: "simple file and a traefik file",
filePath: "./fixtures/toml/simple_file_02.toml",
traefikFilePath: "./fixtures/toml/simple_traefik_file_01.toml",
expectedNumRouter: 4,
expectedNumService: 8,
expectedNumTLSConf: 4,
},
{
desc: "template file",
fileContent: `
[http.routers]
{{ range $i, $e := until 20 }}
[http.routers.router{{ $e }}]
service = "application"
{{ end }}
`,
desc: "simple file and a traefik file yaml",
filePath: "./fixtures/yaml/simple_file_02.yml",
traefikFilePath: "./fixtures/yaml/simple_traefik_file_01.yml",
expectedNumRouter: 4,
expectedNumService: 8,
expectedNumTLSConf: 4,
},
{
desc: "simple traefik file",
traefikFilePath: "./fixtures/toml/simple_traefik_file_02.toml",
expectedNumRouter: 2,
expectedNumService: 3,
expectedNumTLSConf: 4,
},
{
desc: "simple traefik file yaml",
traefikFilePath: "./fixtures/yaml/simple_traefik_file_02.yml",
expectedNumRouter: 2,
expectedNumService: 3,
expectedNumTLSConf: 4,
},
{
desc: "template file",
filePath: "./fixtures/toml/template_file.toml",
expectedNumRouter: 20,
},
{
desc: "template file yaml",
filePath: "./fixtures/yaml/template_file.yml",
expectedNumRouter: 20,
},
{
desc: "simple traefik file with templating",
traefikFilePath: "./fixtures/toml/simple_traefik_file_with_templating.toml",
expectedNumRouter: 2,
expectedNumService: 3,
expectedNumTLSConf: 4,
},
{
desc: "simple directory",
directoryContent: []string{
createRoutersConfiguration(2),
createServicesConfiguration(3),
createTLS(4),
directoryPaths: []string{
"./fixtures/toml/dir01_file01.toml",
"./fixtures/toml/dir01_file02.toml",
"./fixtures/toml/dir01_file03.toml",
},
expectedNumRouter: 2,
expectedNumService: 3,
expectedNumTLSConf: 4,
},
{
desc: "simple directory yaml",
directoryPaths: []string{
"./fixtures/yaml/dir01_file01.yml",
"./fixtures/yaml/dir01_file02.yml",
"./fixtures/yaml/dir01_file03.yml",
},
expectedNumRouter: 2,
expectedNumService: 3,
@ -177,45 +249,21 @@ func getTestCases() []ProvideTestCase {
},
{
desc: "template in directory",
directoryContent: []string{
`
[http.routers]
{{ range $i, $e := until 20 }}
[http.routers.router{{ $e }}]
service = "application"
{{ end }}
`,
`
[http.services]
{{ range $i, $e := until 20 }}
[http.services.application-{{ $e }}]
[[http.services.application-{{ $e }}.servers]]
url="http://127.0.0.1"
{{ end }}
`,
directoryPaths: []string{
"./fixtures/toml/template_in_directory_file01.toml",
"./fixtures/toml/template_in_directory_file02.toml",
},
expectedNumRouter: 20,
expectedNumService: 20,
},
{
desc: "simple traefik file",
traefikFileContent: `
debug=true
[providers.file]
` + createRoutersConfiguration(2) + createServicesConfiguration(3) + createTLS(4),
expectedNumRouter: 2,
expectedNumService: 3,
expectedNumTLSConf: 4,
},
{
desc: "simple traefik file with templating",
traefikFileContent: `
temp="{{ getTag \"test\" }}"
[providers.file]
` + createRoutersConfiguration(2) + createServicesConfiguration(3) + createTLS(4),
expectedNumRouter: 2,
expectedNumService: 3,
expectedNumTLSConf: 4,
desc: "template in directory yaml",
directoryPaths: []string{
"./fixtures/yaml/template_in_directory_file01.yml",
"./fixtures/yaml/template_in_directory_file02.yml",
},
expectedNumRouter: 20,
expectedNumService: 20,
},
}
}
@ -226,30 +274,46 @@ func createProvider(t *testing.T, test ProvideTestCase, watch bool) (*Provider,
provider := &Provider{}
provider.Watch = true
if len(test.directoryContent) > 0 {
if len(test.directoryPaths) > 0 {
if !watch {
for _, fileContent := range test.directoryContent {
createRandomFile(t, tempDir, fileContent)
for _, filePath := range test.directoryPaths {
var err error
_, err = createTempFile(filePath, tempDir)
require.NoError(t, err)
}
}
provider.Directory = tempDir
}
if len(test.fileContent) > 0 {
if watch {
test.fileContent = ""
}
filename := createRandomFile(t, tempDir, test.fileContent)
provider.Filename = filename.Name()
if len(test.filePath) > 0 {
var file *os.File
if watch {
var err error
file, err = ioutil.TempFile(tempDir, "temp*"+filepath.Ext(test.filePath))
require.NoError(t, err)
} else {
var err error
file, err = createTempFile(test.filePath, tempDir)
require.NoError(t, err)
}
provider.Filename = file.Name()
}
if len(test.traefikFileContent) > 0 {
if len(test.traefikFilePath) > 0 {
var file *os.File
if watch {
test.traefikFileContent = ""
var err error
file, err = ioutil.TempFile(tempDir, "temp*"+filepath.Ext(test.traefikFilePath))
require.NoError(t, err)
} else {
var err error
file, err = createTempFile(test.traefikFilePath, tempDir)
require.NoError(t, err)
}
filename := createRandomFile(t, tempDir, test.traefikFileContent)
provider.TraefikFile = filename.Name()
provider.TraefikFile = file.Name()
}
return provider, func() {
@ -257,39 +321,10 @@ func createProvider(t *testing.T, test ProvideTestCase, watch bool) (*Provider,
}
}
// createRandomFile Helper
func createRandomFile(t *testing.T, tempDir string, contents ...string) *os.File {
return createFile(t, tempDir, fmt.Sprintf("temp%d.toml", time.Now().UnixNano()), contents...)
}
// createFile Helper
func createFile(t *testing.T, tempDir string, name string, contents ...string) *os.File {
t.Helper()
fileName := path.Join(tempDir, name)
tempFile, err := os.Create(fileName)
if err != nil {
t.Fatal(err)
}
for _, content := range contents {
_, err = tempFile.WriteString(content)
if err != nil {
t.Fatal(err)
}
}
err = tempFile.Close()
if err != nil {
t.Fatal(err)
}
return tempFile
}
// createTempDir Helper
func createTempDir(t *testing.T, dir string) string {
t.Helper()
d, err := ioutil.TempDir("", dir)
if err != nil {
t.Fatal(err)
@ -297,62 +332,36 @@ func createTempDir(t *testing.T, dir string) string {
return d
}
// createRoutersConfiguration Helper
func createRoutersConfiguration(n int) string {
conf := "[http.routers]\n"
for i := 1; i <= n; i++ {
conf += fmt.Sprintf(`
[http.routers."router%[1]d"]
service = "application-%[1]d"
`, i)
func copyFile(srcPath, dstPath string) error {
dst, err := os.OpenFile(dstPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return err
}
return conf
}
defer dst.Close()
// createServicesConfiguration Helper
func createServicesConfiguration(n int) string {
conf := "[http.services]\n"
for i := 1; i <= n; i++ {
conf += fmt.Sprintf(`
[http.services.application-%[1]d.loadbalancer]
[[http.services.application-%[1]d.loadbalancer.servers]]
url = "http://172.17.0.%[1]d:80"
`, i)
src, err := os.Open(srcPath)
if err != nil {
return err
}
return conf
defer src.Close()
_, err = io.Copy(dst, src)
return err
}
// createTLS Helper
func createTLS(n int) string {
var conf string
for i := 1; i <= n; i++ {
conf += fmt.Sprintf(`[[TLS]]
EntryPoints = ["https"]
[TLS.Certificate]
CertFile = "integration/fixtures/https/snitest%[1]d.com.cert"
KeyFile = "integration/fixtures/https/snitest%[1]d.com.key"
`, i)
func createTempFile(srcPath, tempDir string) (*os.File, error) {
file, err := ioutil.TempFile(tempDir, "temp*"+filepath.Ext(srcPath))
if err != nil {
return nil, err
}
return conf
}
func TestTLSContent(t *testing.T) {
tempDir := createTempDir(t, "testdir")
defer os.RemoveAll(tempDir)
fileTLS := createRandomFile(t, tempDir, "CONTENT")
fileConfig := createRandomFile(t, tempDir, `
[[tls]]
entryPoints = ["https"]
[tls.certificate]
certFile = "`+fileTLS.Name()+`"
keyFile = "`+fileTLS.Name()+`"
`)
provider := &Provider{}
configuration, err := provider.loadFileConfig(fileConfig.Name(), true)
require.NoError(t, err)
require.Equal(t, "CONTENT", configuration.TLS[0].Certificate.CertFile.String())
require.Equal(t, "CONTENT", configuration.TLS[0].Certificate.KeyFile.String())
defer file.Close()
src, err := os.Open(srcPath)
if err != nil {
return nil, err
}
defer src.Close()
_, err = io.Copy(file, src)
return file, err
}

View file

@ -0,0 +1,7 @@
[http.routers]
[http.routers."router1"]
service = "application-1"
[http.routers."router2"]
service = "application-2"

View file

@ -0,0 +1,13 @@
[http.services]
[http.services.application-1.loadbalancer]
[[http.services.application-1.loadbalancer.servers]]
url = "http://172.17.0.1:80"
[http.services.application-2.loadbalancer]
[[http.services.application-2.loadbalancer.servers]]
url = "http://172.17.0.2:80"
[http.services.application-3.loadbalancer]
[[http.services.application-3.loadbalancer.servers]]
url = "http://172.17.0.3:80"

View file

@ -0,0 +1,16 @@
[[TLS]]
[TLS.Certificate]
CertFile = "integration/fixtures/https/snitest1.com.cert"
KeyFile = "integration/fixtures/https/snitest1.com.key"
[[TLS]]
[TLS.Certificate]
CertFile = "integration/fixtures/https/snitest2.com.cert"
KeyFile = "integration/fixtures/https/snitest2.com.key"
[[TLS]]
[TLS.Certificate]
CertFile = "integration/fixtures/https/snitest3.com.cert"
KeyFile = "integration/fixtures/https/snitest3.com.key"
[[TLS]]
[TLS.Certificate]
CertFile = "integration/fixtures/https/snitest4.com.cert"
KeyFile = "integration/fixtures/https/snitest4.com.key"

View file

@ -0,0 +1,55 @@
[http.routers]
[http.routers."router1"]
service = "application-1"
[http.routers."router2"]
service = "application-2"
[http.routers."router3"]
service = "application-3"
[http.services]
[http.services.application-1.loadbalancer]
[[http.services.application-1.loadbalancer.servers]]
url = "http://172.17.0.1:80"
[http.services.application-2.loadbalancer]
[[http.services.application-2.loadbalancer.servers]]
url = "http://172.17.0.2:80"
[http.services.application-3.loadbalancer]
[[http.services.application-3.loadbalancer.servers]]
url = "http://172.17.0.3:80"
[http.services.application-4.loadbalancer]
[[http.services.application-4.loadbalancer.servers]]
url = "http://172.17.0.4:80"
[http.services.application-5.loadbalancer]
[[http.services.application-5.loadbalancer.servers]]
url = "http://172.17.0.5:80"
[http.services.application-6.loadbalancer]
[[http.services.application-6.loadbalancer.servers]]
url = "http://172.17.0.6:80"
[[TLS]]
[TLS.Certificate]
CertFile = "integration/fixtures/https/snitest1.com.cert"
KeyFile = "integration/fixtures/https/snitest1.com.key"
[[TLS]]
[TLS.Certificate]
CertFile = "integration/fixtures/https/snitest2.com.cert"
KeyFile = "integration/fixtures/https/snitest2.com.key"
[[TLS]]
[TLS.Certificate]
CertFile = "integration/fixtures/https/snitest3.com.cert"
KeyFile = "integration/fixtures/https/snitest3.com.key"
[[TLS]]
[TLS.Certificate]
CertFile = "integration/fixtures/https/snitest4.com.cert"
KeyFile = "integration/fixtures/https/snitest4.com.key"
[[TLS]]
[TLS.Certificate]
CertFile = "integration/fixtures/https/snitest5.com.cert"
KeyFile = "integration/fixtures/https/snitest5.com.key"

View file

@ -0,0 +1,62 @@
[http.routers]
[http.routers."router1"]
service = "application-1"
[http.routers."router2"]
service = "application-2"
[http.routers."router3"]
service = "application-3"
[http.routers."router4"]
service = "application-4"
[http.services]
[http.services.application-1.loadbalancer]
[[http.services.application-1.loadbalancer.servers]]
url = "http://172.17.0.1:80"
[http.services.application-2.loadbalancer]
[[http.services.application-2.loadbalancer.servers]]
url = "http://172.17.0.2:80"
[http.services.application-3.loadbalancer]
[[http.services.application-3.loadbalancer.servers]]
url = "http://172.17.0.3:80"
[http.services.application-4.loadbalancer]
[[http.services.application-4.loadbalancer.servers]]
url = "http://172.17.0.4:80"
[http.services.application-5.loadbalancer]
[[http.services.application-5.loadbalancer.servers]]
url = "http://172.17.0.5:80"
[http.services.application-6.loadbalancer]
[[http.services.application-6.loadbalancer.servers]]
url = "http://172.17.0.6:80"
[http.services.application-7.loadbalancer]
[[http.services.application-7.loadbalancer.servers]]
url = "http://172.17.0.7:80"
[http.services.application-8.loadbalancer]
[[http.services.application-8.loadbalancer.servers]]
url = "http://172.17.0.8:80"
[[TLS]]
[TLS.Certificate]
CertFile = "integration/fixtures/https/snitest1.com.cert"
KeyFile = "integration/fixtures/https/snitest1.com.key"
[[TLS]]
[TLS.Certificate]
CertFile = "integration/fixtures/https/snitest2.com.cert"
KeyFile = "integration/fixtures/https/snitest2.com.key"
[[TLS]]
[TLS.Certificate]
CertFile = "integration/fixtures/https/snitest3.com.cert"
KeyFile = "integration/fixtures/https/snitest3.com.key"
[[TLS]]
[TLS.Certificate]
CertFile = "integration/fixtures/https/snitest4.com.cert"
KeyFile = "integration/fixtures/https/snitest4.com.key"

View file

@ -0,0 +1,3 @@
[log]
level = "DEBUG"

View file

@ -0,0 +1,38 @@
[providers.file]
[http.routers]
[http.routers."router1"]
service = "application-1"
[http.routers."router2"]
service = "application-2"
[http.services]
[http.services.application-1.loadbalancer]
[[http.services.application-1.loadbalancer.servers]]
url = "http://172.17.0.1:80"
[http.services.application-2.loadbalancer]
[[http.services.application-2.loadbalancer.servers]]
url = "http://172.17.0.2:80"
[http.services.application-3.loadbalancer]
[[http.services.application-3.loadbalancer.servers]]
url = "http://172.17.0.3:80"
[[TLS]]
[TLS.Certificate]
CertFile = "integration/fixtures/https/snitest1.com.cert"
KeyFile = "integration/fixtures/https/snitest1.com.key"
[[TLS]]
[TLS.Certificate]
CertFile = "integration/fixtures/https/snitest2.com.cert"
KeyFile = "integration/fixtures/https/snitest2.com.key"
[[TLS]]
[TLS.Certificate]
CertFile = "integration/fixtures/https/snitest3.com.cert"
KeyFile = "integration/fixtures/https/snitest3.com.key"
[[TLS]]
[TLS.Certificate]
CertFile = "integration/fixtures/https/snitest4.com.cert"
KeyFile = "integration/fixtures/https/snitest4.com.key"

View file

@ -0,0 +1,39 @@
temp="{{ getTag \"test\" }}"
[providers.file]
[http.routers]
[http.routers."router1"]
service = "application-1"
[http.routers."router2"]
service = "application-2"
[http.services]
[http.services.application-1.loadbalancer]
[[http.services.application-1.loadbalancer.servers]]
url = "http://172.17.0.1:80"
[http.services.application-2.loadbalancer]
[[http.services.application-2.loadbalancer.servers]]
url = "http://172.17.0.2:80"
[http.services.application-3.loadbalancer]
[[http.services.application-3.loadbalancer.servers]]
url = "http://172.17.0.3:80"
[[TLS]]
[TLS.Certificate]
CertFile = "integration/fixtures/https/snitest1.com.cert"
KeyFile = "integration/fixtures/https/snitest1.com.key"
[[TLS]]
[TLS.Certificate]
CertFile = "integration/fixtures/https/snitest2.com.cert"
KeyFile = "integration/fixtures/https/snitest2.com.key"
[[TLS]]
[TLS.Certificate]
CertFile = "integration/fixtures/https/snitest3.com.cert"
KeyFile = "integration/fixtures/https/snitest3.com.key"
[[TLS]]
[TLS.Certificate]
CertFile = "integration/fixtures/https/snitest4.com.cert"
KeyFile = "integration/fixtures/https/snitest4.com.key"

View file

@ -0,0 +1,6 @@
[http.routers]
{{ range $i, $e := until 20 }}
[http.routers.router{{ $e }}]
service = "application"
{{ end }}

View file

@ -0,0 +1,5 @@
[http.routers]
{{ range $i, $e := until 20 }}
[http.routers.router{{ $e }}]
service = "application"
{{ end }}

View file

@ -0,0 +1,6 @@
[http.services]
{{ range $i, $e := until 20 }}
[http.services.application-{{ $e }}]
[[http.services.application-{{ $e }}.servers]]
url="http://127.0.0.1"
{{ end }}

View file

@ -0,0 +1 @@
CONTENT

View file

@ -0,0 +1,6 @@
http:
routers:
router1:
service: application-1
router2:
service: application-2

View file

@ -0,0 +1,14 @@
http:
services:
application-1:
loadbalancer:
servers:
- url: 'http://172.17.0.1:80'
application-2:
loadbalancer:
servers:
- url: 'http://172.17.0.2:80'
application-3:
loadbalancer:
servers:
- url: 'http://172.17.0.3:80'

View file

@ -0,0 +1,13 @@
tls:
- certificate:
certfile: integration/fixtures/https/snitest1.com.cert
keyfile: integration/fixtures/https/snitest1.com.key
- certificate:
certfile: integration/fixtures/https/snitest2.com.cert
keyfile: integration/fixtures/https/snitest2.com.key
- certificate:
certfile: integration/fixtures/https/snitest3.com.cert
keyfile: integration/fixtures/https/snitest3.com.key
- certificate:
certfile: integration/fixtures/https/snitest4.com.cert
keyfile: integration/fixtures/https/snitest4.com.key

View file

@ -0,0 +1,50 @@
http:
routers:
router1:
service: application-1
router2:
service: application-2
router3:
service: application-3
services:
application-1:
loadbalancer:
servers:
- url: 'http://172.17.0.1:80'
application-2:
loadbalancer:
servers:
- url: 'http://172.17.0.2:80'
application-3:
loadbalancer:
servers:
- url: 'http://172.17.0.3:80'
application-4:
loadbalancer:
servers:
- url: 'http://172.17.0.4:80'
application-5:
loadbalancer:
servers:
- url: 'http://172.17.0.5:80'
application-6:
loadbalancer:
servers:
- url: 'http://172.17.0.6:80'
tls:
- certificate:
certfile: integration/fixtures/https/snitest1.com.cert
keyfile: integration/fixtures/https/snitest1.com.key
- certificate:
certfile: integration/fixtures/https/snitest2.com.cert
keyfile: integration/fixtures/https/snitest2.com.key
- certificate:
certfile: integration/fixtures/https/snitest3.com.cert
keyfile: integration/fixtures/https/snitest3.com.key
- certificate:
certfile: integration/fixtures/https/snitest4.com.cert
keyfile: integration/fixtures/https/snitest4.com.key
- certificate:
certfile: integration/fixtures/https/snitest5.com.cert
keyfile: integration/fixtures/https/snitest5.com.key

View file

@ -0,0 +1,58 @@
http:
routers:
router1:
service: application-1
router2:
service: application-2
router3:
service: application-3
router4:
service: application-4
services:
application-1:
loadbalancer:
servers:
- url: 'http://172.17.0.1:80'
application-2:
loadbalancer:
servers:
- url: 'http://172.17.0.2:80'
application-3:
loadbalancer:
servers:
- url: 'http://172.17.0.3:80'
application-4:
loadbalancer:
servers:
- url: 'http://172.17.0.4:80'
application-5:
loadbalancer:
servers:
- url: 'http://172.17.0.5:80'
application-6:
loadbalancer:
servers:
- url: 'http://172.17.0.6:80'
application-7:
loadbalancer:
servers:
- url: 'http://172.17.0.7:80'
application-8:
loadbalancer:
servers:
- url: 'http://172.17.0.8:80'
tls:
- certificate:
certfile: integration/fixtures/https/snitest1.com.cert
keyfile: integration/fixtures/https/snitest1.com.key
- certificate:
certfile: integration/fixtures/https/snitest2.com.cert
keyfile: integration/fixtures/https/snitest2.com.key
- certificate:
certfile: integration/fixtures/https/snitest3.com.cert
keyfile: integration/fixtures/https/snitest3.com.key
- certificate:
certfile: integration/fixtures/https/snitest4.com.cert
keyfile: integration/fixtures/https/snitest4.com.key

View file

@ -0,0 +1,2 @@
log:
level: DEBUG

View file

@ -0,0 +1,35 @@
providers:
file: {}
http:
routers:
router1:
service: application-1
router2:
service: application-2
services:
application-1:
loadbalancer:
servers:
- url: 'http://172.17.0.1:80'
application-2:
loadbalancer:
servers:
- url: 'http://172.17.0.2:80'
application-3:
loadbalancer:
servers:
- url: 'http://172.17.0.3:80'
tls:
- certificate:
certfile: integration/fixtures/https/snitest1.com.cert
keyfile: integration/fixtures/https/snitest1.com.key
- certificate:
certfile: integration/fixtures/https/snitest2.com.cert
keyfile: integration/fixtures/https/snitest2.com.key
- certificate:
certfile: integration/fixtures/https/snitest3.com.cert
keyfile: integration/fixtures/https/snitest3.com.key
- certificate:
certfile: integration/fixtures/https/snitest4.com.cert
keyfile: integration/fixtures/https/snitest4.com.key

View file

@ -0,0 +1,6 @@
http:
{{ range $i, $e := until 20 }}
routers:
router{{ $e }}:
service: application-1
{{ end }}

View file

@ -0,0 +1,6 @@
http:
{{ range $i, $e := until 20 }}
routers:
router{{ $e }}:
service: application-1
{{ end }}

View file

@ -0,0 +1,8 @@
http:
services:
{{ range $i, $e := until 20 }}
application-{{ $e }}:
loadbalancer:
servers:
- url: 'http://127.0.0.1'
{{ end }}

View file

@ -0,0 +1 @@
CONTENT