Send anonymized dynamic configuration to Pilot
Co-authored-by: Kevin Pollet <pollet.kevin@gmail.com>
This commit is contained in:
parent
a488430f23
commit
64a65cadf3
14 changed files with 1394 additions and 374 deletions
|
@ -214,6 +214,7 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
|
|||
pilotRegistry = metrics.RegisterPilot()
|
||||
|
||||
aviator = pilot.New(staticConfiguration.Pilot.Token, pilotRegistry, routinesPool)
|
||||
|
||||
routinesPool.GoCtx(func(ctx context.Context) {
|
||||
aviator.Tick(ctx)
|
||||
})
|
||||
|
@ -348,7 +349,7 @@ func switchRouter(routerFactory *server.RouterFactory, serverEntryPointsTCP serv
|
|||
routers, udpRouters := routerFactory.CreateRouters(rtConf)
|
||||
|
||||
if aviator != nil {
|
||||
aviator.SetRuntimeConfiguration(rtConf)
|
||||
aviator.SetDynamicConfiguration(conf)
|
||||
}
|
||||
|
||||
serverEntryPointsTCP.Switch(routers)
|
||||
|
|
|
@ -7,6 +7,8 @@ import (
|
|||
"regexp"
|
||||
|
||||
"github.com/mitchellh/copystructure"
|
||||
"github.com/traefik/traefik/v2/pkg/config/dynamic"
|
||||
"github.com/traefik/traefik/v2/pkg/tls"
|
||||
"mvdan.cc/xurls/v2"
|
||||
)
|
||||
|
||||
|
@ -43,6 +45,11 @@ func doOnJSON(input string) string {
|
|||
}
|
||||
|
||||
func doOnStruct(field reflect.Value) error {
|
||||
if field.Type().AssignableTo(reflect.TypeOf(dynamic.PluginConf{})) {
|
||||
resetPlugin(field)
|
||||
return nil
|
||||
}
|
||||
|
||||
switch field.Kind() {
|
||||
case reflect.Ptr:
|
||||
if !field.IsNil() {
|
||||
|
@ -57,19 +64,48 @@ func doOnStruct(field reflect.Value) error {
|
|||
if !isExported(stField) {
|
||||
continue
|
||||
}
|
||||
|
||||
if stField.Tag.Get("export") == "true" {
|
||||
// A struct field cannot be set it must be filled as pointer.
|
||||
if fld.Kind() == reflect.Struct {
|
||||
fldPtr := reflect.New(fld.Type())
|
||||
fldPtr.Elem().Set(fld)
|
||||
|
||||
if err := doOnStruct(fldPtr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fld.Set(fldPtr.Elem())
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if err := doOnStruct(fld); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := reset(fld, stField.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err := reset(fld, stField.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case reflect.Map:
|
||||
for _, key := range field.MapKeys() {
|
||||
if err := doOnStruct(field.MapIndex(key)); err != nil {
|
||||
val := field.MapIndex(key)
|
||||
|
||||
// A struct value cannot be set it must be filled as pointer.
|
||||
if val.Kind() == reflect.Struct {
|
||||
valPtr := reflect.New(val.Type())
|
||||
valPtr.Elem().Set(val)
|
||||
|
||||
if err := doOnStruct(valPtr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
field.SetMapIndex(key, valPtr.Elem())
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if err := doOnStruct(val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -100,7 +136,11 @@ func reset(field reflect.Value, name string) error {
|
|||
}
|
||||
case reflect.String:
|
||||
if field.String() != "" {
|
||||
field.Set(reflect.ValueOf(maskShort))
|
||||
if field.Type().AssignableTo(reflect.TypeOf(tls.FileOrContent(""))) {
|
||||
field.Set(reflect.ValueOf(tls.FileOrContent(maskShort)))
|
||||
} else {
|
||||
field.Set(reflect.ValueOf(maskShort))
|
||||
}
|
||||
}
|
||||
case reflect.Map:
|
||||
if field.Len() > 0 {
|
||||
|
@ -130,6 +170,13 @@ func reset(field reflect.Value, name string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// resetPlugin resets the plugin configuration so it keep the plugin name but not its configuration.
|
||||
func resetPlugin(field reflect.Value) {
|
||||
for _, key := range field.MapKeys() {
|
||||
field.SetMapIndex(key, reflect.ValueOf(struct{}{}))
|
||||
}
|
||||
}
|
||||
|
||||
// isExported return true is a struct field is exported, else false.
|
||||
func isExported(f reflect.StructField) bool {
|
||||
if f.PkgPath != "" && !f.Anonymous {
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
ptypes "github.com/traefik/paerser/types"
|
||||
"github.com/traefik/traefik/v2/pkg/config/dynamic"
|
||||
"github.com/traefik/traefik/v2/pkg/config/static"
|
||||
"github.com/traefik/traefik/v2/pkg/ping"
|
||||
"github.com/traefik/traefik/v2/pkg/plugins"
|
||||
|
@ -43,7 +44,438 @@ import (
|
|||
|
||||
var updateExpected = flag.Bool("update_expected", false, "Update expected files in fixtures")
|
||||
|
||||
func TestDo_globalConfiguration(t *testing.T) {
|
||||
func TestDo_dynamicConfiguration(t *testing.T) {
|
||||
config := &dynamic.Configuration{}
|
||||
config.HTTP = &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"foo": {
|
||||
EntryPoints: []string{"foo"},
|
||||
Middlewares: []string{"foo"},
|
||||
Service: "foo",
|
||||
Rule: "foo",
|
||||
Priority: 42,
|
||||
TLS: &dynamic.RouterTLSConfig{
|
||||
Options: "foo",
|
||||
CertResolver: "foo",
|
||||
Domains: []types.Domain{
|
||||
{
|
||||
Main: "foo",
|
||||
SANs: []string{"foo"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"foo": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Sticky: &dynamic.Sticky{
|
||||
Cookie: &dynamic.Cookie{
|
||||
Name: "foo",
|
||||
Secure: true,
|
||||
HTTPOnly: true,
|
||||
SameSite: "foo",
|
||||
},
|
||||
},
|
||||
HealthCheck: &dynamic.HealthCheck{
|
||||
Scheme: "foo",
|
||||
Path: "foo",
|
||||
Port: 42,
|
||||
Interval: "foo",
|
||||
Timeout: "foo",
|
||||
Hostname: "foo",
|
||||
FollowRedirects: boolPtr(true),
|
||||
Headers: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
PassHostHeader: boolPtr(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: "foo",
|
||||
},
|
||||
ServersTransport: "foo",
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:8080",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"bar": {
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "foo",
|
||||
Weight: intPtr(42),
|
||||
},
|
||||
},
|
||||
Sticky: &dynamic.Sticky{
|
||||
Cookie: &dynamic.Cookie{
|
||||
Name: "foo",
|
||||
Secure: true,
|
||||
HTTPOnly: true,
|
||||
SameSite: "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"baz": {
|
||||
Mirroring: &dynamic.Mirroring{
|
||||
Service: "foo",
|
||||
MaxBodySize: int64Ptr(42),
|
||||
Mirrors: []dynamic.MirrorService{
|
||||
{
|
||||
Name: "foo",
|
||||
Percent: 42,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{
|
||||
"foo": {
|
||||
ServerName: "foo",
|
||||
InsecureSkipVerify: true,
|
||||
RootCAs: []traefiktls.FileOrContent{"rootca.pem"},
|
||||
Certificates: []traefiktls.Certificate{
|
||||
{
|
||||
CertFile: "cert.pem",
|
||||
KeyFile: "key.pem",
|
||||
},
|
||||
},
|
||||
MaxIdleConnsPerHost: 42,
|
||||
ForwardingTimeouts: &dynamic.ForwardingTimeouts{
|
||||
DialTimeout: 42,
|
||||
ResponseHeaderTimeout: 42,
|
||||
IdleConnTimeout: 42,
|
||||
},
|
||||
},
|
||||
},
|
||||
Models: map[string]*dynamic.Model{
|
||||
"foo": {
|
||||
Middlewares: []string{"foo"},
|
||||
TLS: &dynamic.RouterTLSConfig{
|
||||
Options: "foo",
|
||||
CertResolver: "foo",
|
||||
Domains: []types.Domain{
|
||||
{
|
||||
Main: "foo",
|
||||
SANs: []string{"foo"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{
|
||||
"foo": {
|
||||
AddPrefix: &dynamic.AddPrefix{
|
||||
Prefix: "foo",
|
||||
},
|
||||
StripPrefix: &dynamic.StripPrefix{
|
||||
Prefixes: []string{"foo"},
|
||||
ForceSlash: true,
|
||||
},
|
||||
StripPrefixRegex: &dynamic.StripPrefixRegex{
|
||||
Regex: []string{"foo"},
|
||||
},
|
||||
ReplacePath: &dynamic.ReplacePath{
|
||||
Path: "foo",
|
||||
},
|
||||
ReplacePathRegex: &dynamic.ReplacePathRegex{
|
||||
Regex: "foo",
|
||||
Replacement: "foo",
|
||||
},
|
||||
Chain: &dynamic.Chain{
|
||||
Middlewares: []string{"foo"},
|
||||
},
|
||||
IPWhiteList: &dynamic.IPWhiteList{
|
||||
SourceRange: []string{"foo"},
|
||||
IPStrategy: &dynamic.IPStrategy{
|
||||
Depth: 42,
|
||||
ExcludedIPs: []string{"127.0.0.1"},
|
||||
},
|
||||
},
|
||||
Headers: &dynamic.Headers{
|
||||
CustomRequestHeaders: map[string]string{"foo": "bar"},
|
||||
CustomResponseHeaders: map[string]string{"foo": "bar"},
|
||||
AccessControlAllowCredentials: true,
|
||||
AccessControlAllowHeaders: []string{"foo"},
|
||||
AccessControlAllowMethods: []string{"foo"},
|
||||
AccessControlAllowOrigin: "foo",
|
||||
AccessControlAllowOriginList: []string{"foo"},
|
||||
AccessControlAllowOriginListRegex: []string{"foo"},
|
||||
AccessControlExposeHeaders: []string{"foo"},
|
||||
AccessControlMaxAge: 42,
|
||||
AddVaryHeader: true,
|
||||
AllowedHosts: []string{"foo"},
|
||||
HostsProxyHeaders: []string{"foo"},
|
||||
SSLRedirect: true,
|
||||
SSLTemporaryRedirect: true,
|
||||
SSLHost: "foo",
|
||||
SSLProxyHeaders: map[string]string{"foo": "bar"},
|
||||
SSLForceHost: true,
|
||||
STSSeconds: 42,
|
||||
STSIncludeSubdomains: true,
|
||||
STSPreload: true,
|
||||
ForceSTSHeader: true,
|
||||
FrameDeny: true,
|
||||
CustomFrameOptionsValue: "foo",
|
||||
ContentTypeNosniff: true,
|
||||
BrowserXSSFilter: true,
|
||||
CustomBrowserXSSValue: "foo",
|
||||
ContentSecurityPolicy: "foo",
|
||||
PublicKey: "foo",
|
||||
ReferrerPolicy: "foo",
|
||||
FeaturePolicy: "foo",
|
||||
IsDevelopment: true,
|
||||
},
|
||||
Errors: &dynamic.ErrorPage{
|
||||
Status: []string{"foo"},
|
||||
Service: "foo",
|
||||
Query: "foo",
|
||||
},
|
||||
RateLimit: &dynamic.RateLimit{
|
||||
Average: 42,
|
||||
Period: 42,
|
||||
Burst: 42,
|
||||
SourceCriterion: &dynamic.SourceCriterion{
|
||||
IPStrategy: &dynamic.IPStrategy{
|
||||
Depth: 42,
|
||||
ExcludedIPs: []string{"foo"},
|
||||
},
|
||||
RequestHeaderName: "foo",
|
||||
RequestHost: true,
|
||||
},
|
||||
},
|
||||
RedirectRegex: &dynamic.RedirectRegex{
|
||||
Regex: "foo",
|
||||
Replacement: "foo",
|
||||
Permanent: true,
|
||||
},
|
||||
RedirectScheme: &dynamic.RedirectScheme{
|
||||
Scheme: "foo",
|
||||
Port: "foo",
|
||||
Permanent: true,
|
||||
},
|
||||
BasicAuth: &dynamic.BasicAuth{
|
||||
Users: []string{"foo"},
|
||||
UsersFile: "foo",
|
||||
Realm: "foo",
|
||||
RemoveHeader: true,
|
||||
HeaderField: "foo",
|
||||
},
|
||||
DigestAuth: &dynamic.DigestAuth{
|
||||
Users: []string{"foo"},
|
||||
UsersFile: "foo",
|
||||
RemoveHeader: true,
|
||||
Realm: "foo",
|
||||
HeaderField: "foo",
|
||||
},
|
||||
ForwardAuth: &dynamic.ForwardAuth{
|
||||
Address: "127.0.0.1",
|
||||
TLS: &dynamic.ClientTLS{
|
||||
CA: "ca.pem",
|
||||
CAOptional: true,
|
||||
Cert: "cert.pem",
|
||||
Key: "cert.pem",
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
TrustForwardHeader: true,
|
||||
AuthResponseHeaders: []string{"foo"},
|
||||
AuthResponseHeadersRegex: "foo",
|
||||
AuthRequestHeaders: []string{"foo"},
|
||||
},
|
||||
InFlightReq: &dynamic.InFlightReq{
|
||||
Amount: 42,
|
||||
SourceCriterion: &dynamic.SourceCriterion{
|
||||
IPStrategy: &dynamic.IPStrategy{
|
||||
Depth: 42,
|
||||
ExcludedIPs: []string{"foo"},
|
||||
},
|
||||
RequestHeaderName: "foo",
|
||||
RequestHost: true,
|
||||
},
|
||||
},
|
||||
Buffering: &dynamic.Buffering{
|
||||
MaxRequestBodyBytes: 42,
|
||||
MemRequestBodyBytes: 42,
|
||||
MaxResponseBodyBytes: 42,
|
||||
MemResponseBodyBytes: 42,
|
||||
RetryExpression: "foo",
|
||||
},
|
||||
CircuitBreaker: &dynamic.CircuitBreaker{
|
||||
Expression: "foo",
|
||||
},
|
||||
Compress: &dynamic.Compress{
|
||||
ExcludedContentTypes: []string{"foo"},
|
||||
},
|
||||
PassTLSClientCert: &dynamic.PassTLSClientCert{
|
||||
PEM: true,
|
||||
Info: &dynamic.TLSClientCertificateInfo{
|
||||
NotAfter: true,
|
||||
NotBefore: true,
|
||||
Sans: true,
|
||||
Subject: &dynamic.TLSCLientCertificateDNInfo{
|
||||
Country: true,
|
||||
Province: true,
|
||||
Locality: true,
|
||||
Organization: true,
|
||||
CommonName: true,
|
||||
SerialNumber: true,
|
||||
DomainComponent: true,
|
||||
},
|
||||
Issuer: &dynamic.TLSCLientCertificateDNInfo{
|
||||
Country: true,
|
||||
Province: true,
|
||||
Locality: true,
|
||||
Organization: true,
|
||||
CommonName: true,
|
||||
SerialNumber: true,
|
||||
DomainComponent: true,
|
||||
},
|
||||
SerialNumber: true,
|
||||
},
|
||||
},
|
||||
Retry: &dynamic.Retry{
|
||||
Attempts: 42,
|
||||
InitialInterval: 42,
|
||||
},
|
||||
ContentType: &dynamic.ContentType{
|
||||
AutoDetect: true,
|
||||
},
|
||||
Plugin: map[string]dynamic.PluginConf{
|
||||
"foo": {
|
||||
"answer": struct{ Answer int }{
|
||||
Answer: 42,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
config.TCP = &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{
|
||||
"foo": {
|
||||
EntryPoints: []string{"foo"},
|
||||
Service: "foo",
|
||||
Rule: "foo",
|
||||
TLS: &dynamic.RouterTCPTLSConfig{
|
||||
Passthrough: true,
|
||||
Options: "foo",
|
||||
CertResolver: "foo",
|
||||
Domains: []types.Domain{
|
||||
{
|
||||
Main: "foo",
|
||||
SANs: []string{"foo"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.TCPService{
|
||||
"foo": {
|
||||
LoadBalancer: &dynamic.TCPServersLoadBalancer{
|
||||
TerminationDelay: intPtr(42),
|
||||
ProxyProtocol: &dynamic.ProxyProtocol{
|
||||
Version: 42,
|
||||
},
|
||||
Servers: []dynamic.TCPServer{
|
||||
{
|
||||
Address: "127.0.0.1:8080",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"bar": {
|
||||
Weighted: &dynamic.TCPWeightedRoundRobin{
|
||||
Services: []dynamic.TCPWRRService{
|
||||
{
|
||||
Name: "foo",
|
||||
Weight: intPtr(42),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
config.UDP = &dynamic.UDPConfiguration{
|
||||
Routers: map[string]*dynamic.UDPRouter{
|
||||
"foo": {
|
||||
EntryPoints: []string{"foo"},
|
||||
Service: "foo",
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.UDPService{
|
||||
"foo": {
|
||||
LoadBalancer: &dynamic.UDPServersLoadBalancer{
|
||||
Servers: []dynamic.UDPServer{
|
||||
{
|
||||
Address: "127.0.0.1:8080",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"bar": {
|
||||
Weighted: &dynamic.UDPWeightedRoundRobin{
|
||||
Services: []dynamic.UDPWRRService{
|
||||
{
|
||||
Name: "foo",
|
||||
Weight: intPtr(42),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
config.TLS = &dynamic.TLSConfiguration{
|
||||
Options: map[string]traefiktls.Options{
|
||||
"foo": {
|
||||
MinVersion: "foo",
|
||||
MaxVersion: "foo",
|
||||
CipherSuites: []string{"foo"},
|
||||
CurvePreferences: []string{"foo"},
|
||||
ClientAuth: traefiktls.ClientAuth{
|
||||
CAFiles: []traefiktls.FileOrContent{"ca.pem"},
|
||||
ClientAuthType: "RequireAndVerifyClientCert",
|
||||
},
|
||||
SniStrict: true,
|
||||
PreferServerCipherSuites: true,
|
||||
},
|
||||
},
|
||||
Certificates: []*traefiktls.CertAndStores{
|
||||
{
|
||||
Certificate: traefiktls.Certificate{
|
||||
CertFile: "cert.pem",
|
||||
KeyFile: "key.pem",
|
||||
},
|
||||
Stores: []string{"foo"},
|
||||
},
|
||||
},
|
||||
Stores: map[string]traefiktls.Store{
|
||||
"foo": {
|
||||
DefaultCertificate: &traefiktls.Certificate{
|
||||
CertFile: "cert.pem",
|
||||
KeyFile: "key.pem",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expectedConfiguration, err := ioutil.ReadFile("./testdata/anonymized-dynamic-config.json")
|
||||
require.NoError(t, err)
|
||||
|
||||
cleanJSON, err := Do(config, true)
|
||||
require.NoError(t, err)
|
||||
|
||||
if *updateExpected {
|
||||
require.NoError(t, ioutil.WriteFile("testdata/anonymized-dynamic-config.json", []byte(cleanJSON), 0666))
|
||||
}
|
||||
|
||||
expected := strings.TrimSuffix(string(expectedConfiguration), "\n")
|
||||
assert.Equal(t, expected, cleanJSON)
|
||||
}
|
||||
|
||||
func TestDo_staticConfiguration(t *testing.T) {
|
||||
config := &static.Configuration{}
|
||||
|
||||
config.Global = &static.Global{
|
||||
|
@ -538,3 +970,15 @@ func TestDo_globalConfiguration(t *testing.T) {
|
|||
expected := strings.TrimSuffix(string(expectedConfiguration), "\n")
|
||||
assert.Equal(t, expected, cleanJSON)
|
||||
}
|
||||
|
||||
func boolPtr(value bool) *bool {
|
||||
return &value
|
||||
}
|
||||
|
||||
func intPtr(value int) *int {
|
||||
return &value
|
||||
}
|
||||
|
||||
func int64Ptr(value int64) *int64 {
|
||||
return &value
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type Courgette struct {
|
||||
|
@ -39,7 +40,6 @@ func Test_doOnStruct(t *testing.T) {
|
|||
name string
|
||||
base *Carotte
|
||||
expected *Carotte
|
||||
hasError bool
|
||||
}{
|
||||
{
|
||||
name: "primitive",
|
||||
|
@ -145,7 +145,7 @@ func Test_doOnStruct(t *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
name: "export map string/struct (UNSAFE)",
|
||||
name: "export map string/struct",
|
||||
base: &Carotte{
|
||||
Name: "koko",
|
||||
ESAubergine: map[string]Tomate{
|
||||
|
@ -158,11 +158,10 @@ func Test_doOnStruct(t *testing.T) {
|
|||
Name: "xxxx",
|
||||
ESAubergine: map[string]Tomate{
|
||||
"foo": {
|
||||
Ji: "JiJiJi",
|
||||
Ji: "xxxx",
|
||||
},
|
||||
},
|
||||
},
|
||||
hasError: true,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -170,12 +169,7 @@ func Test_doOnStruct(t *testing.T) {
|
|||
t.Run(test.name, func(t *testing.T) {
|
||||
val := reflect.ValueOf(test.base).Elem()
|
||||
err := doOnStruct(val)
|
||||
if !test.hasError && err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if test.hasError && err == nil {
|
||||
t.Fatal("Got no error but want an error.")
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.EqualValues(t, test.expected, test.base)
|
||||
})
|
||||
|
|
476
pkg/anonymize/testdata/anonymized-dynamic-config.json
vendored
Normal file
476
pkg/anonymize/testdata/anonymized-dynamic-config.json
vendored
Normal file
|
@ -0,0 +1,476 @@
|
|||
{
|
||||
"http": {
|
||||
"routers": {
|
||||
"foo": {
|
||||
"entryPoints": [
|
||||
"foo"
|
||||
],
|
||||
"middlewares": [
|
||||
"foo"
|
||||
],
|
||||
"service": "foo",
|
||||
"rule": "xxxx",
|
||||
"priority": 42,
|
||||
"tls": {
|
||||
"options": "foo",
|
||||
"certResolver": "foo",
|
||||
"domains": [
|
||||
{
|
||||
"main": "xxxx",
|
||||
"sans": [
|
||||
"xxxx"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"bar": {
|
||||
"weighted": {
|
||||
"services": [
|
||||
{
|
||||
"name": "foo",
|
||||
"weight": 42
|
||||
}
|
||||
],
|
||||
"sticky": {
|
||||
"cookie": {
|
||||
"name": "foo",
|
||||
"secure": true,
|
||||
"httpOnly": true,
|
||||
"sameSite": "foo"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"baz": {
|
||||
"mirroring": {
|
||||
"service": "foo",
|
||||
"maxBodySize": 42,
|
||||
"mirrors": [
|
||||
{
|
||||
"name": "foo",
|
||||
"percent": 42
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"foo": {
|
||||
"loadBalancer": {
|
||||
"sticky": {
|
||||
"cookie": {
|
||||
"name": "foo",
|
||||
"secure": true,
|
||||
"httpOnly": true,
|
||||
"sameSite": "foo"
|
||||
}
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "xxxx"
|
||||
}
|
||||
],
|
||||
"healthCheck": {
|
||||
"scheme": "foo",
|
||||
"path": "foo",
|
||||
"port": 42,
|
||||
"interval": "foo",
|
||||
"timeout": "foo",
|
||||
"hostname": "xxxx",
|
||||
"followRedirects": true,
|
||||
"headers": {
|
||||
"foo": "bar"
|
||||
}
|
||||
},
|
||||
"passHostHeader": true,
|
||||
"responseForwarding": {
|
||||
"flushInterval": "foo"
|
||||
},
|
||||
"serversTransport": "foo"
|
||||
}
|
||||
}
|
||||
},
|
||||
"middlewares": {
|
||||
"foo": {
|
||||
"addPrefix": {
|
||||
"prefix": "foo"
|
||||
},
|
||||
"stripPrefix": {
|
||||
"prefixes": [
|
||||
"foo"
|
||||
],
|
||||
"forceSlash": true
|
||||
},
|
||||
"stripPrefixRegex": {
|
||||
"regex": [
|
||||
"foo"
|
||||
]
|
||||
},
|
||||
"replacePath": {
|
||||
"path": "foo"
|
||||
},
|
||||
"replacePathRegex": {
|
||||
"regex": "foo",
|
||||
"replacement": "foo"
|
||||
},
|
||||
"chain": {
|
||||
"middlewares": [
|
||||
"foo"
|
||||
]
|
||||
},
|
||||
"ipWhiteList": {
|
||||
"sourceRange": [
|
||||
"xxxx"
|
||||
],
|
||||
"ipStrategy": {
|
||||
"depth": 42,
|
||||
"excludedIPs": [
|
||||
"xxxx"
|
||||
]
|
||||
}
|
||||
},
|
||||
"headers": {
|
||||
"customRequestHeaders": {
|
||||
"foo": "bar"
|
||||
},
|
||||
"customResponseHeaders": {
|
||||
"foo": "bar"
|
||||
},
|
||||
"accessControlAllowCredentials": true,
|
||||
"accessControlAllowHeaders": [
|
||||
"foo"
|
||||
],
|
||||
"accessControlAllowMethods": [
|
||||
"foo"
|
||||
],
|
||||
"accessControlAllowOrigin": "xxxx",
|
||||
"accessControlAllowOriginList": [
|
||||
"xxxx"
|
||||
],
|
||||
"accessControlAllowOriginListRegex": [
|
||||
"xxxx"
|
||||
],
|
||||
"accessControlExposeHeaders": [
|
||||
"foo"
|
||||
],
|
||||
"accessControlMaxAge": 42,
|
||||
"addVaryHeader": true,
|
||||
"allowedHosts": [
|
||||
"xxxx"
|
||||
],
|
||||
"hostsProxyHeaders": [
|
||||
"foo"
|
||||
],
|
||||
"sslRedirect": true,
|
||||
"sslTemporaryRedirect": true,
|
||||
"sslHost": "xxxx",
|
||||
"sslForceHost": true,
|
||||
"stsSeconds": 42,
|
||||
"stsIncludeSubdomains": true,
|
||||
"stsPreload": true,
|
||||
"forceSTSHeader": true,
|
||||
"frameDeny": true,
|
||||
"customFrameOptionsValue": "xxxx",
|
||||
"contentTypeNosniff": true,
|
||||
"browserXssFilter": true,
|
||||
"customBrowserXSSValue": "xxxx",
|
||||
"contentSecurityPolicy": "xxxx",
|
||||
"publicKey": "xxxx",
|
||||
"referrerPolicy": "foo",
|
||||
"featurePolicy": "foo",
|
||||
"isDevelopment": true
|
||||
},
|
||||
"errors": {
|
||||
"status": [
|
||||
"foo"
|
||||
],
|
||||
"service": "foo",
|
||||
"query": "foo"
|
||||
},
|
||||
"rateLimit": {
|
||||
"average": 42,
|
||||
"period": 42,
|
||||
"burst": 42,
|
||||
"sourceCriterion": {
|
||||
"ipStrategy": {
|
||||
"depth": 42,
|
||||
"excludedIPs": [
|
||||
"xxxx"
|
||||
]
|
||||
},
|
||||
"requestHeaderName": "foo",
|
||||
"requestHost": true
|
||||
}
|
||||
},
|
||||
"redirectRegex": {
|
||||
"regex": "xxxx",
|
||||
"replacement": "xxxx",
|
||||
"permanent": true
|
||||
},
|
||||
"redirectScheme": {
|
||||
"scheme": "foo",
|
||||
"port": "foo",
|
||||
"permanent": true
|
||||
},
|
||||
"basicAuth": {
|
||||
"users": [
|
||||
"xxxx"
|
||||
],
|
||||
"usersFile": "xxxx",
|
||||
"realm": "xxxx",
|
||||
"removeHeader": true,
|
||||
"headerField": "foo"
|
||||
},
|
||||
"digestAuth": {
|
||||
"users": [
|
||||
"xxxx"
|
||||
],
|
||||
"usersFile": "xxxx",
|
||||
"removeHeader": true,
|
||||
"realm": "xxxx",
|
||||
"headerField": "foo"
|
||||
},
|
||||
"forwardAuth": {
|
||||
"address": "xxxx",
|
||||
"tls": {
|
||||
"ca": "xxxx",
|
||||
"caOptional": true,
|
||||
"cert": "xxxx",
|
||||
"key": "xxxx",
|
||||
"insecureSkipVerify": true
|
||||
},
|
||||
"trustForwardHeader": true,
|
||||
"authResponseHeaders": [
|
||||
"foo"
|
||||
],
|
||||
"authResponseHeadersRegex": "foo",
|
||||
"authRequestHeaders": [
|
||||
"foo"
|
||||
]
|
||||
},
|
||||
"inFlightReq": {
|
||||
"amount": 42,
|
||||
"sourceCriterion": {
|
||||
"ipStrategy": {
|
||||
"depth": 42,
|
||||
"excludedIPs": [
|
||||
"xxxx"
|
||||
]
|
||||
},
|
||||
"requestHeaderName": "foo",
|
||||
"requestHost": true
|
||||
}
|
||||
},
|
||||
"buffering": {
|
||||
"maxRequestBodyBytes": 42,
|
||||
"memRequestBodyBytes": 42,
|
||||
"maxResponseBodyBytes": 42,
|
||||
"memResponseBodyBytes": 42,
|
||||
"retryExpression": "foo"
|
||||
},
|
||||
"circuitBreaker": {
|
||||
"expression": "foo"
|
||||
},
|
||||
"compress": {
|
||||
"excludedContentTypes": [
|
||||
"foo"
|
||||
]
|
||||
},
|
||||
"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
|
||||
},
|
||||
"serialNumber": true
|
||||
}
|
||||
},
|
||||
"retry": {
|
||||
"attempts": 42,
|
||||
"initialInterval": 42
|
||||
},
|
||||
"contentType": {
|
||||
"autoDetect": true
|
||||
},
|
||||
"plugin": {
|
||||
"foo": {
|
||||
"answer": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models": {
|
||||
"foo": {
|
||||
"middlewares": [
|
||||
"foo"
|
||||
],
|
||||
"tls": {
|
||||
"options": "foo",
|
||||
"certResolver": "foo",
|
||||
"domains": [
|
||||
{
|
||||
"main": "xxxx",
|
||||
"sans": [
|
||||
"xxxx"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"serversTransports": {
|
||||
"foo": {
|
||||
"serverName": "xxxx",
|
||||
"insecureSkipVerify": true,
|
||||
"rootCAs": [
|
||||
"xxxx"
|
||||
],
|
||||
"certificates": [
|
||||
{
|
||||
"certFile": "xxxx",
|
||||
"keyFile": "xxxx"
|
||||
}
|
||||
],
|
||||
"maxIdleConnsPerHost": 42,
|
||||
"forwardingTimeouts": {
|
||||
"dialTimeout": 42,
|
||||
"responseHeaderTimeout": 42,
|
||||
"idleConnTimeout": 42
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tcp": {
|
||||
"routers": {
|
||||
"foo": {
|
||||
"entryPoints": [
|
||||
"foo"
|
||||
],
|
||||
"service": "foo",
|
||||
"rule": "xxxx",
|
||||
"tls": {
|
||||
"passthrough": true,
|
||||
"options": "foo",
|
||||
"certResolver": "foo",
|
||||
"domains": [
|
||||
{
|
||||
"main": "xxxx",
|
||||
"sans": [
|
||||
"xxxx"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"bar": {
|
||||
"weighted": {
|
||||
"services": [
|
||||
{
|
||||
"name": "foo",
|
||||
"weight": 42
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"foo": {
|
||||
"loadBalancer": {
|
||||
"terminationDelay": 42,
|
||||
"proxyProtocol": {
|
||||
"version": 42
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"address": "xxxx"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"udp": {
|
||||
"routers": {
|
||||
"foo": {
|
||||
"entryPoints": [
|
||||
"foo"
|
||||
],
|
||||
"service": "foo"
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"bar": {
|
||||
"weighted": {
|
||||
"services": [
|
||||
{
|
||||
"name": "foo",
|
||||
"weight": 42
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"foo": {
|
||||
"loadBalancer": {
|
||||
"servers": [
|
||||
{
|
||||
"address": "xxxx"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tls": {
|
||||
"certificates": [
|
||||
{
|
||||
"certFile": "xxxx",
|
||||
"keyFile": "xxxx",
|
||||
"stores": [
|
||||
"foo"
|
||||
]
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"foo": {
|
||||
"minVersion": "foo",
|
||||
"maxVersion": "foo",
|
||||
"cipherSuites": [
|
||||
"foo"
|
||||
],
|
||||
"curvePreferences": [
|
||||
"foo"
|
||||
],
|
||||
"clientAuth": {},
|
||||
"sniStrict": true,
|
||||
"preferServerCipherSuites": true
|
||||
}
|
||||
},
|
||||
"stores": {
|
||||
"foo": {
|
||||
"defaultCertificate": {
|
||||
"certFile": "xxxx",
|
||||
"keyFile": "xxxx"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,17 +21,17 @@ type Configurations map[string]*Configuration
|
|||
|
||||
// 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"`
|
||||
UDP *UDPConfiguration `json:"udp,omitempty" toml:"udp,omitempty" yaml:"udp,omitempty"`
|
||||
TLS *TLSConfiguration `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty"`
|
||||
HTTP *HTTPConfiguration `json:"http,omitempty" toml:"http,omitempty" yaml:"http,omitempty" export:"true"`
|
||||
TCP *TCPConfiguration `json:"tcp,omitempty" toml:"tcp,omitempty" yaml:"tcp,omitempty" export:"true"`
|
||||
UDP *UDPConfiguration `json:"udp,omitempty" toml:"udp,omitempty" yaml:"udp,omitempty" export:"true"`
|
||||
TLS *TLSConfiguration `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// TLSConfiguration contains all the configuration parameters of a TLS connection.
|
||||
type TLSConfiguration struct {
|
||||
Certificates []*tls.CertAndStores `json:"certificates,omitempty" 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"`
|
||||
Certificates []*tls.CertAndStores `json:"certificates,omitempty" toml:"certificates,omitempty" yaml:"certificates,omitempty" label:"-" export:"true"`
|
||||
Options map[string]tls.Options `json:"options,omitempty" toml:"options,omitempty" yaml:"options,omitempty" export:"true"`
|
||||
Stores map[string]tls.Store `json:"stores,omitempty" toml:"stores,omitempty" yaml:"stores,omitempty" export:"true"`
|
||||
}
|
||||
|
|
|
@ -13,58 +13,58 @@ import (
|
|||
|
||||
// HTTPConfiguration contains all the HTTP configuration parameters.
|
||||
type HTTPConfiguration struct {
|
||||
Routers map[string]*Router `json:"routers,omitempty" toml:"routers,omitempty" yaml:"routers,omitempty"`
|
||||
Services map[string]*Service `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty"`
|
||||
Middlewares map[string]*Middleware `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty"`
|
||||
Models map[string]*Model `json:"models,omitempty" toml:"models,omitempty" yaml:"models,omitempty"`
|
||||
ServersTransports map[string]*ServersTransport `json:"serversTransports,omitempty" toml:"serversTransports,omitempty" yaml:"serversTransports,omitempty" label:"-"`
|
||||
Routers map[string]*Router `json:"routers,omitempty" toml:"routers,omitempty" yaml:"routers,omitempty" export:"true"`
|
||||
Services map[string]*Service `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty" export:"true"`
|
||||
Middlewares map[string]*Middleware `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty" export:"true"`
|
||||
Models map[string]*Model `json:"models,omitempty" toml:"models,omitempty" yaml:"models,omitempty" export:"true"`
|
||||
ServersTransports map[string]*ServersTransport `json:"serversTransports,omitempty" toml:"serversTransports,omitempty" yaml:"serversTransports,omitempty" label:"-" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// Model is a set of default router's values.
|
||||
type Model struct {
|
||||
Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty"`
|
||||
TLS *RouterTLSConfig `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||
Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty" export:"true"`
|
||||
TLS *RouterTLSConfig `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// Service holds a service configuration (can only be of one type at the same time).
|
||||
type Service struct {
|
||||
LoadBalancer *ServersLoadBalancer `json:"loadBalancer,omitempty" toml:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty"`
|
||||
Weighted *WeightedRoundRobin `json:"weighted,omitempty" toml:"weighted,omitempty" yaml:"weighted,omitempty" label:"-"`
|
||||
Mirroring *Mirroring `json:"mirroring,omitempty" toml:"mirroring,omitempty" yaml:"mirroring,omitempty" label:"-"`
|
||||
LoadBalancer *ServersLoadBalancer `json:"loadBalancer,omitempty" toml:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty" export:"true"`
|
||||
Weighted *WeightedRoundRobin `json:"weighted,omitempty" toml:"weighted,omitempty" yaml:"weighted,omitempty" label:"-" export:"true"`
|
||||
Mirroring *Mirroring `json:"mirroring,omitempty" toml:"mirroring,omitempty" yaml:"mirroring,omitempty" label:"-" export:"true"`
|
||||
}
|
||||
|
||||
// +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"`
|
||||
EntryPoints []string `json:"entryPoints,omitempty" toml:"entryPoints,omitempty" yaml:"entryPoints,omitempty" export:"true"`
|
||||
Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty" export:"true"`
|
||||
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty" export:"true"`
|
||||
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" file:"allowEmpty"`
|
||||
Priority int `json:"priority,omitempty" toml:"priority,omitempty,omitzero" yaml:"priority,omitempty" export:"true"`
|
||||
TLS *RouterTLSConfig `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
}
|
||||
|
||||
// +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"`
|
||||
CertResolver string `json:"certResolver,omitempty" toml:"certResolver,omitempty" yaml:"certResolver,omitempty"`
|
||||
Domains []types.Domain `json:"domains,omitempty" toml:"domains,omitempty" yaml:"domains,omitempty"`
|
||||
Options string `json:"options,omitempty" toml:"options,omitempty" yaml:"options,omitempty" export:"true"`
|
||||
CertResolver string `json:"certResolver,omitempty" toml:"certResolver,omitempty" yaml:"certResolver,omitempty" export:"true"`
|
||||
Domains []types.Domain `json:"domains,omitempty" toml:"domains,omitempty" yaml:"domains,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// Mirroring holds the Mirroring configuration.
|
||||
type Mirroring struct {
|
||||
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty"`
|
||||
MaxBodySize *int64 `json:"maxBodySize,omitempty" toml:"maxBodySize,omitempty" yaml:"maxBodySize,omitempty"`
|
||||
Mirrors []MirrorService `json:"mirrors,omitempty" toml:"mirrors,omitempty" yaml:"mirrors,omitempty"`
|
||||
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty" export:"true"`
|
||||
MaxBodySize *int64 `json:"maxBodySize,omitempty" toml:"maxBodySize,omitempty" yaml:"maxBodySize,omitempty" export:"true"`
|
||||
Mirrors []MirrorService `json:"mirrors,omitempty" toml:"mirrors,omitempty" yaml:"mirrors,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// SetDefaults Default values for a WRRService.
|
||||
|
@ -77,24 +77,24 @@ func (m *Mirroring) SetDefaults() {
|
|||
|
||||
// MirrorService holds the MirrorService configuration.
|
||||
type MirrorService struct {
|
||||
Name string `json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty"`
|
||||
Percent int `json:"percent,omitempty" toml:"percent,omitempty" yaml:"percent,omitempty"`
|
||||
Name string `json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty" export:"true"`
|
||||
Percent int `json:"percent,omitempty" toml:"percent,omitempty" yaml:"percent,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// WeightedRoundRobin is a weighted round robin load-balancer of services.
|
||||
type WeightedRoundRobin struct {
|
||||
Services []WRRService `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty"`
|
||||
Sticky *Sticky `json:"sticky,omitempty" toml:"sticky,omitempty" yaml:"sticky,omitempty"`
|
||||
Services []WRRService `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty" export:"true"`
|
||||
Sticky *Sticky `json:"sticky,omitempty" toml:"sticky,omitempty" yaml:"sticky,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// WRRService is a reference to a service load-balanced with weighted round robin.
|
||||
type WRRService struct {
|
||||
Name string `json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty"`
|
||||
Weight *int `json:"weight,omitempty" toml:"weight,omitempty" yaml:"weight,omitempty"`
|
||||
Name string `json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty" export:"true"`
|
||||
Weight *int `json:"weight,omitempty" toml:"weight,omitempty" yaml:"weight,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// SetDefaults Default values for a WRRService.
|
||||
|
@ -107,29 +107,29 @@ func (w *WRRService) SetDefaults() {
|
|||
|
||||
// Sticky holds the sticky configuration.
|
||||
type Sticky struct {
|
||||
Cookie *Cookie `json:"cookie,omitempty" toml:"cookie,omitempty" yaml:"cookie,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||
Cookie *Cookie `json:"cookie,omitempty" toml:"cookie,omitempty" yaml:"cookie,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// Cookie holds the sticky configuration based on cookie.
|
||||
type Cookie struct {
|
||||
Name string `json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty"`
|
||||
Secure bool `json:"secure,omitempty" toml:"secure,omitempty" yaml:"secure,omitempty"`
|
||||
HTTPOnly bool `json:"httpOnly,omitempty" toml:"httpOnly,omitempty" yaml:"httpOnly,omitempty"`
|
||||
SameSite string `json:"sameSite,omitempty" toml:"sameSite,omitempty" yaml:"sameSite,omitempty"`
|
||||
Name string `json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty" export:"true"`
|
||||
Secure bool `json:"secure,omitempty" toml:"secure,omitempty" yaml:"secure,omitempty" export:"true"`
|
||||
HTTPOnly bool `json:"httpOnly,omitempty" toml:"httpOnly,omitempty" yaml:"httpOnly,omitempty" export:"true"`
|
||||
SameSite string `json:"sameSite,omitempty" toml:"sameSite,omitempty" yaml:"sameSite,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// ServersLoadBalancer holds the ServersLoadBalancer configuration.
|
||||
type ServersLoadBalancer struct {
|
||||
Sticky *Sticky `json:"sticky,omitempty" toml:"sticky,omitempty" yaml:"sticky,omitempty" label:"allowEmpty" file:"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"`
|
||||
ServersTransport string `json:"serversTransport,omitempty" toml:"serversTransport,omitempty" yaml:"serversTransport,omitempty"`
|
||||
Sticky *Sticky `json:"sticky,omitempty" toml:"sticky,omitempty" yaml:"sticky,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
Servers []Server `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server" export:"true"`
|
||||
HealthCheck *HealthCheck `json:"healthCheck,omitempty" toml:"healthCheck,omitempty" yaml:"healthCheck,omitempty" export:"true"`
|
||||
PassHostHeader *bool `json:"passHostHeader" toml:"passHostHeader" yaml:"passHostHeader" export:"true"`
|
||||
ResponseForwarding *ResponseForwarding `json:"responseForwarding,omitempty" toml:"responseForwarding,omitempty" yaml:"responseForwarding,omitempty" export:"true"`
|
||||
ServersTransport string `json:"serversTransport,omitempty" toml:"serversTransport,omitempty" yaml:"serversTransport,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// Mergeable tells if the given service is mergeable.
|
||||
|
@ -159,7 +159,7 @@ func (l *ServersLoadBalancer) SetDefaults() {
|
|||
|
||||
// ResponseForwarding holds configuration for the forward of the response.
|
||||
type ResponseForwarding struct {
|
||||
FlushInterval string `json:"flushInterval,omitempty" toml:"flushInterval,omitempty" yaml:"flushInterval,omitempty"`
|
||||
FlushInterval string `json:"flushInterval,omitempty" toml:"flushInterval,omitempty" yaml:"flushInterval,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
@ -180,16 +180,16 @@ func (s *Server) SetDefaults() {
|
|||
|
||||
// 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"`
|
||||
Scheme string `json:"scheme,omitempty" toml:"scheme,omitempty" yaml:"scheme,omitempty" export:"true"`
|
||||
Path string `json:"path,omitempty" toml:"path,omitempty" yaml:"path,omitempty" export:"true"`
|
||||
Port int `json:"port,omitempty" toml:"port,omitempty,omitzero" yaml:"port,omitempty" export:"true"`
|
||||
// FIXME change string to ptypes.Duration
|
||||
Interval string `json:"interval,omitempty" toml:"interval,omitempty" yaml:"interval,omitempty"`
|
||||
Interval string `json:"interval,omitempty" toml:"interval,omitempty" yaml:"interval,omitempty" export:"true"`
|
||||
// FIXME change string to ptypes.Duration
|
||||
Timeout string `json:"timeout,omitempty" toml:"timeout,omitempty" yaml:"timeout,omitempty"`
|
||||
Timeout string `json:"timeout,omitempty" toml:"timeout,omitempty" yaml:"timeout,omitempty" export:"true"`
|
||||
Hostname string `json:"hostname,omitempty" toml:"hostname,omitempty" yaml:"hostname,omitempty"`
|
||||
FollowRedirects *bool `json:"followRedirects" toml:"followRedirects" yaml:"followRedirects"`
|
||||
Headers map[string]string `json:"headers,omitempty" toml:"headers,omitempty" yaml:"headers,omitempty"`
|
||||
FollowRedirects *bool `json:"followRedirects" toml:"followRedirects" yaml:"followRedirects" export:"true"`
|
||||
Headers map[string]string `json:"headers,omitempty" toml:"headers,omitempty" yaml:"headers,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// SetDefaults Default values for a HealthCheck.
|
||||
|
@ -202,10 +202,10 @@ func (h *HealthCheck) SetDefaults() {
|
|||
|
||||
// ServersTransport options to configure communication between Traefik and the servers.
|
||||
type ServersTransport struct {
|
||||
ServerName string `description:"ServerName used to contact the server" json:"serverName,omitempty" toml:"serverName,omitempty" yaml:"serverName,omitempty" export:"true"`
|
||||
ServerName string `description:"ServerName used to contact the server" json:"serverName,omitempty" toml:"serverName,omitempty" yaml:"serverName,omitempty"`
|
||||
InsecureSkipVerify bool `description:"Disable SSL certificate verification." json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty" export:"true"`
|
||||
RootCAs []tls.FileOrContent `description:"Add cert file for self-signed certificate." json:"rootCAs,omitempty" toml:"rootCAs,omitempty" yaml:"rootCAs,omitempty"`
|
||||
Certificates tls.Certificates `description:"Certificates for mTLS." json:"certificates,omitempty" toml:"certificates,omitempty" yaml:"certificates,omitempty"`
|
||||
Certificates tls.Certificates `description:"Certificates for mTLS." json:"certificates,omitempty" toml:"certificates,omitempty" yaml:"certificates,omitempty" export:"true"`
|
||||
MaxIdleConnsPerHost int `description:"If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used" json:"maxIdleConnsPerHost,omitempty" toml:"maxIdleConnsPerHost,omitempty" yaml:"maxIdleConnsPerHost,omitempty" export:"true"`
|
||||
ForwardingTimeouts *ForwardingTimeouts `description:"Timeouts for requests forwarded to the backend servers." json:"forwardingTimeouts,omitempty" toml:"forwardingTimeouts,omitempty" yaml:"forwardingTimeouts,omitempty" export:"true"`
|
||||
}
|
||||
|
|
|
@ -16,30 +16,30 @@ import (
|
|||
|
||||
// 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"`
|
||||
InFlightReq *InFlightReq `json:"inFlightReq,omitempty" toml:"inFlightReq,omitempty" yaml:"inFlightReq,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" file:"allowEmpty"`
|
||||
PassTLSClientCert *PassTLSClientCert `json:"passTLSClientCert,omitempty" toml:"passTLSClientCert,omitempty" yaml:"passTLSClientCert,omitempty"`
|
||||
Retry *Retry `json:"retry,omitempty" toml:"retry,omitempty" yaml:"retry,omitempty"`
|
||||
ContentType *ContentType `json:"contentType,omitempty" toml:"contentType,omitempty" yaml:"contentType,omitempty"`
|
||||
AddPrefix *AddPrefix `json:"addPrefix,omitempty" toml:"addPrefix,omitempty" yaml:"addPrefix,omitempty" export:"true"`
|
||||
StripPrefix *StripPrefix `json:"stripPrefix,omitempty" toml:"stripPrefix,omitempty" yaml:"stripPrefix,omitempty" export:"true"`
|
||||
StripPrefixRegex *StripPrefixRegex `json:"stripPrefixRegex,omitempty" toml:"stripPrefixRegex,omitempty" yaml:"stripPrefixRegex,omitempty" export:"true"`
|
||||
ReplacePath *ReplacePath `json:"replacePath,omitempty" toml:"replacePath,omitempty" yaml:"replacePath,omitempty" export:"true"`
|
||||
ReplacePathRegex *ReplacePathRegex `json:"replacePathRegex,omitempty" toml:"replacePathRegex,omitempty" yaml:"replacePathRegex,omitempty" export:"true"`
|
||||
Chain *Chain `json:"chain,omitempty" toml:"chain,omitempty" yaml:"chain,omitempty" export:"true"`
|
||||
IPWhiteList *IPWhiteList `json:"ipWhiteList,omitempty" toml:"ipWhiteList,omitempty" yaml:"ipWhiteList,omitempty" export:"true"`
|
||||
Headers *Headers `json:"headers,omitempty" toml:"headers,omitempty" yaml:"headers,omitempty" export:"true"`
|
||||
Errors *ErrorPage `json:"errors,omitempty" toml:"errors,omitempty" yaml:"errors,omitempty" export:"true"`
|
||||
RateLimit *RateLimit `json:"rateLimit,omitempty" toml:"rateLimit,omitempty" yaml:"rateLimit,omitempty" export:"true"`
|
||||
RedirectRegex *RedirectRegex `json:"redirectRegex,omitempty" toml:"redirectRegex,omitempty" yaml:"redirectRegex,omitempty" export:"true"`
|
||||
RedirectScheme *RedirectScheme `json:"redirectScheme,omitempty" toml:"redirectScheme,omitempty" yaml:"redirectScheme,omitempty" export:"true"`
|
||||
BasicAuth *BasicAuth `json:"basicAuth,omitempty" toml:"basicAuth,omitempty" yaml:"basicAuth,omitempty" export:"true"`
|
||||
DigestAuth *DigestAuth `json:"digestAuth,omitempty" toml:"digestAuth,omitempty" yaml:"digestAuth,omitempty" export:"true"`
|
||||
ForwardAuth *ForwardAuth `json:"forwardAuth,omitempty" toml:"forwardAuth,omitempty" yaml:"forwardAuth,omitempty" export:"true"`
|
||||
InFlightReq *InFlightReq `json:"inFlightReq,omitempty" toml:"inFlightReq,omitempty" yaml:"inFlightReq,omitempty" export:"true"`
|
||||
Buffering *Buffering `json:"buffering,omitempty" toml:"buffering,omitempty" yaml:"buffering,omitempty" export:"true"`
|
||||
CircuitBreaker *CircuitBreaker `json:"circuitBreaker,omitempty" toml:"circuitBreaker,omitempty" yaml:"circuitBreaker,omitempty" export:"true"`
|
||||
Compress *Compress `json:"compress,omitempty" toml:"compress,omitempty" yaml:"compress,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
PassTLSClientCert *PassTLSClientCert `json:"passTLSClientCert,omitempty" toml:"passTLSClientCert,omitempty" yaml:"passTLSClientCert,omitempty" export:"true"`
|
||||
Retry *Retry `json:"retry,omitempty" toml:"retry,omitempty" yaml:"retry,omitempty" export:"true"`
|
||||
ContentType *ContentType `json:"contentType,omitempty" toml:"contentType,omitempty" yaml:"contentType,omitempty" export:"true"`
|
||||
|
||||
Plugin map[string]PluginConf `json:"plugin,omitempty" toml:"plugin,omitempty" yaml:"plugin,omitempty"`
|
||||
Plugin map[string]PluginConf `json:"plugin,omitempty" toml:"plugin,omitempty" yaml:"plugin,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
@ -54,23 +54,14 @@ type Middleware struct {
|
|||
// and it is going to be kept that way in order to support users currently relying on it.
|
||||
// This middleware exists to enable the correct behavior until at least the default one can be changed in a future version.
|
||||
type ContentType struct {
|
||||
AutoDetect bool `json:"autoDetect,omitempty" toml:"autoDetect,omitempty" yaml:"autoDetect,omitempty"`
|
||||
AutoDetect bool `json:"autoDetect,omitempty" toml:"autoDetect,omitempty" yaml:"autoDetect,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +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"`
|
||||
Prefix string `json:"prefix,omitempty" toml:"prefix,omitempty" yaml:"prefix,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
@ -80,7 +71,7 @@ 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"`
|
||||
RemoveHeader bool `json:"removeHeader,omitempty" toml:"removeHeader,omitempty" yaml:"removeHeader,omitempty" export:"true"`
|
||||
HeaderField string `json:"headerField,omitempty" toml:"headerField,omitempty" yaml:"headerField,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
|
@ -88,25 +79,25 @@ type BasicAuth struct {
|
|||
|
||||
// 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"`
|
||||
MaxRequestBodyBytes int64 `json:"maxRequestBodyBytes,omitempty" toml:"maxRequestBodyBytes,omitempty" yaml:"maxRequestBodyBytes,omitempty" export:"true"`
|
||||
MemRequestBodyBytes int64 `json:"memRequestBodyBytes,omitempty" toml:"memRequestBodyBytes,omitempty" yaml:"memRequestBodyBytes,omitempty" export:"true"`
|
||||
MaxResponseBodyBytes int64 `json:"maxResponseBodyBytes,omitempty" toml:"maxResponseBodyBytes,omitempty" yaml:"maxResponseBodyBytes,omitempty" export:"true"`
|
||||
MemResponseBodyBytes int64 `json:"memResponseBodyBytes,omitempty" toml:"memResponseBodyBytes,omitempty" yaml:"memResponseBodyBytes,omitempty" export:"true"`
|
||||
RetryExpression string `json:"retryExpression,omitempty" toml:"retryExpression,omitempty" yaml:"retryExpression,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// Chain holds a chain of middlewares.
|
||||
type Chain struct {
|
||||
Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty"`
|
||||
Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// CircuitBreaker holds the circuit breaker configuration.
|
||||
type CircuitBreaker struct {
|
||||
Expression string `json:"expression,omitempty" toml:"expression,omitempty" yaml:"expression,omitempty"`
|
||||
Expression string `json:"expression,omitempty" toml:"expression,omitempty" yaml:"expression,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
@ -122,7 +113,7 @@ type Compress struct {
|
|||
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"`
|
||||
RemoveHeader bool `json:"removeHeader,omitempty" toml:"removeHeader,omitempty" yaml:"removeHeader,omitempty" export:"true"`
|
||||
Realm string `json:"realm,omitempty" toml:"realm,omitempty" yaml:"realm,omitempty"`
|
||||
HeaderField string `json:"headerField,omitempty" toml:"headerField,omitempty" yaml:"headerField,omitempty" export:"true"`
|
||||
}
|
||||
|
@ -131,9 +122,9 @@ type DigestAuth struct {
|
|||
|
||||
// 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"`
|
||||
Status []string `json:"status,omitempty" toml:"status,omitempty" yaml:"status,omitempty" export:"true"`
|
||||
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty" export:"true"`
|
||||
Query string `json:"query,omitempty" toml:"query,omitempty" yaml:"query,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
@ -141,26 +132,26 @@ type ErrorPage struct {
|
|||
// 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"`
|
||||
TLS *ClientTLS `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
|
||||
TrustForwardHeader bool `json:"trustForwardHeader,omitempty" toml:"trustForwardHeader,omitempty" yaml:"trustForwardHeader,omitempty" export:"true"`
|
||||
AuthResponseHeaders []string `json:"authResponseHeaders,omitempty" toml:"authResponseHeaders,omitempty" yaml:"authResponseHeaders,omitempty"`
|
||||
AuthResponseHeadersRegex string `json:"authResponseHeadersRegex,omitempty" toml:"authResponseHeadersRegex,omitempty" yaml:"authResponseHeadersRegex,omitempty"`
|
||||
AuthRequestHeaders []string `json:"authRequestHeaders,omitempty" toml:"authRequestHeaders,omitempty" yaml:"authRequestHeaders,omitempty"`
|
||||
AuthResponseHeaders []string `json:"authResponseHeaders,omitempty" toml:"authResponseHeaders,omitempty" yaml:"authResponseHeaders,omitempty" export:"true"`
|
||||
AuthResponseHeadersRegex string `json:"authResponseHeadersRegex,omitempty" toml:"authResponseHeadersRegex,omitempty" yaml:"authResponseHeadersRegex,omitempty" export:"true"`
|
||||
AuthRequestHeaders []string `json:"authRequestHeaders,omitempty" toml:"authRequestHeaders,omitempty" yaml:"authRequestHeaders,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +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"`
|
||||
CustomRequestHeaders map[string]string `json:"customRequestHeaders,omitempty" toml:"customRequestHeaders,omitempty" yaml:"customRequestHeaders,omitempty" export:"true"`
|
||||
CustomResponseHeaders map[string]string `json:"customResponseHeaders,omitempty" toml:"customResponseHeaders,omitempty" yaml:"customResponseHeaders,omitempty" export:"true"`
|
||||
|
||||
// AccessControlAllowCredentials is only valid if true. false is ignored.
|
||||
AccessControlAllowCredentials bool `json:"accessControlAllowCredentials,omitempty" toml:"accessControlAllowCredentials,omitempty" yaml:"accessControlAllowCredentials,omitempty"`
|
||||
AccessControlAllowCredentials bool `json:"accessControlAllowCredentials,omitempty" toml:"accessControlAllowCredentials,omitempty" yaml:"accessControlAllowCredentials,omitempty" export:"true"`
|
||||
// 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"`
|
||||
AccessControlAllowHeaders []string `json:"accessControlAllowHeaders,omitempty" toml:"accessControlAllowHeaders,omitempty" yaml:"accessControlAllowHeaders,omitempty" export:"true"`
|
||||
// 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"`
|
||||
AccessControlAllowMethods []string `json:"accessControlAllowMethods,omitempty" toml:"accessControlAllowMethods,omitempty" yaml:"accessControlAllowMethods,omitempty" export:"true"`
|
||||
// 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"` // Deprecated
|
||||
// AccessControlAllowOriginList is a list of allowable origins. Can also be a wildcard origin "*".
|
||||
|
@ -168,33 +159,33 @@ type Headers struct {
|
|||
// AccessControlAllowOriginListRegex is a list of allowable origins written following the Regular Expression syntax (https://golang.org/pkg/regexp/).
|
||||
AccessControlAllowOriginListRegex []string `json:"accessControlAllowOriginListRegex,omitempty" toml:"accessControlAllowOriginListRegex,omitempty" yaml:"accessControlAllowOriginListRegex,omitempty"`
|
||||
// AccessControlExposeHeaders sets valid headers for the response.
|
||||
AccessControlExposeHeaders []string `json:"accessControlExposeHeaders,omitempty" toml:"accessControlExposeHeaders,omitempty" yaml:"accessControlExposeHeaders,omitempty"`
|
||||
AccessControlExposeHeaders []string `json:"accessControlExposeHeaders,omitempty" toml:"accessControlExposeHeaders,omitempty" yaml:"accessControlExposeHeaders,omitempty" export:"true"`
|
||||
// AccessControlMaxAge sets the time that a preflight request may be cached.
|
||||
AccessControlMaxAge int64 `json:"accessControlMaxAge,omitempty" toml:"accessControlMaxAge,omitempty" yaml:"accessControlMaxAge,omitempty"`
|
||||
AccessControlMaxAge int64 `json:"accessControlMaxAge,omitempty" toml:"accessControlMaxAge,omitempty" yaml:"accessControlMaxAge,omitempty" export:"true"`
|
||||
// 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"`
|
||||
AddVaryHeader bool `json:"addVaryHeader,omitempty" toml:"addVaryHeader,omitempty" yaml:"addVaryHeader,omitempty" export:"true"`
|
||||
|
||||
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"`
|
||||
HostsProxyHeaders []string `json:"hostsProxyHeaders,omitempty" toml:"hostsProxyHeaders,omitempty" yaml:"hostsProxyHeaders,omitempty" export:"true"`
|
||||
SSLRedirect bool `json:"sslRedirect,omitempty" toml:"sslRedirect,omitempty" yaml:"sslRedirect,omitempty" export:"true"`
|
||||
SSLTemporaryRedirect bool `json:"sslTemporaryRedirect,omitempty" toml:"sslTemporaryRedirect,omitempty" yaml:"sslTemporaryRedirect,omitempty" export:"true"`
|
||||
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"`
|
||||
SSLForceHost bool `json:"sslForceHost,omitempty" toml:"sslForceHost,omitempty" yaml:"sslForceHost,omitempty" export:"true"`
|
||||
STSSeconds int64 `json:"stsSeconds,omitempty" toml:"stsSeconds,omitempty" yaml:"stsSeconds,omitempty" export:"true"`
|
||||
STSIncludeSubdomains bool `json:"stsIncludeSubdomains,omitempty" toml:"stsIncludeSubdomains,omitempty" yaml:"stsIncludeSubdomains,omitempty" export:"true"`
|
||||
STSPreload bool `json:"stsPreload,omitempty" toml:"stsPreload,omitempty" yaml:"stsPreload,omitempty" export:"true"`
|
||||
ForceSTSHeader bool `json:"forceSTSHeader,omitempty" toml:"forceSTSHeader,omitempty" yaml:"forceSTSHeader,omitempty" export:"true"`
|
||||
FrameDeny bool `json:"frameDeny,omitempty" toml:"frameDeny,omitempty" yaml:"frameDeny,omitempty" export:"true"`
|
||||
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"`
|
||||
ContentTypeNosniff bool `json:"contentTypeNosniff,omitempty" toml:"contentTypeNosniff,omitempty" yaml:"contentTypeNosniff,omitempty" export:"true"`
|
||||
BrowserXSSFilter bool `json:"browserXssFilter,omitempty" toml:"browserXssFilter,omitempty" yaml:"browserXssFilter,omitempty" export:"true"`
|
||||
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"`
|
||||
FeaturePolicy string `json:"featurePolicy,omitempty" toml:"featurePolicy,omitempty" yaml:"featurePolicy,omitempty"`
|
||||
IsDevelopment bool `json:"isDevelopment,omitempty" toml:"isDevelopment,omitempty" yaml:"isDevelopment,omitempty"`
|
||||
ReferrerPolicy string `json:"referrerPolicy,omitempty" toml:"referrerPolicy,omitempty" yaml:"referrerPolicy,omitempty" export:"true"`
|
||||
FeaturePolicy string `json:"featurePolicy,omitempty" toml:"featurePolicy,omitempty" yaml:"featurePolicy,omitempty" export:"true"`
|
||||
IsDevelopment bool `json:"isDevelopment,omitempty" toml:"isDevelopment,omitempty" yaml:"isDevelopment,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// HasCustomHeadersDefined checks to see if any of the custom header elements have been set.
|
||||
|
@ -282,23 +273,23 @@ func (s *IPStrategy) Get() (ip.Strategy, error) {
|
|||
// 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" file:"allowEmpty"`
|
||||
IPStrategy *IPStrategy `json:"ipStrategy,omitempty" toml:"ipStrategy,omitempty" yaml:"ipStrategy,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// InFlightReq limits the number of requests being processed and served concurrently.
|
||||
type InFlightReq struct {
|
||||
Amount int64 `json:"amount,omitempty" toml:"amount,omitempty" yaml:"amount,omitempty"`
|
||||
SourceCriterion *SourceCriterion `json:"sourceCriterion,omitempty" toml:"sourceCriterion,omitempty" yaml:"sourceCriterion,omitempty"`
|
||||
Amount int64 `json:"amount,omitempty" toml:"amount,omitempty" yaml:"amount,omitempty" export:"true"`
|
||||
SourceCriterion *SourceCriterion `json:"sourceCriterion,omitempty" toml:"sourceCriterion,omitempty" yaml:"sourceCriterion,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +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"`
|
||||
PEM bool `json:"pem,omitempty" toml:"pem,omitempty" yaml:"pem,omitempty" export:"true"`
|
||||
Info *TLSClientCertificateInfo `json:"info,omitempty" toml:"info,omitempty" yaml:"info,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
@ -307,9 +298,9 @@ type PassTLSClientCert struct {
|
|||
// If none are set, the default is to use the request's remote address field.
|
||||
// All fields are mutually exclusive.
|
||||
type SourceCriterion struct {
|
||||
IPStrategy *IPStrategy `json:"ipStrategy,omitempty" toml:"ipStrategy,omitempty" yaml:"ipStrategy,omitempty"`
|
||||
RequestHeaderName string `json:"requestHeaderName,omitempty" toml:"requestHeaderName,omitempty" yaml:"requestHeaderName,omitempty"`
|
||||
RequestHost bool `json:"requestHost,omitempty" toml:"requestHost,omitempty" yaml:"requestHost,omitempty"`
|
||||
IPStrategy *IPStrategy `json:"ipStrategy,omitempty" toml:"ipStrategy,omitempty" yaml:"ipStrategy,omitempty" export:"true"`
|
||||
RequestHeaderName string `json:"requestHeaderName,omitempty" toml:"requestHeaderName,omitempty" yaml:"requestHeaderName,omitempty" export:"true"`
|
||||
RequestHost bool `json:"requestHost,omitempty" toml:"requestHost,omitempty" yaml:"requestHost,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
@ -320,17 +311,17 @@ type RateLimit struct {
|
|||
// It defaults to 0, which means no rate limiting.
|
||||
// The rate is actually defined by dividing Average by Period. So for a rate below 1req/s,
|
||||
// one needs to define a Period larger than a second.
|
||||
Average int64 `json:"average,omitempty" toml:"average,omitempty" yaml:"average,omitempty"`
|
||||
Average int64 `json:"average,omitempty" toml:"average,omitempty" yaml:"average,omitempty" export:"true"`
|
||||
|
||||
// Period, in combination with Average, defines the actual maximum rate, such as:
|
||||
// r = Average / Period. It defaults to a second.
|
||||
Period ptypes.Duration `json:"period,omitempty" toml:"period,omitempty" yaml:"period,omitempty"`
|
||||
Period ptypes.Duration `json:"period,omitempty" toml:"period,omitempty" yaml:"period,omitempty" export:"true"`
|
||||
|
||||
// Burst is the maximum number of requests allowed to arrive in the same arbitrarily small period of time.
|
||||
// It defaults to 1.
|
||||
Burst int64 `json:"burst,omitempty" toml:"burst,omitempty" yaml:"burst,omitempty"`
|
||||
Burst int64 `json:"burst,omitempty" toml:"burst,omitempty" yaml:"burst,omitempty" export:"true"`
|
||||
|
||||
SourceCriterion *SourceCriterion `json:"sourceCriterion,omitempty" toml:"sourceCriterion,omitempty" yaml:"sourceCriterion,omitempty"`
|
||||
SourceCriterion *SourceCriterion `json:"sourceCriterion,omitempty" toml:"sourceCriterion,omitempty" yaml:"sourceCriterion,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// SetDefaults sets the default values on a RateLimit.
|
||||
|
@ -345,47 +336,47 @@ func (r *RateLimit) SetDefaults() {
|
|||
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"`
|
||||
Permanent bool `json:"permanent,omitempty" toml:"permanent,omitempty" yaml:"permanent,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +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"`
|
||||
Scheme string `json:"scheme,omitempty" toml:"scheme,omitempty" yaml:"scheme,omitempty" export:"true"`
|
||||
Port string `json:"port,omitempty" toml:"port,omitempty" yaml:"port,omitempty" export:"true"`
|
||||
Permanent bool `json:"permanent,omitempty" toml:"permanent,omitempty" yaml:"permanent,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// ReplacePath holds the ReplacePath configuration.
|
||||
type ReplacePath struct {
|
||||
Path string `json:"path,omitempty" toml:"path,omitempty" yaml:"path,omitempty"`
|
||||
Path string `json:"path,omitempty" toml:"path,omitempty" yaml:"path,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +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"`
|
||||
Regex string `json:"regex,omitempty" toml:"regex,omitempty" yaml:"regex,omitempty" export:"true"`
|
||||
Replacement string `json:"replacement,omitempty" toml:"replacement,omitempty" yaml:"replacement,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// Retry holds the retry configuration.
|
||||
type Retry struct {
|
||||
Attempts int `json:"attempts,omitempty" toml:"attempts,omitempty" yaml:"attempts,omitempty"`
|
||||
InitialInterval ptypes.Duration `json:"initialInterval,omitempty" toml:"initialInterval,omitempty" yaml:"initialInterval,omitempty"`
|
||||
Attempts int `json:"attempts,omitempty" toml:"attempts,omitempty" yaml:"attempts,omitempty" export:"true"`
|
||||
InitialInterval ptypes.Duration `json:"initialInterval,omitempty" toml:"initialInterval,omitempty" yaml:"initialInterval,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"`
|
||||
ForceSlash bool `json:"forceSlash,omitempty" toml:"forceSlash,omitempty" yaml:"forceSlash,omitempty"` // Deprecated
|
||||
Prefixes []string `json:"prefixes,omitempty" toml:"prefixes,omitempty" yaml:"prefixes,omitempty" export:"true"`
|
||||
ForceSlash bool `json:"forceSlash,omitempty" toml:"forceSlash,omitempty" yaml:"forceSlash,omitempty" export:"true"` // Deprecated
|
||||
}
|
||||
|
||||
// SetDefaults Default values for a StripPrefix.
|
||||
|
@ -397,33 +388,33 @@ func (s *StripPrefix) SetDefaults() {
|
|||
|
||||
// StripPrefixRegex holds the StripPrefixRegex configuration.
|
||||
type StripPrefixRegex struct {
|
||||
Regex []string `json:"regex,omitempty" toml:"regex,omitempty" yaml:"regex,omitempty"`
|
||||
Regex []string `json:"regex,omitempty" toml:"regex,omitempty" yaml:"regex,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +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"`
|
||||
SerialNumber bool `json:"serialNumber,omitempty" toml:"serialNumber,omitempty" yaml:"serialNumber,omitempty"`
|
||||
NotAfter bool `json:"notAfter,omitempty" toml:"notAfter,omitempty" yaml:"notAfter,omitempty" export:"true"`
|
||||
NotBefore bool `json:"notBefore,omitempty" toml:"notBefore,omitempty" yaml:"notBefore,omitempty" export:"true"`
|
||||
Sans bool `json:"sans,omitempty" toml:"sans,omitempty" yaml:"sans,omitempty" export:"true"`
|
||||
Subject *TLSCLientCertificateDNInfo `json:"subject,omitempty" toml:"subject,omitempty" yaml:"subject,omitempty" export:"true"`
|
||||
Issuer *TLSCLientCertificateDNInfo `json:"issuer,omitempty" toml:"issuer,omitempty" yaml:"issuer,omitempty" export:"true"`
|
||||
SerialNumber bool `json:"serialNumber,omitempty" toml:"serialNumber,omitempty" yaml:"serialNumber,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// TLSCLientCertificateDNInfo holds the client TLS certificate distinguished name info configuration
|
||||
// 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"`
|
||||
Country bool `json:"country,omitempty" toml:"country,omitempty" yaml:"country,omitempty" export:"true"`
|
||||
Province bool `json:"province,omitempty" toml:"province,omitempty" yaml:"province,omitempty" export:"true"`
|
||||
Locality bool `json:"locality,omitempty" toml:"locality,omitempty" yaml:"locality,omitempty" export:"true"`
|
||||
Organization bool `json:"organization,omitempty" toml:"organization,omitempty" yaml:"organization,omitempty" export:"true"`
|
||||
CommonName bool `json:"commonName,omitempty" toml:"commonName,omitempty" yaml:"commonName,omitempty" export:"true"`
|
||||
SerialNumber bool `json:"serialNumber,omitempty" toml:"serialNumber,omitempty" yaml:"serialNumber,omitempty" export:"true"`
|
||||
DomainComponent bool `json:"domainComponent,omitempty" toml:"domainComponent,omitempty" yaml:"domainComponent,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
@ -437,10 +428,10 @@ type Users []string
|
|||
// 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"`
|
||||
CAOptional bool `json:"caOptional,omitempty" toml:"caOptional,omitempty" yaml:"caOptional,omitempty" export:"true"`
|
||||
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"`
|
||||
InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// CreateTLSConfig creates a TLS config from ClientTLS structures.
|
||||
|
|
|
@ -10,31 +10,31 @@ import (
|
|||
|
||||
// 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"`
|
||||
Routers map[string]*TCPRouter `json:"routers,omitempty" toml:"routers,omitempty" yaml:"routers,omitempty" export:"true"`
|
||||
Services map[string]*TCPService `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// TCPService holds a tcp service configuration (can only be of one type at the same time).
|
||||
type TCPService struct {
|
||||
LoadBalancer *TCPServersLoadBalancer `json:"loadBalancer,omitempty" toml:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty"`
|
||||
Weighted *TCPWeightedRoundRobin `json:"weighted,omitempty" toml:"weighted,omitempty" yaml:"weighted,omitempty" label:"-"`
|
||||
LoadBalancer *TCPServersLoadBalancer `json:"loadBalancer,omitempty" toml:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty" export:"true"`
|
||||
Weighted *TCPWeightedRoundRobin `json:"weighted,omitempty" toml:"weighted,omitempty" yaml:"weighted,omitempty" label:"-" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// TCPWeightedRoundRobin is a weighted round robin tcp load-balancer of services.
|
||||
type TCPWeightedRoundRobin struct {
|
||||
Services []TCPWRRService `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty"`
|
||||
Services []TCPWRRService `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// TCPWRRService is a reference to a tcp service load-balanced with weighted round robin.
|
||||
type TCPWRRService struct {
|
||||
Name string `json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty"`
|
||||
Weight *int `json:"weight,omitempty" toml:"weight,omitempty" yaml:"weight,omitempty"`
|
||||
Name string `json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty" export:"true"`
|
||||
Weight *int `json:"weight,omitempty" toml:"weight,omitempty" yaml:"weight,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// SetDefaults Default values for a TCPWRRService.
|
||||
|
@ -47,20 +47,20 @@ func (w *TCPWRRService) SetDefaults() {
|
|||
|
||||
// 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"`
|
||||
EntryPoints []string `json:"entryPoints,omitempty" toml:"entryPoints,omitempty" yaml:"entryPoints,omitempty" export:"true"`
|
||||
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty" export:"true"`
|
||||
Rule string `json:"rule,omitempty" toml:"rule,omitempty" yaml:"rule,omitempty"`
|
||||
TLS *RouterTCPTLSConfig `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||
TLS *RouterTCPTLSConfig `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
}
|
||||
|
||||
// +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"`
|
||||
CertResolver string `json:"certResolver,omitempty" toml:"certResolver,omitempty" yaml:"certResolver,omitempty"`
|
||||
Domains []types.Domain `json:"domains,omitempty" toml:"domains,omitempty" yaml:"domains,omitempty"`
|
||||
Passthrough bool `json:"passthrough" toml:"passthrough" yaml:"passthrough" export:"true"`
|
||||
Options string `json:"options,omitempty" toml:"options,omitempty" yaml:"options,omitempty" export:"true"`
|
||||
CertResolver string `json:"certResolver,omitempty" toml:"certResolver,omitempty" yaml:"certResolver,omitempty" export:"true"`
|
||||
Domains []types.Domain `json:"domains,omitempty" toml:"domains,omitempty" yaml:"domains,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
@ -72,9 +72,9 @@ type TCPServersLoadBalancer struct {
|
|||
// connection, to close the reading capability as well, hence fully terminating the
|
||||
// connection. It is a duration in milliseconds, defaulting to 100. A negative value
|
||||
// means an infinite deadline (i.e. the reading capability is never closed).
|
||||
TerminationDelay *int `json:"terminationDelay,omitempty" toml:"terminationDelay,omitempty" yaml:"terminationDelay,omitempty"`
|
||||
ProxyProtocol *ProxyProtocol `json:"proxyProtocol,omitempty" toml:"proxyProtocol,omitempty" yaml:"proxyProtocol,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||
Servers []TCPServer `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server"`
|
||||
TerminationDelay *int `json:"terminationDelay,omitempty" toml:"terminationDelay,omitempty" yaml:"terminationDelay,omitempty" export:"true"`
|
||||
ProxyProtocol *ProxyProtocol `json:"proxyProtocol,omitempty" toml:"proxyProtocol,omitempty" yaml:"proxyProtocol,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
Servers []TCPServer `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server" export:"true"`
|
||||
}
|
||||
|
||||
// SetDefaults Default values for a TCPServersLoadBalancer.
|
||||
|
@ -112,7 +112,7 @@ type TCPServer struct {
|
|||
|
||||
// ProxyProtocol holds the ProxyProtocol configuration.
|
||||
type ProxyProtocol struct {
|
||||
Version int `json:"version,omitempty" toml:"version,omitempty" yaml:"version,omitempty"`
|
||||
Version int `json:"version,omitempty" toml:"version,omitempty" yaml:"version,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// SetDefaults Default values for a ProxyProtocol.
|
||||
|
|
|
@ -8,31 +8,31 @@ import (
|
|||
|
||||
// UDPConfiguration contains all the UDP configuration parameters.
|
||||
type UDPConfiguration struct {
|
||||
Routers map[string]*UDPRouter `json:"routers,omitempty" toml:"routers,omitempty" yaml:"routers,omitempty"`
|
||||
Services map[string]*UDPService `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty"`
|
||||
Routers map[string]*UDPRouter `json:"routers,omitempty" toml:"routers,omitempty" yaml:"routers,omitempty" export:"true"`
|
||||
Services map[string]*UDPService `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// UDPService defines the configuration for a UDP service. All fields are mutually exclusive.
|
||||
type UDPService struct {
|
||||
LoadBalancer *UDPServersLoadBalancer `json:"loadBalancer,omitempty" toml:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty"`
|
||||
Weighted *UDPWeightedRoundRobin `json:"weighted,omitempty" toml:"weighted,omitempty" yaml:"weighted,omitempty" label:"-"`
|
||||
LoadBalancer *UDPServersLoadBalancer `json:"loadBalancer,omitempty" toml:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty" export:"true"`
|
||||
Weighted *UDPWeightedRoundRobin `json:"weighted,omitempty" toml:"weighted,omitempty" yaml:"weighted,omitempty" label:"-" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// UDPWeightedRoundRobin is a weighted round robin UDP load-balancer of services.
|
||||
type UDPWeightedRoundRobin struct {
|
||||
Services []UDPWRRService `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty"`
|
||||
Services []UDPWRRService `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// UDPWRRService is a reference to a UDP service load-balanced with weighted round robin.
|
||||
type UDPWRRService struct {
|
||||
Name string `json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty"`
|
||||
Weight *int `json:"weight,omitempty" toml:"weight,omitempty" yaml:"weight,omitempty"`
|
||||
Name string `json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty" export:"true"`
|
||||
Weight *int `json:"weight,omitempty" toml:"weight,omitempty" yaml:"weight,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// SetDefaults sets the default values for a UDPWRRService.
|
||||
|
@ -45,15 +45,15 @@ func (w *UDPWRRService) SetDefaults() {
|
|||
|
||||
// UDPRouter defines the configuration for an UDP router.
|
||||
type UDPRouter struct {
|
||||
EntryPoints []string `json:"entryPoints,omitempty" toml:"entryPoints,omitempty" yaml:"entryPoints,omitempty"`
|
||||
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty"`
|
||||
EntryPoints []string `json:"entryPoints,omitempty" toml:"entryPoints,omitempty" yaml:"entryPoints,omitempty" export:"true"`
|
||||
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// UDPServersLoadBalancer defines the configuration for a load-balancer of UDP servers.
|
||||
type UDPServersLoadBalancer struct {
|
||||
Servers []UDPServer `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server"`
|
||||
Servers []UDPServer `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server" export:"true"`
|
||||
}
|
||||
|
||||
// Mergeable reports whether the given load-balancer can be merged with the receiver.
|
||||
|
|
|
@ -49,37 +49,6 @@ func (in *AddPrefix) DeepCopy() *AddPrefix {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Auth) DeepCopyInto(out *Auth) {
|
||||
*out = *in
|
||||
if in.Basic != nil {
|
||||
in, out := &in.Basic, &out.Basic
|
||||
*out = new(BasicAuth)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Digest != nil {
|
||||
in, out := &in.Digest, &out.Digest
|
||||
*out = new(DigestAuth)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Forward != nil {
|
||||
in, out := &in.Forward, &out.Forward
|
||||
*out = new(ForwardAuth)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Auth.
|
||||
func (in *Auth) DeepCopy() *Auth {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Auth)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *BasicAuth) DeepCopyInto(out *BasicAuth) {
|
||||
*out = *in
|
||||
|
|
|
@ -5,57 +5,56 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/traefik/traefik/v2/pkg/config/runtime"
|
||||
"github.com/traefik/traefik/v2/pkg/anonymize"
|
||||
"github.com/traefik/traefik/v2/pkg/config/dynamic"
|
||||
"github.com/traefik/traefik/v2/pkg/log"
|
||||
"github.com/traefik/traefik/v2/pkg/metrics"
|
||||
"github.com/traefik/traefik/v2/pkg/safe"
|
||||
"github.com/traefik/traefik/v2/pkg/version"
|
||||
)
|
||||
|
||||
const baseURL = "https://instance-info.pilot.traefik.io/public"
|
||||
|
||||
const tokenHeader = "X-Token"
|
||||
|
||||
const (
|
||||
pilotTimer = 5 * time.Minute
|
||||
maxElapsedTime = 4 * time.Minute
|
||||
baseInstanceInfoURL = "https://instance-info.pilot.traefik.io/public"
|
||||
baseGatewayURL = "https://gateway.pilot.traefik.io"
|
||||
)
|
||||
|
||||
// RunTimeRepresentation is the configuration information exposed by the API handler.
|
||||
type RunTimeRepresentation struct {
|
||||
Routers map[string]*runtime.RouterInfo `json:"routers,omitempty"`
|
||||
Middlewares map[string]*runtime.MiddlewareInfo `json:"middlewares,omitempty"`
|
||||
Services map[string]*serviceInfoRepresentation `json:"services,omitempty"`
|
||||
TCPRouters map[string]*runtime.TCPRouterInfo `json:"tcpRouters,omitempty"`
|
||||
TCPServices map[string]*runtime.TCPServiceInfo `json:"tcpServices,omitempty"`
|
||||
UDPRouters map[string]*runtime.UDPRouterInfo `json:"udpRouters,omitempty"`
|
||||
UDPServices map[string]*runtime.UDPServiceInfo `json:"udpServices,omitempty"`
|
||||
}
|
||||
const (
|
||||
tokenHeader = "X-Token"
|
||||
tokenHashHeader = "X-Token-Hash"
|
||||
)
|
||||
|
||||
type serviceInfoRepresentation struct {
|
||||
*runtime.ServiceInfo
|
||||
ServerStatus map[string]string `json:"serverStatus,omitempty"`
|
||||
}
|
||||
const (
|
||||
pilotInstanceInfoTimer = 5 * time.Minute
|
||||
pilotDynConfTimer = 12 * time.Hour
|
||||
maxElapsedTime = 4 * time.Minute
|
||||
)
|
||||
|
||||
type instanceInfo struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Configuration RunTimeRepresentation `json:"configuration,omitempty"`
|
||||
Metrics []metrics.PilotMetric `json:"metrics,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Metrics []metrics.PilotMetric `json:"metrics,omitempty"`
|
||||
}
|
||||
|
||||
// New creates a new Pilot.
|
||||
func New(token string, metricsRegistry *metrics.PilotRegistry, pool *safe.Pool) *Pilot {
|
||||
tokenHash := fnv.New64a()
|
||||
|
||||
// the `sum64a` implementation of the `Write` method never returns an error.
|
||||
_, _ = tokenHash.Write([]byte(token))
|
||||
|
||||
return &Pilot{
|
||||
rtConfChan: make(chan *runtime.Configuration),
|
||||
dynamicConfigCh: make(chan dynamic.Configuration),
|
||||
client: &client{
|
||||
token: token,
|
||||
httpClient: &http.Client{Timeout: 5 * time.Second},
|
||||
baseURL: baseURL,
|
||||
token: token,
|
||||
tokenHash: fmt.Sprintf("%x", tokenHash.Sum64()),
|
||||
httpClient: &http.Client{Timeout: 5 * time.Second},
|
||||
baseInstanceInfoURL: baseInstanceInfoURL,
|
||||
baseGatewayURL: baseGatewayURL,
|
||||
},
|
||||
routinesPool: pool,
|
||||
metricsRegistry: metricsRegistry,
|
||||
|
@ -67,44 +66,25 @@ type Pilot struct {
|
|||
routinesPool *safe.Pool
|
||||
client *client
|
||||
|
||||
rtConf *runtime.Configuration
|
||||
rtConfChan chan *runtime.Configuration
|
||||
dynamicConfig dynamic.Configuration
|
||||
dynamicConfigCh chan dynamic.Configuration
|
||||
metricsRegistry *metrics.PilotRegistry
|
||||
}
|
||||
|
||||
// SetRuntimeConfiguration stores the runtime configuration.
|
||||
func (p *Pilot) SetRuntimeConfiguration(rtConf *runtime.Configuration) {
|
||||
p.rtConfChan <- rtConf
|
||||
// SetDynamicConfiguration stores the dynamic configuration.
|
||||
func (p *Pilot) SetDynamicConfiguration(dynamicConfig dynamic.Configuration) {
|
||||
p.dynamicConfigCh <- dynamicConfig
|
||||
}
|
||||
|
||||
func (p *Pilot) getRepresentation() RunTimeRepresentation {
|
||||
if p.rtConf == nil {
|
||||
return RunTimeRepresentation{}
|
||||
func (p *Pilot) sendAnonDynConf(ctx context.Context, config dynamic.Configuration) {
|
||||
err := p.client.SendAnonDynConf(ctx, config)
|
||||
if err != nil {
|
||||
log.WithoutContext().Error(err)
|
||||
}
|
||||
|
||||
siRepr := make(map[string]*serviceInfoRepresentation, len(p.rtConf.Services))
|
||||
for k, v := range p.rtConf.Services {
|
||||
siRepr[k] = &serviceInfoRepresentation{
|
||||
ServiceInfo: v,
|
||||
ServerStatus: v.GetAllStatus(),
|
||||
}
|
||||
}
|
||||
|
||||
result := RunTimeRepresentation{
|
||||
Routers: p.rtConf.Routers,
|
||||
Middlewares: p.rtConf.Middlewares,
|
||||
Services: siRepr,
|
||||
TCPRouters: p.rtConf.TCPRouters,
|
||||
TCPServices: p.rtConf.TCPServices,
|
||||
UDPRouters: p.rtConf.UDPRouters,
|
||||
UDPServices: p.rtConf.UDPServices,
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (p *Pilot) sendData(ctx context.Context, conf RunTimeRepresentation, pilotMetrics []metrics.PilotMetric) {
|
||||
err := p.client.SendData(ctx, conf, pilotMetrics)
|
||||
func (p *Pilot) sendInstanceInfo(ctx context.Context, pilotMetrics []metrics.PilotMetric) {
|
||||
err := p.client.SendInstanceInfo(ctx, pilotMetrics)
|
||||
if err != nil {
|
||||
log.WithoutContext().Error(err)
|
||||
}
|
||||
|
@ -112,35 +92,33 @@ func (p *Pilot) sendData(ctx context.Context, conf RunTimeRepresentation, pilotM
|
|||
|
||||
// Tick sends data periodically.
|
||||
func (p *Pilot) Tick(ctx context.Context) {
|
||||
select {
|
||||
case rtConf := <-p.rtConfChan:
|
||||
p.rtConf = rtConf
|
||||
break
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
|
||||
conf := p.getRepresentation()
|
||||
pilotMetrics := p.metricsRegistry.Data()
|
||||
|
||||
p.routinesPool.GoCtx(func(ctxRt context.Context) {
|
||||
p.sendData(ctxRt, conf, pilotMetrics)
|
||||
p.sendInstanceInfo(ctxRt, pilotMetrics)
|
||||
})
|
||||
|
||||
ticker := time.NewTicker(pilotTimer)
|
||||
instanceInfoTicker := time.NewTicker(pilotInstanceInfoTimer)
|
||||
dynConfTicker := time.NewTicker(pilotDynConfTimer)
|
||||
|
||||
for {
|
||||
select {
|
||||
case tick := <-ticker.C:
|
||||
log.WithoutContext().Debugf("Send to pilot: %s", tick)
|
||||
case tick := <-instanceInfoTicker.C:
|
||||
log.WithoutContext().Debugf("Send instance info to pilot: %s", tick)
|
||||
|
||||
conf := p.getRepresentation()
|
||||
pilotMetrics := p.metricsRegistry.Data()
|
||||
|
||||
p.routinesPool.GoCtx(func(ctxRt context.Context) {
|
||||
p.sendData(ctxRt, conf, pilotMetrics)
|
||||
p.sendInstanceInfo(ctxRt, pilotMetrics)
|
||||
})
|
||||
case rtConf := <-p.rtConfChan:
|
||||
p.rtConf = rtConf
|
||||
case tick := <-dynConfTicker.C:
|
||||
log.WithoutContext().Debugf("Send anonymized dynamic configuration to pilot: %s", tick)
|
||||
|
||||
p.routinesPool.GoCtx(func(ctxRt context.Context) {
|
||||
p.sendAnonDynConf(ctxRt, p.dynamicConfig)
|
||||
})
|
||||
case dynamicConfig := <-p.dynamicConfigCh:
|
||||
p.dynamicConfig = dynamicConfig
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
|
@ -148,15 +126,17 @@ func (p *Pilot) Tick(ctx context.Context) {
|
|||
}
|
||||
|
||||
type client struct {
|
||||
httpClient *http.Client
|
||||
baseURL string
|
||||
token string
|
||||
uuid string
|
||||
httpClient *http.Client
|
||||
baseInstanceInfoURL string
|
||||
baseGatewayURL string
|
||||
token string
|
||||
tokenHash string
|
||||
uuid string
|
||||
}
|
||||
|
||||
func (c *client) createUUID() (string, error) {
|
||||
data := []byte(`{"version":"` + version.Version + `","codeName":"` + version.Codename + `"}`)
|
||||
req, err := http.NewRequest(http.MethodPost, c.baseURL+"/", bytes.NewBuffer(data))
|
||||
req, err := http.NewRequest(http.MethodPost, c.baseInstanceInfoURL+"/", bytes.NewBuffer(data))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create request: %w", err)
|
||||
}
|
||||
|
@ -189,22 +169,23 @@ func (c *client) createUUID() (string, error) {
|
|||
return created.ID, nil
|
||||
}
|
||||
|
||||
// SendData sends data to Pilot.
|
||||
func (c *client) SendData(ctx context.Context, rtConf RunTimeRepresentation, pilotMetrics []metrics.PilotMetric) error {
|
||||
exponentialBackOff := backoff.NewExponentialBackOff()
|
||||
exponentialBackOff.MaxElapsedTime = maxElapsedTime
|
||||
// SendAnonDynConf sends anonymized dynamic configuration to Pilot.
|
||||
func (c *client) SendAnonDynConf(ctx context.Context, config dynamic.Configuration) error {
|
||||
anonConfig, err := anonymize.Do(&config, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to anonymize dynamic configuration: %w", err)
|
||||
}
|
||||
|
||||
return backoff.RetryNotify(
|
||||
func() error {
|
||||
return c.sendData(rtConf, pilotMetrics)
|
||||
},
|
||||
backoff.WithContext(exponentialBackOff, ctx),
|
||||
func(err error, duration time.Duration) {
|
||||
log.WithoutContext().Errorf("retry in %s due to: %v ", duration, err)
|
||||
})
|
||||
req, err := http.NewRequest(http.MethodPost, c.baseGatewayURL+"/collect", bytes.NewReader([]byte(anonConfig)))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create request: %w", err)
|
||||
}
|
||||
|
||||
return c.sendDataRetryable(ctx, req)
|
||||
}
|
||||
|
||||
func (c *client) sendData(_ RunTimeRepresentation, pilotMetrics []metrics.PilotMetric) error {
|
||||
// SendInstanceInfo sends instance information to Pilot.
|
||||
func (c *client) SendInstanceInfo(ctx context.Context, pilotMetrics []metrics.PilotMetric) error {
|
||||
if len(c.uuid) == 0 {
|
||||
var err error
|
||||
c.uuid, err = c.createUUID()
|
||||
|
@ -225,29 +206,45 @@ func (c *client) sendData(_ RunTimeRepresentation, pilotMetrics []metrics.PilotM
|
|||
return fmt.Errorf("failed to marshall request body: %w", err)
|
||||
}
|
||||
|
||||
request, err := http.NewRequest(http.MethodPost, c.baseURL+"/command", bytes.NewBuffer(b))
|
||||
req, err := http.NewRequest(http.MethodPost, c.baseInstanceInfoURL+"/command", bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create request: %w", err)
|
||||
return fmt.Errorf("failed to create instance info request: %w", err)
|
||||
}
|
||||
|
||||
request.Header.Set("Content-Type", "application/json")
|
||||
request.Header.Set(tokenHeader, c.token)
|
||||
req.Header.Set(tokenHeader, c.token)
|
||||
|
||||
resp, err := c.httpClient.Do(request)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to call Pilot: %w", err)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read response body: %w", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("wrong status code while sending configuration: %d: %s", resp.StatusCode, body)
|
||||
}
|
||||
|
||||
return nil
|
||||
return c.sendDataRetryable(ctx, req)
|
||||
}
|
||||
|
||||
func (c *client) sendDataRetryable(ctx context.Context, req *http.Request) error {
|
||||
exponentialBackOff := backoff.NewExponentialBackOff()
|
||||
exponentialBackOff.MaxElapsedTime = maxElapsedTime
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set(tokenHashHeader, c.tokenHash)
|
||||
|
||||
return backoff.RetryNotify(
|
||||
func() error {
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to call Pilot: %w", err)
|
||||
}
|
||||
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read response body: %w", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("wrong status code while sending configuration: %d: %s", resp.StatusCode, body)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
backoff.WithContext(exponentialBackOff, ctx),
|
||||
func(err error, duration time.Duration) {
|
||||
log.WithoutContext().Errorf("retry in %s due to: %v ", duration, err)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -4,13 +4,16 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/traefik/traefik/v2/pkg/config/runtime"
|
||||
"github.com/traefik/traefik/v2/pkg/config/dynamic"
|
||||
"github.com/traefik/traefik/v2/pkg/metrics"
|
||||
"github.com/traefik/traefik/v2/pkg/safe"
|
||||
)
|
||||
|
@ -45,15 +48,16 @@ func TestTick(t *testing.T) {
|
|||
})
|
||||
|
||||
pilot := New("token", metrics.RegisterPilot(), safe.NewPool(context.Background()))
|
||||
pilot.client.baseURL = server.URL
|
||||
|
||||
pilot.client.baseInstanceInfoURL = server.URL
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
t.Cleanup(cancel)
|
||||
|
||||
go pilot.Tick(ctx)
|
||||
|
||||
pilot.SetRuntimeConfiguration(&runtime.Configuration{})
|
||||
pilot.SetRuntimeConfiguration(&runtime.Configuration{})
|
||||
pilot.SetDynamicConfiguration(dynamic.Configuration{})
|
||||
pilot.SetDynamicConfiguration(dynamic.Configuration{})
|
||||
|
||||
select {
|
||||
case <-time.Tick(10 * time.Second):
|
||||
|
@ -63,9 +67,12 @@ func TestTick(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestClient_SendConfiguration(t *testing.T) {
|
||||
func TestClient_SendInstanceInfo(t *testing.T) {
|
||||
myToken := "myToken"
|
||||
|
||||
myTokenHash, err := hashToken(myToken)
|
||||
require.NoError(t, err)
|
||||
|
||||
mux := http.NewServeMux()
|
||||
server := httptest.NewServer(mux)
|
||||
t.Cleanup(server.Close)
|
||||
|
@ -79,6 +86,7 @@ func TestClient_SendConfiguration(t *testing.T) {
|
|||
tk := req.Header.Get(tokenHeader)
|
||||
if tk != myToken {
|
||||
http.Error(rw, fmt.Sprintf("invalid token: %s", tk), http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
err := json.NewEncoder(rw).Encode(instanceInfo{ID: "123"})
|
||||
|
@ -97,9 +105,16 @@ func TestClient_SendConfiguration(t *testing.T) {
|
|||
tk := req.Header.Get(tokenHeader)
|
||||
if tk != myToken {
|
||||
http.Error(rw, fmt.Sprintf("invalid token: %s", tk), http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
defer req.Body.Close()
|
||||
tkh := req.Header.Get(tokenHashHeader)
|
||||
if tkh != myTokenHash {
|
||||
http.Error(rw, fmt.Sprintf("invalid token hash: %s", tkh), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
defer func() { _ = req.Body.Close() }()
|
||||
|
||||
info := &instanceInfo{}
|
||||
err := json.NewDecoder(req.Body).Decode(info)
|
||||
|
@ -114,11 +129,97 @@ func TestClient_SendConfiguration(t *testing.T) {
|
|||
})
|
||||
|
||||
client := client{
|
||||
baseURL: server.URL,
|
||||
httpClient: http.DefaultClient,
|
||||
token: myToken,
|
||||
baseInstanceInfoURL: server.URL,
|
||||
httpClient: http.DefaultClient,
|
||||
token: myToken,
|
||||
tokenHash: myTokenHash,
|
||||
}
|
||||
|
||||
err := client.SendData(context.Background(), RunTimeRepresentation{}, []metrics.PilotMetric{})
|
||||
err = client.SendInstanceInfo(context.Background(), []metrics.PilotMetric{})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestClient_SendAnonDynConf(t *testing.T) {
|
||||
myToken := "myToken"
|
||||
|
||||
myTokenHash, err := hashToken(myToken)
|
||||
require.NoError(t, err)
|
||||
|
||||
var count int
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/collect", func(rw http.ResponseWriter, req *http.Request) {
|
||||
count++
|
||||
if count == 1 {
|
||||
http.Error(rw, "OOPS", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Method != http.MethodPost {
|
||||
http.Error(rw, "invalid method", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
tkh := req.Header.Get(tokenHashHeader)
|
||||
if tkh != myTokenHash {
|
||||
http.Error(rw, fmt.Sprintf("invalid token hash: %s", tkh), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
defer func() { _ = req.Body.Close() }()
|
||||
|
||||
config := &dynamic.Configuration{}
|
||||
err := json.NewDecoder(req.Body).Decode(config)
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
router, exists := config.HTTP.Routers["foo"]
|
||||
if !exists {
|
||||
http.Error(rw, "router configuration is missing", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(router, &dynamic.Router{Service: "foo", Rule: "xxxx"}) {
|
||||
http.Error(rw, fmt.Sprintf("configuration is not anonymized: %+v", router), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
server := httptest.NewServer(mux)
|
||||
t.Cleanup(server.Close)
|
||||
|
||||
client := client{
|
||||
baseGatewayURL: server.URL,
|
||||
httpClient: http.DefaultClient,
|
||||
token: myToken,
|
||||
tokenHash: myTokenHash,
|
||||
}
|
||||
|
||||
config := dynamic.Configuration{
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"foo": {
|
||||
Service: "foo",
|
||||
Rule: "foo.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err = client.SendAnonDynConf(context.Background(), config)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 2, count)
|
||||
}
|
||||
|
||||
func hashToken(token string) (string, error) {
|
||||
tokenHash := fnv.New64a()
|
||||
|
||||
_, err := tokenHash.Write([]byte(token))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%x", tokenHash.Sum64()), nil
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ type ClientAuth struct {
|
|||
CAFiles []FileOrContent `json:"caFiles,omitempty" toml:"caFiles,omitempty" yaml:"caFiles,omitempty"`
|
||||
// ClientAuthType defines the client authentication type to apply.
|
||||
// The available values are: "NoClientCert", "RequestClientCert", "VerifyClientCertIfGiven" and "RequireAndVerifyClientCert".
|
||||
ClientAuthType string `json:"clientAuthType,omitempty" toml:"clientAuthType,omitempty" yaml:"clientAuthType,omitempty"`
|
||||
ClientAuthType string `json:"clientAuthType,omitempty" toml:"clientAuthType,omitempty" yaml:"clientAuthType,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
@ -18,8 +18,8 @@ type ClientAuth struct {
|
|||
type Options struct {
|
||||
MinVersion string `json:"minVersion,omitempty" toml:"minVersion,omitempty" yaml:"minVersion,omitempty" export:"true"`
|
||||
MaxVersion string `json:"maxVersion,omitempty" toml:"maxVersion,omitempty" yaml:"maxVersion,omitempty" export:"true"`
|
||||
CipherSuites []string `json:"cipherSuites,omitempty" toml:"cipherSuites,omitempty" yaml:"cipherSuites,omitempty"`
|
||||
CurvePreferences []string `json:"curvePreferences,omitempty" toml:"curvePreferences,omitempty" yaml:"curvePreferences,omitempty"`
|
||||
CipherSuites []string `json:"cipherSuites,omitempty" toml:"cipherSuites,omitempty" yaml:"cipherSuites,omitempty" export:"true"`
|
||||
CurvePreferences []string `json:"curvePreferences,omitempty" toml:"curvePreferences,omitempty" yaml:"curvePreferences,omitempty" export:"true"`
|
||||
ClientAuth ClientAuth `json:"clientAuth,omitempty" toml:"clientAuth,omitempty" yaml:"clientAuth,omitempty"`
|
||||
SniStrict bool `json:"sniStrict,omitempty" toml:"sniStrict,omitempty" yaml:"sniStrict,omitempty" export:"true"`
|
||||
PreferServerCipherSuites bool `json:"preferServerCipherSuites,omitempty" toml:"preferServerCipherSuites,omitempty" yaml:"preferServerCipherSuites,omitempty" export:"true"`
|
||||
|
@ -29,13 +29,13 @@ type Options struct {
|
|||
|
||||
// Store holds the options for a given Store.
|
||||
type Store struct {
|
||||
DefaultCertificate *Certificate `json:"defaultCertificate,omitempty" toml:"defaultCertificate,omitempty" yaml:"defaultCertificate,omitempty"`
|
||||
DefaultCertificate *Certificate `json:"defaultCertificate,omitempty" toml:"defaultCertificate,omitempty" yaml:"defaultCertificate,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// CertAndStores allows mapping a TLS certificate to a list of entry points.
|
||||
type CertAndStores struct {
|
||||
Certificate `yaml:",inline"`
|
||||
Stores []string `json:"stores,omitempty" toml:"stores,omitempty" yaml:"stores,omitempty"`
|
||||
Certificate `yaml:",inline" export:"true"`
|
||||
Stores []string `json:"stores,omitempty" toml:"stores,omitempty" yaml:"stores,omitempty" export:"true"`
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue