1
0
Fork 0

Move dynamic config into a dedicated package.

This commit is contained in:
Ludovic Fernandez 2019-07-10 09:26:04 +02:00 committed by Traefiker Bot
parent 09cc1161c9
commit c8bf8e896a
102 changed files with 3170 additions and 3166 deletions

View file

@ -0,0 +1,36 @@
package dynamic
import (
"github.com/containous/traefik/pkg/tls"
)
// +k8s:deepcopy-gen=true
// Message holds configuration information exchanged between parts of traefik.
type Message struct {
ProviderName string
Configuration *Configuration
}
// +k8s:deepcopy-gen=true
// Configurations is for currentConfigurations Map.
type Configurations map[string]*Configuration
// +k8s:deepcopy-gen=true
// Configuration is the root of the dynamic configuration
type Configuration struct {
HTTP *HTTPConfiguration `json:"http,omitempty" toml:"http,omitempty" yaml:"http,omitempty"`
TCP *TCPConfiguration `json:"tcp,omitempty" toml:"tcp,omitempty" yaml:"tcp,omitempty"`
TLS *TLSConfiguration `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty"`
}
// +k8s:deepcopy-gen=true
// TLSConfiguration contains all the configuration parameters of a TLS connection.
type TLSConfiguration struct {
Certificates []*tls.CertAndStores `json:"-" toml:"certificates,omitempty" yaml:"certificates,omitempty" label:"-"`
Options map[string]tls.Options `json:"options,omitempty" toml:"options,omitempty" yaml:"options,omitempty"`
Stores map[string]tls.Store `json:"stores,omitempty" toml:"stores,omitempty" yaml:"stores,omitempty"`
}

View file

@ -0,0 +1,37 @@
package dynamic
import (
"reflect"
"testing"
"github.com/BurntSushi/toml"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestDeepCopy(t *testing.T) {
cfg := &Configuration{}
_, err := toml.DecodeFile("./fixtures/sample.toml", &cfg)
require.NoError(t, err)
cfgCopy := cfg
assert.Equal(t, reflect.ValueOf(cfgCopy), reflect.ValueOf(cfg))
assert.Equal(t, reflect.ValueOf(cfgCopy), reflect.ValueOf(cfg))
assert.Equal(t, cfgCopy, cfg)
cfgDeepCopy := cfg.DeepCopy()
assert.NotEqual(t, reflect.ValueOf(cfgDeepCopy), reflect.ValueOf(cfg))
assert.Equal(t, reflect.TypeOf(cfgDeepCopy), reflect.TypeOf(cfg))
assert.Equal(t, cfgDeepCopy, cfg)
// Update cfg
cfg.HTTP.Routers["powpow"] = &Router{}
assert.Equal(t, reflect.ValueOf(cfgCopy), reflect.ValueOf(cfg))
assert.Equal(t, reflect.ValueOf(cfgCopy), reflect.ValueOf(cfg))
assert.Equal(t, cfgCopy, cfg)
assert.NotEqual(t, reflect.ValueOf(cfgDeepCopy), reflect.ValueOf(cfg))
assert.Equal(t, reflect.TypeOf(cfgDeepCopy), reflect.TypeOf(cfg))
assert.NotEqual(t, cfgDeepCopy, cfg)
}

View file

@ -0,0 +1,481 @@
[global]
checkNewVersion = true
sendAnonymousUsage = true
[serversTransport]
insecureSkipVerify = true
rootCAs = ["foobar", "foobar"]
maxIdleConnsPerHost = 42
[serversTransport.forwardingTimeouts]
dialTimeout = 42
responseHeaderTimeout = 42
idleConnTimeout = 42
[entryPoints]
[entryPoints.EntryPoint0]
address = "foobar"
[entryPoints.EntryPoint0.transport]
[entryPoints.EntryPoint0.transport.lifeCycle]
requestAcceptGraceTimeout = 42
graceTimeOut = 42
[entryPoints.EntryPoint0.transport.respondingTimeouts]
readTimeout = 42
writeTimeout = 42
idleTimeout = 42
[entryPoints.EntryPoint0.proxyProtocol]
insecure = true
trustedIPs = ["foobar", "foobar"]
[entryPoints.EntryPoint0.forwardedHeaders]
insecure = true
trustedIPs = ["foobar", "foobar"]
[providers]
providersThrottleDuration = 42
[providers.docker]
constraints = "foobar"
watch = true
endpoint = "foobar"
defaultRule = "foobar"
exposedByDefault = true
useBindPortIP = true
swarmMode = true
network = "foobar"
swarmModeRefreshSeconds = 42
[providers.docker.tls]
ca = "foobar"
caOptional = true
cert = "foobar"
key = "foobar"
insecureSkipVerify = true
[providers.file]
directory = "foobar"
watch = true
filename = "foobar"
debugLogGeneratedTemplate = true
traefikFile = "foobar"
[providers.marathon]
constraints = "foobar"
trace = true
watch = true
endpoint = "foobar"
defaultRule = "foobar"
exposedByDefault = true
dcosToken = "foobar"
dialerTimeout = 42
responseHeaderTimeout = 42
tlsHandshakeTimeout = 42
keepAlive = 42
forceTaskHostname = true
respectReadinessChecks = true
[providers.marathon.tls]
ca = "foobar"
caOptional = true
cert = "foobar"
key = "foobar"
insecureSkipVerify = true
[providers.marathon.basic]
httpBasicAuthUser = "foobar"
httpBasicPassword = "foobar"
[providers.kubernetesIngress]
endpoint = "foobar"
token = "foobar"
certAuthFilePath = "foobar"
disablePassHostHeaders = true
namespaces = ["foobar", "foobar"]
labelSelector = "foobar"
ingressClass = "foobar"
[providers.kubernetesIngress.ingressEndpoint]
ip = "foobar"
hostname = "foobar"
publishedService = "foobar"
[providers.kubernetesCRD]
endpoint = "foobar"
token = "foobar"
certAuthFilePath = "foobar"
disablePassHostHeaders = true
namespaces = ["foobar", "foobar"]
labelSelector = "foobar"
ingressClass = "foobar"
[providers.rest]
entryPoint = "foobar"
[providers.rancher]
constraints = "foobar"
watch = true
defaultRule = "foobar"
exposedByDefault = true
enableServiceHealthFilter = true
refreshSeconds = 42
intervalPoll = true
prefix = "foobar"
[api]
entryPoint = "foobar"
dashboard = true
middlewares = ["foobar", "foobar"]
[api.statistics]
recentErrors = 42
[metrics]
[metrics.prometheus]
buckets = [42.0, 42.0]
entryPoint = "foobar"
middlewares = ["foobar", "foobar"]
[metrics.dataDog]
address = "foobar"
pushInterval = "10s"
[metrics.statsD]
address = "foobar"
pushInterval = "10s"
[metrics.influxDB]
address = "foobar"
protocol = "foobar"
pushInterval = "10s"
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"
bufferingSize = 42
[accessLog.filters]
statusCodes = ["foobar", "foobar"]
retryAttempts = true
minDuration = 42
[accessLog.fields]
defaultMode = "foobar"
[accessLog.fields.names]
name0 = "foobar"
name1 = "foobar"
[accessLog.fields.headers]
defaultMode = "foobar"
[accessLog.fields.headers.names]
name0 = "foobar"
name1 = "foobar"
[tracing]
serviceName = "foobar"
spanNameLimit = 42
[tracing.jaeger]
samplingServerURL = "foobar"
samplingType = "foobar"
samplingParam = 42.0
localAgentHostPort = "foobar"
gen128Bit = true
propagation = "foobar"
traceContextHeaderName = "foobar"
[tracing.zipkin]
httpEndpoint = "foobar"
sameSpan = true
id128Bit = true
debug = true
sampleRate = 42.0
[tracing.dataDog]
localAgentHostPort = "foobar"
globalTag = "foobar"
debug = true
prioritySampling = true
traceIDHeaderName = "foobar"
parentIDHeaderName = "foobar"
samplingPriorityHeaderName = "foobar"
bagagePrefixHeaderName = "foobar"
[tracing.instana]
localAgentHost = "foobar"
localAgentPort = 42
logLevel = "foobar"
[tracing.haystack]
localAgentHost = "foobar"
localAgentPort = 42
globalTag = "foobar"
traceIDHeaderName = "foobar"
parentIDHeaderName = "foobar"
spanIDHeaderName = "foobar"
[hostResolver]
cnameFlattening = true
resolvConfig = "foobar"
resolvDepth = 42
[acme]
email = "foobar"
acmeLogging = true
caServer = "foobar"
storage = "foobar"
entryPoint = "foobar"
keyType = "foobar"
onHostRule = true
[acme.dnsChallenge]
provider = "foobar"
delayBeforeCheck = 42
resolvers = ["foobar", "foobar"]
disablePropagationCheck = true
[acme.httpChallenge]
entryPoint = "foobar"
[acme.tlsChallenge]
[[acme.domains]]
main = "foobar"
sans = ["foobar", "foobar"]
[[acme.domains]]
main = "foobar"
sans = ["foobar", "foobar"]
## Dynamic configuration
[http]
[http.routers]
[http.routers.Router0]
entryPoints = ["foobar", "foobar"]
middlewares = ["foobar", "foobar"]
service = "foobar"
rule = "foobar"
priority = 42
[http.routers.Router0.tls]
[http.middlewares]
[http.middlewares.Middleware0]
[http.middlewares.Middleware0.addPrefix]
prefix = "foobar"
[http.middlewares.Middleware1]
[http.middlewares.Middleware1.stripPrefix]
prefixes = ["foobar", "foobar"]
[http.middlewares.Middleware10]
[http.middlewares.Middleware10.rateLimit]
extractorFunc = "foobar"
[http.middlewares.Middleware10.rateLimit.rateSet]
[http.middlewares.Middleware10.rateLimit.rateSet.Rate0]
period = 42000000000
average = 42
burst = 42
[http.middlewares.Middleware10.rateLimit.rateSet.Rate1]
period = 42000000000
average = 42
burst = 42
[http.middlewares.Middleware11]
[http.middlewares.Middleware11.redirectRegex]
regex = "foobar"
replacement = "foobar"
permanent = true
[http.middlewares.Middleware12]
[http.middlewares.Middleware12.redirectScheme]
scheme = "foobar"
port = "foobar"
permanent = true
[http.middlewares.Middleware13]
[http.middlewares.Middleware13.basicAuth]
users = ["foobar", "foobar"]
usersFile = "foobar"
realm = "foobar"
removeHeader = true
headerField = "foobar"
[http.middlewares.Middleware14]
[http.middlewares.Middleware14.digestAuth]
users = ["foobar", "foobar"]
usersFile = "foobar"
removeHeader = true
realm = "foobar"
headerField = "foobar"
[http.middlewares.Middleware15]
[http.middlewares.Middleware15.forwardAuth]
address = "foobar"
trustForwardHeader = true
authResponseHeaders = ["foobar", "foobar"]
[http.middlewares.Middleware15.forwardAuth.tls]
ca = "foobar"
caOptional = true
cert = "foobar"
key = "foobar"
insecureSkipVerify = true
[http.middlewares.Middleware16]
[http.middlewares.Middleware16.maxConn]
amount = 42
extractorFunc = "foobar"
[http.middlewares.Middleware17]
[http.middlewares.Middleware17.buffering]
maxRequestBodyBytes = 42
memRequestBodyBytes = 42
maxResponseBodyBytes = 42
memResponseBodyBytes = 42
retryExpression = "foobar"
[http.middlewares.Middleware18]
[http.middlewares.Middleware18.circuitBreaker]
expression = "foobar"
[http.middlewares.Middleware19]
[http.middlewares.Middleware19.compress]
[http.middlewares.Middleware2]
[http.middlewares.Middleware2.stripPrefixRegex]
regex = ["foobar", "foobar"]
[http.middlewares.Middleware20]
[http.middlewares.Middleware20.passTLSClientCert]
pem = true
[http.middlewares.Middleware20.passTLSClientCert.info]
notAfter = true
notBefore = true
sans = true
[http.middlewares.Middleware20.passTLSClientCert.info.subject]
country = true
province = true
locality = true
organization = true
commonName = true
serialNumber = true
domainComponent = true
[http.middlewares.Middleware20.passTLSClientCert.info.issuer]
country = true
province = true
locality = true
organization = true
commonName = true
serialNumber = true
domainComponent = true
[http.middlewares.Middleware21]
[http.middlewares.Middleware21.retry]
regex = 0
[http.middlewares.Middleware3]
[http.middlewares.Middleware3.replacePath]
path = "foobar"
[http.middlewares.Middleware4]
[http.middlewares.Middleware4.replacePathRegex]
regex = "foobar"
replacement = "foobar"
[http.middlewares.Middleware5]
[http.middlewares.Middleware5.chain]
middlewares = ["foobar", "foobar"]
[http.middlewares.Middleware6]
[http.middlewares.Middleware6.ipWhiteList]
sourceRange = ["foobar", "foobar"]
[http.middlewares.Middleware7]
[http.middlewares.Middleware7.ipWhiteList]
[http.middlewares.Middleware7.ipWhiteList.ipStrategy]
depth = 42
excludedIPs = ["foobar", "foobar"]
[http.middlewares.Middleware8]
[http.middlewares.Middleware8.headers]
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"
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
[http.middlewares.Middleware8.headers.customRequestHeaders]
name0 = "foobar"
name1 = "foobar"
[http.middlewares.Middleware8.headers.customResponseHeaders]
name0 = "foobar"
name1 = "foobar"
[http.middlewares.Middleware8.headers.sslProxyHeaders]
name0 = "foobar"
name1 = "foobar"
[http.middlewares.Middleware9]
[http.middlewares.Middleware9.errors]
status = ["foobar", "foobar"]
service = "foobar"
query = "foobar"
[http.services]
[http.services.Service0]
[http.services.Service0.loadBalancer]
passHostHeader = true
[http.services.Service0.loadBalancer.stickiness]
cookieName = "foobar"
[[http.services.Service0.loadBalancer.servers]]
url = "foobar"
[[http.services.Service0.loadBalancer.servers]]
url = "foobar"
[http.services.Service0.loadBalancer.healthCheck]
scheme = "foobar"
path = "foobar"
port = 42
interval = "foobar"
timeout = "foobar"
hostname = "foobar"
[http.services.Service0.loadBalancer.healthCheck.headers]
name0 = "foobar"
name1 = "foobar"
[http.services.Service0.loadBalancer.responseForwarding]
flushInterval = "foobar"
[tcp]
[tcp.routers]
[tcp.routers.TCPRouter0]
entryPoints = ["foobar", "foobar"]
service = "foobar"
rule = "foobar"
[tcp.routers.TCPRouter0.tls]
passthrough = true
[tcp.services]
[tcp.services.TCPService0]
[tcp.services.TCPService0.loadBalancer]
[[tcp.services.TCPService0.loadBalancer.servers]]
address = "foobar"
[[tcp.services.TCPService0.loadBalancer.servers]]
address = "foobar"
[tls]
[[tls.Certificates]]
certFile = "foobar"
keyFile = "foobar"
stores = ["foobar", "foobar"]
[[tls.Certificates]]
certFile = "foobar"
keyFile = "foobar"
stores = ["foobar", "foobar"]
[tls.options]
[tls.options.TLS0]
minVersion = "foobar"
cipherSuites = ["foobar", "foobar"]
sniStrict = true
[tls.options.TLS0.clientCA]
files = ["foobar", "foobar"]
optional = true
[tls.options.TLS1]
minVersion = "foobar"
cipherSuites = ["foobar", "foobar"]
sniStrict = true
[tls.options.TLS1.clientCA]
files = ["foobar", "foobar"]
optional = true
[tls.stores]
[tls.stores.Store0]
[tls.stores.Store0.defaultCertificate]
certFile = "foobar"
keyFile = "foobar"
[tls.stores.Store1]
[tls.stores.Store1.defaultCertificate]
certFile = "foobar"
keyFile = "foobar"

View file

@ -0,0 +1,116 @@
package dynamic
import "reflect"
// +k8s:deepcopy-gen=true
// HTTPConfiguration contains all the HTTP configuration parameters.
type HTTPConfiguration struct {
Routers map[string]*Router `json:"routers,omitempty" toml:"routers,omitempty" yaml:"routers,omitempty"`
Middlewares map[string]*Middleware `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty"`
Services map[string]*Service `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty"`
}
// +k8s:deepcopy-gen=true
// Service holds a service configuration (can only be of one type at the same time).
type Service struct {
LoadBalancer *LoadBalancerService `json:"loadBalancer,omitempty" toml:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty"`
}
// +k8s:deepcopy-gen=true
// Router holds the router configuration.
type Router struct {
EntryPoints []string `json:"entryPoints,omitempty" toml:"entryPoints,omitempty" yaml:"entryPoints,omitempty"`
Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty"`
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty"`
Rule string `json:"rule,omitempty" toml:"rule,omitempty" yaml:"rule,omitempty"`
Priority int `json:"priority,omitempty" toml:"priority,omitempty,omitzero" yaml:"priority,omitempty"`
TLS *RouterTLSConfig `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty"`
}
// +k8s:deepcopy-gen=true
// RouterTLSConfig holds the TLS configuration for a router
type RouterTLSConfig struct {
Options string `json:"options,omitempty" toml:"options,omitempty" yaml:"options,omitempty"`
}
// +k8s:deepcopy-gen=true
// LoadBalancerService holds the LoadBalancerService configuration.
type LoadBalancerService struct {
Stickiness *Stickiness `json:"stickiness,omitempty" toml:"stickiness,omitempty" yaml:"stickiness,omitempty" label:"allowEmpty"`
Servers []Server `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server"`
HealthCheck *HealthCheck `json:"healthCheck,omitempty" toml:"healthCheck,omitempty" yaml:"healthCheck,omitempty"`
PassHostHeader bool `json:"passHostHeader" toml:"passHostHeader" yaml:"passHostHeader"`
ResponseForwarding *ResponseForwarding `json:"responseForwarding,omitempty" toml:"responseForwarding,omitempty" yaml:"responseForwarding,omitempty"`
}
// Mergeable tells if the given service is mergeable.
func (l *LoadBalancerService) Mergeable(loadBalancer *LoadBalancerService) bool {
savedServers := l.Servers
defer func() {
l.Servers = savedServers
}()
l.Servers = nil
savedServersLB := loadBalancer.Servers
defer func() {
loadBalancer.Servers = savedServersLB
}()
loadBalancer.Servers = nil
return reflect.DeepEqual(l, loadBalancer)
}
// SetDefaults Default values for a LoadBalancerService.
func (l *LoadBalancerService) SetDefaults() {
l.PassHostHeader = true
}
// +k8s:deepcopy-gen=true
// ResponseForwarding holds configuration for the forward of the response.
type ResponseForwarding struct {
FlushInterval string `json:"flushInterval,omitempty" toml:"flushInterval,omitempty" yaml:"flushInterval,omitempty"`
}
// +k8s:deepcopy-gen=true
// Stickiness holds the stickiness configuration.
type Stickiness struct {
CookieName string `json:"cookieName,omitempty" toml:"cookieName,omitempty" yaml:"cookieName,omitempty"`
SecureCookie bool `json:"secureCookie,omitempty" toml:"secureCookie,omitempty" yaml:"secureCookie,omitempty"`
HTTPOnlyCookie bool `json:"httpOnlyCookie,omitempty" toml:"httpOnlyCookie,omitempty" yaml:"httpOnlyCookie,omitempty"`
}
// +k8s:deepcopy-gen=true
// Server holds the server configuration.
type Server struct {
URL string `json:"url,omitempty" toml:"url,omitempty" yaml:"url,omitempty" label:"-"`
Scheme string `toml:"-" json:"-" yaml:"-"`
Port string `toml:"-" json:"-" yaml:"-"`
}
// SetDefaults Default values for a Server.
func (s *Server) SetDefaults() {
s.Scheme = "http"
}
// +k8s:deepcopy-gen=true
// HealthCheck holds the HealthCheck configuration.
type HealthCheck struct {
Scheme string `json:"scheme,omitempty" toml:"scheme,omitempty" yaml:"scheme,omitempty"`
Path string `json:"path,omitempty" toml:"path,omitempty" yaml:"path,omitempty"`
Port int `json:"port,omitempty" toml:"port,omitempty,omitzero" yaml:"port,omitempty"`
// FIXME change string to types.Duration
Interval string `json:"interval,omitempty" toml:"interval,omitempty" yaml:"interval,omitempty"`
// FIXME change string to types.Duration
Timeout string `json:"timeout,omitempty" toml:"timeout,omitempty" yaml:"timeout,omitempty"`
Hostname string `json:"hostname,omitempty" toml:"hostname,omitempty" yaml:"hostname,omitempty"`
Headers map[string]string `json:"headers,omitempty" toml:"headers,omitempty" yaml:"headers,omitempty"`
}

View file

@ -0,0 +1,464 @@
package dynamic
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"os"
"github.com/containous/traefik/pkg/ip"
"github.com/containous/traefik/pkg/types"
)
// +k8s:deepcopy-gen=true
// Middleware holds the Middleware configuration.
type Middleware struct {
AddPrefix *AddPrefix `json:"addPrefix,omitempty" toml:"addPrefix,omitempty" yaml:"addPrefix,omitempty"`
StripPrefix *StripPrefix `json:"stripPrefix,omitempty" toml:"stripPrefix,omitempty" yaml:"stripPrefix,omitempty"`
StripPrefixRegex *StripPrefixRegex `json:"stripPrefixRegex,omitempty" toml:"stripPrefixRegex,omitempty" yaml:"stripPrefixRegex,omitempty"`
ReplacePath *ReplacePath `json:"replacePath,omitempty" toml:"replacePath,omitempty" yaml:"replacePath,omitempty"`
ReplacePathRegex *ReplacePathRegex `json:"replacePathRegex,omitempty" toml:"replacePathRegex,omitempty" yaml:"replacePathRegex,omitempty"`
Chain *Chain `json:"chain,omitempty" toml:"chain,omitempty" yaml:"chain,omitempty"`
IPWhiteList *IPWhiteList `json:"ipWhiteList,omitempty" toml:"ipWhiteList,omitempty" yaml:"ipWhiteList,omitempty"`
Headers *Headers `json:"headers,omitempty" toml:"headers,omitempty" yaml:"headers,omitempty"`
Errors *ErrorPage `json:"errors,omitempty" toml:"errors,omitempty" yaml:"errors,omitempty"`
RateLimit *RateLimit `json:"rateLimit,omitempty" toml:"rateLimit,omitempty" yaml:"rateLimit,omitempty"`
RedirectRegex *RedirectRegex `json:"redirectRegex,omitempty" toml:"redirectRegex,omitempty" yaml:"redirectRegex,omitempty"`
RedirectScheme *RedirectScheme `json:"redirectScheme,omitempty" toml:"redirectScheme,omitempty" yaml:"redirectScheme,omitempty"`
BasicAuth *BasicAuth `json:"basicAuth,omitempty" toml:"basicAuth,omitempty" yaml:"basicAuth,omitempty"`
DigestAuth *DigestAuth `json:"digestAuth,omitempty" toml:"digestAuth,omitempty" yaml:"digestAuth,omitempty"`
ForwardAuth *ForwardAuth `json:"forwardAuth,omitempty" toml:"forwardAuth,omitempty" yaml:"forwardAuth,omitempty"`
MaxConn *MaxConn `json:"maxConn,omitempty" toml:"maxConn,omitempty" yaml:"maxConn,omitempty"`
Buffering *Buffering `json:"buffering,omitempty" toml:"buffering,omitempty" yaml:"buffering,omitempty"`
CircuitBreaker *CircuitBreaker `json:"circuitBreaker,omitempty" toml:"circuitBreaker,omitempty" yaml:"circuitBreaker,omitempty"`
Compress *Compress `json:"compress,omitempty" toml:"compress,omitempty" yaml:"compress,omitempty" label:"allowEmpty"`
PassTLSClientCert *PassTLSClientCert `json:"passTLSClientCert,omitempty" toml:"passTLSClientCert,omitempty" yaml:"passTLSClientCert,omitempty"`
Retry *Retry `json:"retry,omitempty" toml:"retry,omitempty" yaml:"retry,omitempty"`
}
// +k8s:deepcopy-gen=true
// AddPrefix holds the AddPrefix configuration.
type AddPrefix struct {
Prefix string `json:"prefix,omitempty" toml:"prefix,omitempty" yaml:"prefix,omitempty"`
}
// +k8s:deepcopy-gen=true
// Auth holds the authentication configuration (BASIC, DIGEST, users).
type Auth struct {
Basic *BasicAuth `json:"basic,omitempty" toml:"basic,omitempty" yaml:"basic,omitempty" export:"true"`
Digest *DigestAuth `json:"digest,omitempty" toml:"digest,omitempty" yaml:"digest,omitempty" export:"true"`
Forward *ForwardAuth `json:"forward,omitempty" toml:"forward,omitempty" yaml:"forward,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// BasicAuth holds the HTTP basic authentication configuration.
type BasicAuth struct {
Users Users `json:"users,omitempty" toml:"users,omitempty" yaml:"users,omitempty"`
UsersFile string `json:"usersFile,omitempty" toml:"usersFile,omitempty" yaml:"usersFile,omitempty"`
Realm string `json:"realm,omitempty" toml:"realm,omitempty" yaml:"realm,omitempty"`
RemoveHeader bool `json:"removeHeader,omitempty" toml:"removeHeader,omitempty" yaml:"removeHeader,omitempty"`
HeaderField string `json:"headerField,omitempty" toml:"headerField,omitempty" yaml:"headerField,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// Buffering holds the request/response buffering configuration.
type Buffering struct {
MaxRequestBodyBytes int64 `json:"maxRequestBodyBytes,omitempty" toml:"maxRequestBodyBytes,omitempty" yaml:"maxRequestBodyBytes,omitempty"`
MemRequestBodyBytes int64 `json:"memRequestBodyBytes,omitempty" toml:"memRequestBodyBytes,omitempty" yaml:"memRequestBodyBytes,omitempty"`
MaxResponseBodyBytes int64 `json:"maxResponseBodyBytes,omitempty" toml:"maxResponseBodyBytes,omitempty" yaml:"maxResponseBodyBytes,omitempty"`
MemResponseBodyBytes int64 `json:"memResponseBodyBytes,omitempty" toml:"memResponseBodyBytes,omitempty" yaml:"memResponseBodyBytes,omitempty"`
RetryExpression string `json:"retryExpression,omitempty" toml:"retryExpression,omitempty" yaml:"retryExpression,omitempty"`
}
// +k8s:deepcopy-gen=true
// Chain holds a chain of middlewares
type Chain struct {
Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty"`
}
// +k8s:deepcopy-gen=true
// CircuitBreaker holds the circuit breaker configuration.
type CircuitBreaker struct {
Expression string `json:"expression,omitempty" toml:"expression,omitempty" yaml:"expression,omitempty"`
}
// +k8s:deepcopy-gen=true
// Compress holds the compress configuration.
type Compress struct{}
// +k8s:deepcopy-gen=true
// DigestAuth holds the Digest HTTP authentication configuration.
type DigestAuth struct {
Users Users `json:"users,omitempty" toml:"users,omitempty" yaml:"users,omitempty"`
UsersFile string `json:"usersFile,omitempty" toml:"usersFile,omitempty" yaml:"usersFile,omitempty"`
RemoveHeader bool `json:"removeHeader,omitempty" toml:"removeHeader,omitempty" yaml:"removeHeader,omitempty"`
Realm string `json:"realm,omitempty" toml:"realm,omitempty" yaml:"realm,omitempty"`
HeaderField string `json:"headerField,omitempty" toml:"headerField,omitempty" yaml:"headerField,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// ErrorPage holds the custom error page configuration.
type ErrorPage struct {
Status []string `json:"status,omitempty" toml:"status,omitempty" yaml:"status,omitempty"`
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty"`
Query string `json:"query,omitempty" toml:"query,omitempty" yaml:"query,omitempty"`
}
// +k8s:deepcopy-gen=true
// ForwardAuth holds the http forward authentication configuration.
type ForwardAuth struct {
Address string `json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty"`
TLS *ClientTLS `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty"`
TrustForwardHeader bool `json:"trustForwardHeader,omitempty" toml:"trustForwardHeader,omitempty" yaml:"trustForwardHeader,omitempty" export:"true"`
AuthResponseHeaders []string `json:"authResponseHeaders,omitempty" toml:"authResponseHeaders,omitempty" yaml:"authResponseHeaders,omitempty"`
}
// +k8s:deepcopy-gen=true
// Headers holds the custom header configuration.
type Headers struct {
CustomRequestHeaders map[string]string `json:"customRequestHeaders,omitempty" toml:"customRequestHeaders,omitempty" yaml:"customRequestHeaders,omitempty"`
CustomResponseHeaders map[string]string `json:"customResponseHeaders,omitempty" toml:"customResponseHeaders,omitempty" yaml:"customResponseHeaders,omitempty"`
// AccessControlAllowCredentials is only valid if true. false is ignored.
AccessControlAllowCredentials bool `json:"accessControlAllowCredentials,omitempty" toml:"accessControlAllowCredentials,omitempty" yaml:"accessControlAllowCredentials,omitempty"`
// AccessControlAllowHeaders must be used in response to a preflight request with Access-Control-Request-Headers set.
AccessControlAllowHeaders []string `json:"accessControlAllowHeaders,omitempty" toml:"accessControlAllowHeaders,omitempty" yaml:"accessControlAllowHeaders,omitempty"`
// AccessControlAllowMethods must be used in response to a preflight request with Access-Control-Request-Method set.
AccessControlAllowMethods []string `json:"accessControlAllowMethods,omitempty" toml:"accessControlAllowMethods,omitempty" yaml:"accessControlAllowMethods,omitempty"`
// AccessControlAllowOrigin Can be "origin-list-or-null" or "*". From (https://www.w3.org/TR/cors/#access-control-allow-origin-response-header)
AccessControlAllowOrigin string `json:"accessControlAllowOrigin,omitempty" toml:"accessControlAllowOrigin,omitempty" yaml:"accessControlAllowOrigin,omitempty"`
// AccessControlExposeHeaders sets valid headers for the response.
AccessControlExposeHeaders []string `json:"accessControlExposeHeaders,omitempty" toml:"accessControlExposeHeaders,omitempty" yaml:"accessControlExposeHeaders,omitempty"`
// AccessControlMaxAge sets the time that a preflight request may be cached.
AccessControlMaxAge int64 `json:"accessControlMaxAge,omitempty" toml:"accessControlMaxAge,omitempty" yaml:"accessControlMaxAge,omitempty"`
// AddVaryHeader controls if the Vary header is automatically added/updated when the AccessControlAllowOrigin is set.
AddVaryHeader bool `json:"addVaryHeader,omitempty" toml:"addVaryHeader,omitempty" yaml:"addVaryHeader,omitempty"`
AllowedHosts []string `json:"allowedHosts,omitempty" toml:"allowedHosts,omitempty" yaml:"allowedHosts,omitempty"`
HostsProxyHeaders []string `json:"hostsProxyHeaders,omitempty" toml:"hostsProxyHeaders,omitempty" yaml:"hostsProxyHeaders,omitempty"`
SSLRedirect bool `json:"sslRedirect,omitempty" toml:"sslRedirect,omitempty" yaml:"sslRedirect,omitempty"`
SSLTemporaryRedirect bool `json:"sslTemporaryRedirect,omitempty" toml:"sslTemporaryRedirect,omitempty" yaml:"sslTemporaryRedirect,omitempty"`
SSLHost string `json:"sslHost,omitempty" toml:"sslHost,omitempty" yaml:"sslHost,omitempty"`
SSLProxyHeaders map[string]string `json:"sslProxyHeaders,omitempty" toml:"sslProxyHeaders,omitempty" yaml:"sslProxyHeaders,omitempty"`
SSLForceHost bool `json:"sslForceHost,omitempty" toml:"sslForceHost,omitempty" yaml:"sslForceHost,omitempty"`
STSSeconds int64 `json:"stsSeconds,omitempty" toml:"stsSeconds,omitempty" yaml:"stsSeconds,omitempty"`
STSIncludeSubdomains bool `json:"stsIncludeSubdomains,omitempty" toml:"stsIncludeSubdomains,omitempty" yaml:"stsIncludeSubdomains,omitempty"`
STSPreload bool `json:"stsPreload,omitempty" toml:"stsPreload,omitempty" yaml:"stsPreload,omitempty"`
ForceSTSHeader bool `json:"forceSTSHeader,omitempty" toml:"forceSTSHeader,omitempty" yaml:"forceSTSHeader,omitempty"`
FrameDeny bool `json:"frameDeny,omitempty" toml:"frameDeny,omitempty" yaml:"frameDeny,omitempty"`
CustomFrameOptionsValue string `json:"customFrameOptionsValue,omitempty" toml:"customFrameOptionsValue,omitempty" yaml:"customFrameOptionsValue,omitempty"`
ContentTypeNosniff bool `json:"contentTypeNosniff,omitempty" toml:"contentTypeNosniff,omitempty" yaml:"contentTypeNosniff,omitempty"`
BrowserXSSFilter bool `json:"browserXssFilter,omitempty" toml:"browserXssFilter,omitempty" yaml:"browserXssFilter,omitempty"`
CustomBrowserXSSValue string `json:"customBrowserXSSValue,omitempty" toml:"customBrowserXSSValue,omitempty" yaml:"customBrowserXSSValue,omitempty"`
ContentSecurityPolicy string `json:"contentSecurityPolicy,omitempty" toml:"contentSecurityPolicy,omitempty" yaml:"contentSecurityPolicy,omitempty"`
PublicKey string `json:"publicKey,omitempty" toml:"publicKey,omitempty" yaml:"publicKey,omitempty"`
ReferrerPolicy string `json:"referrerPolicy,omitempty" toml:"referrerPolicy,omitempty" yaml:"referrerPolicy,omitempty"`
IsDevelopment bool `json:"isDevelopment,omitempty" toml:"isDevelopment,omitempty" yaml:"isDevelopment,omitempty"`
}
// HasCustomHeadersDefined checks to see if any of the custom header elements have been set
func (h *Headers) HasCustomHeadersDefined() bool {
return h != nil && (len(h.CustomResponseHeaders) != 0 ||
len(h.CustomRequestHeaders) != 0)
}
// HasCorsHeadersDefined checks to see if any of the cors header elements have been set
func (h *Headers) HasCorsHeadersDefined() bool {
return h != nil && (h.AccessControlAllowCredentials ||
len(h.AccessControlAllowHeaders) != 0 ||
len(h.AccessControlAllowMethods) != 0 ||
h.AccessControlAllowOrigin != "" ||
len(h.AccessControlExposeHeaders) != 0 ||
h.AccessControlMaxAge != 0 ||
h.AddVaryHeader)
}
// HasSecureHeadersDefined checks to see if any of the secure header elements have been set
func (h *Headers) HasSecureHeadersDefined() bool {
return h != nil && (len(h.AllowedHosts) != 0 ||
len(h.HostsProxyHeaders) != 0 ||
h.SSLRedirect ||
h.SSLTemporaryRedirect ||
h.SSLForceHost ||
h.SSLHost != "" ||
len(h.SSLProxyHeaders) != 0 ||
h.STSSeconds != 0 ||
h.STSIncludeSubdomains ||
h.STSPreload ||
h.ForceSTSHeader ||
h.FrameDeny ||
h.CustomFrameOptionsValue != "" ||
h.ContentTypeNosniff ||
h.BrowserXSSFilter ||
h.CustomBrowserXSSValue != "" ||
h.ContentSecurityPolicy != "" ||
h.PublicKey != "" ||
h.ReferrerPolicy != "" ||
h.IsDevelopment)
}
// +k8s:deepcopy-gen=true
// IPStrategy holds the ip strategy configuration.
type IPStrategy struct {
Depth int `json:"depth,omitempty" toml:"depth,omitempty" yaml:"depth,omitempty" export:"true"`
ExcludedIPs []string `json:"excludedIPs,omitempty" toml:"excludedIPs,omitempty" yaml:"excludedIPs,omitempty"`
}
// Get an IP selection strategy
// if nil return the RemoteAddr strategy
// else return a strategy base on the configuration using the X-Forwarded-For Header.
// Depth override the ExcludedIPs
func (s *IPStrategy) Get() (ip.Strategy, error) {
if s == nil {
return &ip.RemoteAddrStrategy{}, nil
}
if s.Depth > 0 {
return &ip.DepthStrategy{
Depth: s.Depth,
}, nil
}
if len(s.ExcludedIPs) > 0 {
checker, err := ip.NewChecker(s.ExcludedIPs)
if err != nil {
return nil, err
}
return &ip.CheckerStrategy{
Checker: checker,
}, nil
}
return &ip.RemoteAddrStrategy{}, nil
}
// +k8s:deepcopy-gen=true
// IPWhiteList holds the ip white list configuration.
type IPWhiteList struct {
SourceRange []string `json:"sourceRange,omitempty" toml:"sourceRange,omitempty" yaml:"sourceRange,omitempty"`
IPStrategy *IPStrategy `json:"ipStrategy,omitempty" toml:"ipStrategy,omitempty" yaml:"ipStrategy,omitempty" label:"allowEmpty"`
}
// +k8s:deepcopy-gen=true
// MaxConn holds maximum connection configuration.
type MaxConn struct {
Amount int64 `json:"amount,omitempty" toml:"amount,omitempty" yaml:"amount,omitempty"`
ExtractorFunc string `json:"extractorFunc,omitempty" toml:"extractorFunc,omitempty" yaml:"extractorFunc,omitempty"`
}
// SetDefaults Default values for a MaxConn.
func (m *MaxConn) SetDefaults() {
m.ExtractorFunc = "request.host"
}
// +k8s:deepcopy-gen=true
// PassTLSClientCert holds the TLS client cert headers configuration.
type PassTLSClientCert struct {
PEM bool `json:"pem,omitempty" toml:"pem,omitempty" yaml:"pem,omitempty"`
Info *TLSClientCertificateInfo `json:"info,omitempty" toml:"info,omitempty" yaml:"info,omitempty"`
}
// +k8s:deepcopy-gen=true
// Rate holds the rate limiting configuration for a specific time period.
type Rate struct {
Period types.Duration `json:"period,omitempty" toml:"period,omitempty" yaml:"period,omitempty"`
Average int64 `json:"average,omitempty" toml:"average,omitempty" yaml:"average,omitempty"`
Burst int64 `json:"burst,omitempty" toml:"burst,omitempty" yaml:"burst,omitempty"`
}
// +k8s:deepcopy-gen=true
// RateLimit holds the rate limiting configuration for a given frontend.
type RateLimit struct {
RateSet map[string]*Rate `json:"rateSet,omitempty" toml:"rateSet,omitempty" yaml:"rateSet,omitempty"`
// FIXME replace by ipStrategy see oxy and replace
ExtractorFunc string `json:"extractorFunc,omitempty" toml:"extractorFunc,omitempty" yaml:"extractorFunc,omitempty"`
}
// SetDefaults Default values for a MaxConn.
func (r *RateLimit) SetDefaults() {
r.ExtractorFunc = "request.host"
}
// +k8s:deepcopy-gen=true
// RedirectRegex holds the redirection configuration.
type RedirectRegex struct {
Regex string `json:"regex,omitempty" toml:"regex,omitempty" yaml:"regex,omitempty"`
Replacement string `json:"replacement,omitempty" toml:"replacement,omitempty" yaml:"replacement,omitempty"`
Permanent bool `json:"permanent,omitempty" toml:"permanent,omitempty" yaml:"permanent,omitempty"`
}
// +k8s:deepcopy-gen=true
// RedirectScheme holds the scheme redirection configuration.
type RedirectScheme struct {
Scheme string `json:"scheme,omitempty" toml:"scheme,omitempty" yaml:"scheme,omitempty"`
Port string `json:"port,omitempty" toml:"port,omitempty" yaml:"port,omitempty"`
Permanent bool `json:"permanent,omitempty" toml:"permanent,omitempty" yaml:"permanent,omitempty"`
}
// +k8s:deepcopy-gen=true
// ReplacePath holds the ReplacePath configuration.
type ReplacePath struct {
Path string `json:"path,omitempty" toml:"path,omitempty" yaml:"path,omitempty"`
}
// +k8s:deepcopy-gen=true
// ReplacePathRegex holds the ReplacePathRegex configuration.
type ReplacePathRegex struct {
Regex string `json:"regex,omitempty" toml:"regex,omitempty" yaml:"regex,omitempty"`
Replacement string `json:"replacement,omitempty" toml:"replacement,omitempty" yaml:"replacement,omitempty"`
}
// +k8s:deepcopy-gen=true
// Retry holds the retry configuration.
type Retry struct {
Attempts int `json:"attempts,omitempty" toml:"attempts,omitempty" yaml:"attempts,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// StripPrefix holds the StripPrefix configuration.
type StripPrefix struct {
Prefixes []string `json:"prefixes,omitempty" toml:"prefixes,omitempty" yaml:"prefixes,omitempty"`
}
// +k8s:deepcopy-gen=true
// StripPrefixRegex holds the StripPrefixRegex configuration.
type StripPrefixRegex struct {
Regex []string `json:"regex,omitempty" toml:"regex,omitempty" yaml:"regex,omitempty"`
}
// +k8s:deepcopy-gen=true
// TLSClientCertificateInfo holds the client TLS certificate info configuration.
type TLSClientCertificateInfo struct {
NotAfter bool `json:"notAfter,omitempty" toml:"notAfter,omitempty" yaml:"notAfter,omitempty"`
NotBefore bool `json:"notBefore,omitempty" toml:"notBefore,omitempty" yaml:"notBefore,omitempty"`
Sans bool `json:"sans,omitempty" toml:"sans,omitempty" yaml:"sans,omitempty"`
Subject *TLSCLientCertificateDNInfo `json:"subject,omitempty" toml:"subject,omitempty" yaml:"subject,omitempty"`
Issuer *TLSCLientCertificateDNInfo `json:"issuer,omitempty" toml:"issuer,omitempty" yaml:"issuer,omitempty"`
}
// +k8s:deepcopy-gen=true
// TLSCLientCertificateDNInfo holds the client TLS certificate distinguished name info configuration
// cf https://tools.ietf.org/html/rfc3739
type TLSCLientCertificateDNInfo struct {
Country bool `json:"country,omitempty" toml:"country,omitempty" yaml:"country,omitempty"`
Province bool `json:"province,omitempty" toml:"province,omitempty" yaml:"province,omitempty"`
Locality bool `json:"locality,omitempty" toml:"locality,omitempty" yaml:"locality,omitempty"`
Organization bool `json:"organization,omitempty" toml:"organization,omitempty" yaml:"organization,omitempty"`
CommonName bool `json:"commonName,omitempty" toml:"commonName,omitempty" yaml:"commonName,omitempty"`
SerialNumber bool `json:"serialNumber,omitempty" toml:"serialNumber,omitempty" yaml:"serialNumber,omitempty"`
DomainComponent bool `json:"domainComponent,omitempty" toml:"domainComponent,omitempty" yaml:"domainComponent,omitempty"`
}
// +k8s:deepcopy-gen=true
// Users holds a list of users
type Users []string
// +k8s:deepcopy-gen=true
// ClientTLS holds the TLS specific configurations as client
// CA, Cert and Key can be either path or file contents.
type ClientTLS struct {
CA string `json:"ca,omitempty" toml:"ca,omitempty" yaml:"ca,omitempty"`
CAOptional bool `json:"caOptional,omitempty" toml:"caOptional,omitempty" yaml:"caOptional,omitempty"`
Cert string `json:"cert,omitempty" toml:"cert,omitempty" yaml:"cert,omitempty"`
Key string `json:"key,omitempty" toml:"key,omitempty" yaml:"key,omitempty"`
InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty"`
}
// CreateTLSConfig creates a TLS config from ClientTLS structures.
func (clientTLS *ClientTLS) CreateTLSConfig() (*tls.Config, error) {
if clientTLS == nil {
return nil, nil
}
var err error
caPool := x509.NewCertPool()
clientAuth := tls.NoClientCert
if clientTLS.CA != "" {
var ca []byte
if _, errCA := os.Stat(clientTLS.CA); errCA == nil {
ca, err = ioutil.ReadFile(clientTLS.CA)
if err != nil {
return nil, fmt.Errorf("failed to read CA. %s", err)
}
} else {
ca = []byte(clientTLS.CA)
}
if !caPool.AppendCertsFromPEM(ca) {
return nil, fmt.Errorf("failed to parse CA")
}
if clientTLS.CAOptional {
clientAuth = tls.VerifyClientCertIfGiven
} else {
clientAuth = tls.RequireAndVerifyClientCert
}
}
cert := tls.Certificate{}
_, errKeyIsFile := os.Stat(clientTLS.Key)
if !clientTLS.InsecureSkipVerify && (len(clientTLS.Cert) == 0 || len(clientTLS.Key) == 0) {
return nil, fmt.Errorf("TLS Certificate or Key file must be set when TLS configuration is created")
}
if len(clientTLS.Cert) > 0 && len(clientTLS.Key) > 0 {
if _, errCertIsFile := os.Stat(clientTLS.Cert); errCertIsFile == nil {
if errKeyIsFile == nil {
cert, err = tls.LoadX509KeyPair(clientTLS.Cert, clientTLS.Key)
if err != nil {
return nil, fmt.Errorf("failed to load TLS keypair: %v", err)
}
} else {
return nil, fmt.Errorf("tls cert is a file, but tls key is not")
}
} else {
if errKeyIsFile != nil {
cert, err = tls.X509KeyPair([]byte(clientTLS.Cert), []byte(clientTLS.Key))
if err != nil {
return nil, fmt.Errorf("failed to load TLS keypair: %v", err)
}
} else {
return nil, fmt.Errorf("TLS key is a file, but tls cert is not")
}
}
}
return &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: caPool,
InsecureSkipVerify: clientTLS.InsecureSkipVerify,
ClientAuth: clientAuth,
}, nil
}

View file

@ -0,0 +1,279 @@
package dynamic
import (
"context"
"sort"
"strings"
"sync"
"github.com/containous/traefik/pkg/log"
)
// RuntimeConfiguration holds the information about the currently running traefik instance.
type RuntimeConfiguration struct {
Routers map[string]*RouterInfo `json:"routers,omitempty"`
Middlewares map[string]*MiddlewareInfo `json:"middlewares,omitempty"`
Services map[string]*ServiceInfo `json:"services,omitempty"`
TCPRouters map[string]*TCPRouterInfo `json:"tcpRouters,omitempty"`
TCPServices map[string]*TCPServiceInfo `json:"tcpServices,omitempty"`
}
// NewRuntimeConfig returns a RuntimeConfiguration initialized with the given conf. It never returns nil.
func NewRuntimeConfig(conf Configuration) *RuntimeConfiguration {
if conf.HTTP == nil && conf.TCP == nil {
return &RuntimeConfiguration{}
}
runtimeConfig := &RuntimeConfiguration{}
if conf.HTTP != nil {
routers := conf.HTTP.Routers
if len(routers) > 0 {
runtimeConfig.Routers = make(map[string]*RouterInfo, len(routers))
for k, v := range routers {
runtimeConfig.Routers[k] = &RouterInfo{Router: v}
}
}
services := conf.HTTP.Services
if len(services) > 0 {
runtimeConfig.Services = make(map[string]*ServiceInfo, len(services))
for k, v := range services {
runtimeConfig.Services[k] = &ServiceInfo{Service: v}
}
}
middlewares := conf.HTTP.Middlewares
if len(middlewares) > 0 {
runtimeConfig.Middlewares = make(map[string]*MiddlewareInfo, len(middlewares))
for k, v := range middlewares {
runtimeConfig.Middlewares[k] = &MiddlewareInfo{Middleware: v}
}
}
}
if conf.TCP != nil {
if len(conf.TCP.Routers) > 0 {
runtimeConfig.TCPRouters = make(map[string]*TCPRouterInfo, len(conf.TCP.Routers))
for k, v := range conf.TCP.Routers {
runtimeConfig.TCPRouters[k] = &TCPRouterInfo{TCPRouter: v}
}
}
if len(conf.TCP.Services) > 0 {
runtimeConfig.TCPServices = make(map[string]*TCPServiceInfo, len(conf.TCP.Services))
for k, v := range conf.TCP.Services {
runtimeConfig.TCPServices[k] = &TCPServiceInfo{TCPService: v}
}
}
}
return runtimeConfig
}
// PopulateUsedBy populates all the UsedBy lists of the underlying fields of r,
// based on the relations between the included services, routers, and middlewares.
func (r *RuntimeConfiguration) PopulateUsedBy() {
if r == nil {
return
}
logger := log.WithoutContext()
for routerName, routerInfo := range r.Routers {
providerName := getProviderName(routerName)
if providerName == "" {
logger.WithField(log.RouterName, routerName).Error("router name is not fully qualified")
continue
}
for _, midName := range routerInfo.Router.Middlewares {
fullMidName := getQualifiedName(providerName, midName)
if _, ok := r.Middlewares[fullMidName]; !ok {
continue
}
r.Middlewares[fullMidName].UsedBy = append(r.Middlewares[fullMidName].UsedBy, routerName)
}
serviceName := getQualifiedName(providerName, routerInfo.Router.Service)
if _, ok := r.Services[serviceName]; !ok {
continue
}
r.Services[serviceName].UsedBy = append(r.Services[serviceName].UsedBy, routerName)
}
for k := range r.Services {
sort.Strings(r.Services[k].UsedBy)
}
for k := range r.Middlewares {
sort.Strings(r.Middlewares[k].UsedBy)
}
for routerName, routerInfo := range r.TCPRouters {
providerName := getProviderName(routerName)
if providerName == "" {
logger.WithField(log.RouterName, routerName).Error("tcp router name is not fully qualified")
continue
}
serviceName := getQualifiedName(providerName, routerInfo.TCPRouter.Service)
if _, ok := r.TCPServices[serviceName]; !ok {
continue
}
r.TCPServices[serviceName].UsedBy = append(r.TCPServices[serviceName].UsedBy, routerName)
}
for k := range r.TCPServices {
sort.Strings(r.TCPServices[k].UsedBy)
}
}
func contains(entryPoints []string, entryPointName string) bool {
for _, name := range entryPoints {
if name == entryPointName {
return true
}
}
return false
}
// GetRoutersByEntrypoints returns all the http routers by entrypoints name and routers name
func (r *RuntimeConfiguration) GetRoutersByEntrypoints(ctx context.Context, entryPoints []string, tls bool) map[string]map[string]*RouterInfo {
entryPointsRouters := make(map[string]map[string]*RouterInfo)
for rtName, rt := range r.Routers {
if (tls && rt.TLS == nil) || (!tls && rt.TLS != nil) {
continue
}
eps := rt.EntryPoints
if len(eps) == 0 {
eps = entryPoints
}
for _, entryPointName := range eps {
if !contains(entryPoints, entryPointName) {
log.FromContext(log.With(ctx, log.Str(log.EntryPointName, entryPointName))).
Errorf("entryPoint %q doesn't exist", entryPointName)
continue
}
if _, ok := entryPointsRouters[entryPointName]; !ok {
entryPointsRouters[entryPointName] = make(map[string]*RouterInfo)
}
entryPointsRouters[entryPointName][rtName] = rt
}
}
return entryPointsRouters
}
// GetTCPRoutersByEntrypoints returns all the tcp routers by entrypoints name and routers name
func (r *RuntimeConfiguration) GetTCPRoutersByEntrypoints(ctx context.Context, entryPoints []string) map[string]map[string]*TCPRouterInfo {
entryPointsRouters := make(map[string]map[string]*TCPRouterInfo)
for rtName, rt := range r.TCPRouters {
eps := rt.EntryPoints
if len(eps) == 0 {
eps = entryPoints
}
for _, entryPointName := range eps {
if !contains(entryPoints, entryPointName) {
log.FromContext(log.With(ctx, log.Str(log.EntryPointName, entryPointName))).
Errorf("entryPoint %q doesn't exist", entryPointName)
continue
}
if _, ok := entryPointsRouters[entryPointName]; !ok {
entryPointsRouters[entryPointName] = make(map[string]*TCPRouterInfo)
}
entryPointsRouters[entryPointName][rtName] = rt
}
}
return entryPointsRouters
}
// RouterInfo holds information about a currently running HTTP router
type RouterInfo struct {
*Router // dynamic configuration
Err string `json:"error,omitempty"` // initialization error
}
// TCPRouterInfo holds information about a currently running TCP router
type TCPRouterInfo struct {
*TCPRouter // dynamic configuration
Err string `json:"error,omitempty"` // initialization error
}
// MiddlewareInfo holds information about a currently running middleware
type MiddlewareInfo struct {
*Middleware // dynamic configuration
Err error `json:"error,omitempty"` // initialization error
UsedBy []string `json:"usedBy,omitempty"` // list of routers and services using that middleware
}
// ServiceInfo holds information about a currently running service
type ServiceInfo struct {
*Service // dynamic configuration
Err error `json:"error,omitempty"` // initialization error
UsedBy []string `json:"usedBy,omitempty"` // list of routers using that service
statusMu sync.RWMutex
status map[string]string // keyed by server URL
}
// UpdateStatus sets the status of the server in the ServiceInfo.
// It is the responsibility of the caller to check that s is not nil.
func (s *ServiceInfo) UpdateStatus(server string, status string) {
s.statusMu.Lock()
defer s.statusMu.Unlock()
if s.status == nil {
s.status = make(map[string]string)
}
s.status[server] = status
}
// GetAllStatus returns all the statuses of all the servers in ServiceInfo.
// It is the responsibility of the caller to check that s is not nil
func (s *ServiceInfo) GetAllStatus() map[string]string {
s.statusMu.RLock()
defer s.statusMu.RUnlock()
if len(s.status) == 0 {
return nil
}
allStatus := make(map[string]string, len(s.status))
for k, v := range s.status {
allStatus[k] = v
}
return allStatus
}
// TCPServiceInfo holds information about a currently running TCP service
type TCPServiceInfo struct {
*TCPService // dynamic configuration
Err error `json:"error,omitempty"` // initialization error
UsedBy []string `json:"usedBy,omitempty"` // list of routers using that service
}
func getProviderName(elementName string) string {
parts := strings.Split(elementName, "@")
if len(parts) > 1 {
return parts[1]
}
return ""
}
func getQualifiedName(provider, elementName string) string {
parts := strings.Split(elementName, "@")
if len(parts) == 1 {
return elementName + "@" + provider
}
return elementName
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,68 @@
package dynamic
import "reflect"
// +k8s:deepcopy-gen=true
// TCPConfiguration contains all the TCP configuration parameters.
type TCPConfiguration struct {
Routers map[string]*TCPRouter `json:"routers,omitempty" toml:"routers,omitempty" yaml:"routers,omitempty"`
Services map[string]*TCPService `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty"`
}
// +k8s:deepcopy-gen=true
// TCPService holds a tcp service configuration (can only be of one type at the same time).
type TCPService struct {
LoadBalancer *TCPLoadBalancerService `json:"loadBalancer,omitempty" toml:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty"`
}
// +k8s:deepcopy-gen=true
// TCPRouter holds the router configuration.
type TCPRouter struct {
EntryPoints []string `json:"entryPoints,omitempty" toml:"entryPoints,omitempty" yaml:"entryPoints,omitempty"`
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty"`
Rule string `json:"rule,omitempty" toml:"rule,omitempty" yaml:"rule,omitempty"`
TLS *RouterTCPTLSConfig `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty"`
}
// +k8s:deepcopy-gen=true
// RouterTCPTLSConfig holds the TLS configuration for a router
type RouterTCPTLSConfig struct {
Passthrough bool `json:"passthrough" toml:"passthrough" yaml:"passthrough"`
Options string `json:"options,omitempty" toml:"options,omitempty" yaml:"options,omitempty"`
}
// +k8s:deepcopy-gen=true
// TCPLoadBalancerService holds the LoadBalancerService configuration.
type TCPLoadBalancerService struct {
Servers []TCPServer `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server" label-slice-as-struct:"server"`
}
// Mergeable tells if the given service is mergeable.
func (l *TCPLoadBalancerService) Mergeable(loadBalancer *TCPLoadBalancerService) bool {
savedServers := l.Servers
defer func() {
l.Servers = savedServers
}()
l.Servers = nil
savedServersLB := loadBalancer.Servers
defer func() {
loadBalancer.Servers = savedServersLB
}()
loadBalancer.Servers = nil
return reflect.DeepEqual(l, loadBalancer)
}
// +k8s:deepcopy-gen=true
// TCPServer holds a TCP Server configuration
type TCPServer struct {
Address string `json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty" label:"-"`
Port string `toml:"-" json:"-" yaml:"-"`
}

File diff suppressed because it is too large Load diff