1
0
Fork 0

Merge remote-tracking branch 'upstream/v2.2' into mrg-current-v2.2

This commit is contained in:
jb doumenjou 2020-07-10 10:46:11 +02:00
commit 73ca7ad0c1
156 changed files with 1768 additions and 892 deletions

View file

@ -11,6 +11,7 @@ type Courgette struct {
Ji string
Ho string
}
type Tomate struct {
Ji string
Ho string

View file

@ -226,7 +226,7 @@ func TestHandler_EntryPoints(t *testing.T) {
newJSON, err := json.MarshalIndent(results, "", "\t")
require.NoError(t, err)
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0644)
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0o644)
require.NoError(t, err)
}

View file

@ -840,7 +840,7 @@ func TestHandler_HTTP(t *testing.T) {
newJSON, err := json.MarshalIndent(results, "", "\t")
require.NoError(t, err)
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0644)
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0o644)
require.NoError(t, err)
}

View file

@ -277,7 +277,7 @@ func TestHandler_Overview(t *testing.T) {
newJSON, err := json.MarshalIndent(results, "", "\t")
require.NoError(t, err)
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0644)
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0o644)
require.NoError(t, err)
}

View file

@ -548,7 +548,7 @@ func TestHandler_TCP(t *testing.T) {
newJSON, err := json.MarshalIndent(results, "", "\t")
require.NoError(t, err)
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0644)
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0o644)
require.NoError(t, err)
}

View file

@ -161,7 +161,7 @@ func TestHandler_RawData(t *testing.T) {
newJSON, err := json.MarshalIndent(rtRepr, "", "\t")
require.NoError(t, err)
err = ioutil.WriteFile(test.expected.json, newJSON, 0644)
err = ioutil.WriteFile(test.expected.json, newJSON, 0o644)
require.NoError(t, err)
}

View file

@ -525,7 +525,7 @@ func TestHandler_UDP(t *testing.T) {
newJSON, err := json.MarshalIndent(results, "", "\t")
require.NoError(t, err)
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0644)
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0o644)
require.NoError(t, err)
}

View file

@ -40,7 +40,7 @@ func Decode(filePath string, element interface{}) error {
// file contents -> tree of untyped nodes
// untyped nodes -> nodes augmented with metadata such as kind (inferred from element)
// "typed" nodes -> typed element.
func DecodeContent(content string, extension string, element interface{}) error {
func DecodeContent(content, extension string, element interface{}) error {
data := make(map[string]interface{})
switch extension {

View file

@ -100,25 +100,34 @@ func Test_decodeFileToNode_Toml(t *testing.T) {
{Name: "defaultMode", Value: "foobar"},
{Name: "names", Children: []*parser.Node{
{Name: "name0", Value: "foobar"},
{Name: "name1", Value: "foobar"}}}}},
{Name: "name1", Value: "foobar"},
}},
}},
{Name: "names", Children: []*parser.Node{
{Name: "name0", Value: "foobar"},
{Name: "name1", Value: "foobar"}}}}},
{Name: "name1", Value: "foobar"},
}},
}},
{Name: "filePath", Value: "foobar"},
{Name: "filters", Children: []*parser.Node{
{Name: "minDuration", Value: "42"},
{Name: "retryAttempts", Value: "true"},
{Name: "statusCodes", Value: "foobar,foobar"}}},
{Name: "format", Value: "foobar"}}},
{Name: "statusCodes", Value: "foobar,foobar"},
}},
{Name: "format", Value: "foobar"},
}},
{Name: "api", Children: []*parser.Node{
{Name: "dashboard", Value: "true"},
{Name: "entryPoint", Value: "foobar"},
{Name: "middlewares", Value: "foobar,foobar"},
{Name: "statistics", Children: []*parser.Node{
{Name: "recentErrors", Value: "42"}}}}},
{Name: "recentErrors", Value: "42"},
}},
}},
{Name: "certificatesResolvers", Children: []*parser.Node{
{Name: "default", Children: []*parser.Node{
{Name: "acme",
{
Name: "acme",
Children: []*parser.Node{
{Name: "acmeLogging", Value: "true"},
{Name: "caServer", Value: "foobar"},
@ -131,7 +140,8 @@ func Test_decodeFileToNode_Toml(t *testing.T) {
{Name: "email", Value: "foobar"},
{Name: "entryPoint", Value: "foobar"},
{Name: "httpChallenge", Children: []*parser.Node{
{Name: "entryPoint", Value: "foobar"}}},
{Name: "entryPoint", Value: "foobar"},
}},
{Name: "keyType", Value: "foobar"},
{Name: "storage", Value: "foobar"},
{Name: "tlsChallenge"},
@ -144,33 +154,44 @@ func Test_decodeFileToNode_Toml(t *testing.T) {
{Name: "address", Value: "foobar"},
{Name: "forwardedHeaders", Children: []*parser.Node{
{Name: "insecure", Value: "true"},
{Name: "trustedIPs", Value: "foobar,foobar"}}},
{Name: "trustedIPs", Value: "foobar,foobar"},
}},
{Name: "proxyProtocol", Children: []*parser.Node{
{Name: "insecure", Value: "true"},
{Name: "trustedIPs", Value: "foobar,foobar"}}},
{Name: "trustedIPs", Value: "foobar,foobar"},
}},
{Name: "transport", Children: []*parser.Node{
{Name: "lifeCycle", Children: []*parser.Node{
{Name: "graceTimeOut", Value: "42"},
{Name: "requestAcceptGraceTimeout", Value: "42"}}},
{Name: "requestAcceptGraceTimeout", Value: "42"},
}},
{Name: "respondingTimeouts", Children: []*parser.Node{
{Name: "idleTimeout", Value: "42"},
{Name: "readTimeout", Value: "42"},
{Name: "writeTimeout", Value: "42"}}}}}}}}},
{Name: "writeTimeout", Value: "42"},
}},
}},
}},
}},
{Name: "global", Children: []*parser.Node{
{Name: "checkNewVersion", Value: "true"},
{Name: "sendAnonymousUsage", Value: "true"}}},
{Name: "sendAnonymousUsage", Value: "true"},
}},
{Name: "hostResolver", Children: []*parser.Node{
{Name: "cnameFlattening", Value: "true"},
{Name: "resolvConfig", Value: "foobar"},
{Name: "resolvDepth", Value: "42"}}},
{Name: "resolvDepth", Value: "42"},
}},
{Name: "log", Children: []*parser.Node{
{Name: "filePath", Value: "foobar"},
{Name: "format", Value: "foobar"},
{Name: "level", Value: "foobar"}}},
{Name: "level", Value: "foobar"},
}},
{Name: "metrics", Children: []*parser.Node{
{Name: "datadog", Children: []*parser.Node{
{Name: "address", Value: "foobar"},
{Name: "pushInterval", Value: "10s"}}},
{Name: "pushInterval", Value: "10s"},
}},
{Name: "influxDB", Children: []*parser.Node{
{Name: "address", Value: "foobar"},
{Name: "database", Value: "foobar"},
@ -178,17 +199,22 @@ func Test_decodeFileToNode_Toml(t *testing.T) {
{Name: "protocol", Value: "foobar"},
{Name: "pushInterval", Value: "10s"},
{Name: "retentionPolicy", Value: "foobar"},
{Name: "username", Value: "foobar"}}},
{Name: "username", Value: "foobar"},
}},
{Name: "prometheus", Children: []*parser.Node{
{Name: "buckets", Value: "42,42"},
{Name: "entryPoint", Value: "foobar"},
{Name: "middlewares", Value: "foobar,foobar"}}},
{Name: "middlewares", Value: "foobar,foobar"},
}},
{Name: "statsD", Children: []*parser.Node{
{Name: "address", Value: "foobar"},
{Name: "pushInterval", Value: "10s"}}}}},
{Name: "pushInterval", Value: "10s"},
}},
}},
{Name: "ping", Children: []*parser.Node{
{Name: "entryPoint", Value: "foobar"},
{Name: "middlewares", Value: "foobar,foobar"}}},
{Name: "middlewares", Value: "foobar,foobar"},
}},
{Name: "providers", Children: []*parser.Node{
{Name: "docker", Children: []*parser.Node{
{Name: "constraints", Value: "foobar"},
@ -203,15 +229,19 @@ func Test_decodeFileToNode_Toml(t *testing.T) {
{Name: "caOptional", Value: "true"},
{Name: "cert", Value: "foobar"},
{Name: "insecureSkipVerify", Value: "true"},
{Name: "key", Value: "foobar"}}},
{Name: "key", Value: "foobar"},
}},
{Name: "useBindPortIP", Value: "true"},
{Name: "watch", Value: "true"}}},
{Name: "watch", Value: "true"},
}},
{Name: "file", Children: []*parser.Node{
{Name: "debugLogGeneratedTemplate", Value: "true"},
{Name: "directory", Value: "foobar"},
{Name: "filename", Value: "foobar"},
{Name: "watch", Value: "true"}}},
{Name: "kubernetesCRD",
{Name: "watch", Value: "true"},
}},
{
Name: "kubernetesCRD",
Children: []*parser.Node{
{Name: "certAuthFilePath", Value: "foobar"},
{Name: "disablePassHostHeaders", Value: "true"},
@ -219,7 +249,9 @@ func Test_decodeFileToNode_Toml(t *testing.T) {
{Name: "ingressClass", Value: "foobar"},
{Name: "labelSelector", Value: "foobar"},
{Name: "namespaces", Value: "foobar,foobar"},
{Name: "token", Value: "foobar"}}},
{Name: "token", Value: "foobar"},
},
},
{Name: "kubernetesIngress", Children: []*parser.Node{
{Name: "certAuthFilePath", Value: "foobar"},
{Name: "disablePassHostHeaders", Value: "true"},
@ -228,14 +260,17 @@ func Test_decodeFileToNode_Toml(t *testing.T) {
{Name: "ingressEndpoint", Children: []*parser.Node{
{Name: "hostname", Value: "foobar"},
{Name: "ip", Value: "foobar"},
{Name: "publishedService", Value: "foobar"}}},
{Name: "publishedService", Value: "foobar"},
}},
{Name: "labelSelector", Value: "foobar"},
{Name: "namespaces", Value: "foobar,foobar"},
{Name: "token", Value: "foobar"}}},
{Name: "token", Value: "foobar"},
}},
{Name: "marathon", Children: []*parser.Node{
{Name: "basic", Children: []*parser.Node{
{Name: "httpBasicAuthUser", Value: "foobar"},
{Name: "httpBasicPassword", Value: "foobar"}}},
{Name: "httpBasicPassword", Value: "foobar"},
}},
{Name: "constraints", Value: "foobar"},
{Name: "dcosToken", Value: "foobar"},
{Name: "defaultRule", Value: "foobar"},
@ -251,10 +286,12 @@ func Test_decodeFileToNode_Toml(t *testing.T) {
{Name: "caOptional", Value: "true"},
{Name: "cert", Value: "foobar"},
{Name: "insecureSkipVerify", Value: "true"},
{Name: "key", Value: "foobar"}}},
{Name: "key", Value: "foobar"},
}},
{Name: "tlsHandshakeTimeout", Value: "42"},
{Name: "trace", Value: "true"},
{Name: "watch", Value: "true"}}},
{Name: "watch", Value: "true"},
}},
{Name: "providersThrottleDuration", Value: "42"},
{Name: "rancher", Children: []*parser.Node{
{Name: "constraints", Value: "foobar"},
@ -264,17 +301,22 @@ func Test_decodeFileToNode_Toml(t *testing.T) {
{Name: "intervalPoll", Value: "true"},
{Name: "prefix", Value: "foobar"},
{Name: "refreshSeconds", Value: "42"},
{Name: "watch", Value: "true"}}},
{Name: "watch", Value: "true"},
}},
{Name: "rest", Children: []*parser.Node{
{Name: "entryPoint", Value: "foobar"}}}}},
{Name: "entryPoint", Value: "foobar"},
}},
}},
{Name: "serversTransport", Children: []*parser.Node{
{Name: "forwardingTimeouts", Children: []*parser.Node{
{Name: "dialTimeout", Value: "42"},
{Name: "idleConnTimeout", Value: "42"},
{Name: "responseHeaderTimeout", Value: "42"}}},
{Name: "responseHeaderTimeout", Value: "42"},
}},
{Name: "insecureSkipVerify", Value: "true"},
{Name: "maxIdleConnsPerHost", Value: "42"},
{Name: "rootCAs", Value: "foobar,foobar"}}},
{Name: "rootCAs", Value: "foobar,foobar"},
}},
{Name: "tracing", Children: []*parser.Node{
{Name: "datadog", Children: []*parser.Node{
{Name: "bagagePrefixHeaderName", Value: "foobar"},
@ -284,18 +326,21 @@ func Test_decodeFileToNode_Toml(t *testing.T) {
{Name: "parentIDHeaderName", Value: "foobar"},
{Name: "prioritySampling", Value: "true"},
{Name: "samplingPriorityHeaderName", Value: "foobar"},
{Name: "traceIDHeaderName", Value: "foobar"}}},
{Name: "traceIDHeaderName", Value: "foobar"},
}},
{Name: "haystack", Children: []*parser.Node{
{Name: "globalTag", Value: "foobar"},
{Name: "localAgentHost", Value: "foobar"},
{Name: "localAgentPort", Value: "42"},
{Name: "parentIDHeaderName", Value: "foobar"},
{Name: "spanIDHeaderName", Value: "foobar"},
{Name: "traceIDHeaderName", Value: "foobar"}}},
{Name: "traceIDHeaderName", Value: "foobar"},
}},
{Name: "instana", Children: []*parser.Node{
{Name: "localAgentHost", Value: "foobar"},
{Name: "localAgentPort", Value: "42"},
{Name: "logLevel", Value: "foobar"}}},
{Name: "logLevel", Value: "foobar"},
}},
{Name: "jaeger", Children: []*parser.Node{
{Name: "gen128Bit", Value: "true"},
{Name: "localAgentHostPort", Value: "foobar"},
@ -303,14 +348,17 @@ func Test_decodeFileToNode_Toml(t *testing.T) {
{Name: "samplingParam", Value: "42"},
{Name: "samplingServerURL", Value: "foobar"},
{Name: "samplingType", Value: "foobar"},
{Name: "traceContextHeaderName", Value: "foobar"}}},
{Name: "traceContextHeaderName", Value: "foobar"},
}},
{Name: "serviceName", Value: "foobar"},
{Name: "spanNameLimit", Value: "42"},
{Name: "zipkin", Children: []*parser.Node{
{Name: "httpEndpoint", Value: "foobar"},
{Name: "id128Bit", Value: "true"},
{Name: "sameSpan", Value: "true"},
{Name: "sampleRate", Value: "42"}}}}},
{Name: "sampleRate", Value: "42"},
}},
}},
},
}
@ -332,25 +380,34 @@ func Test_decodeFileToNode_Yaml(t *testing.T) {
{Name: "defaultMode", Value: "foobar"},
{Name: "names", Children: []*parser.Node{
{Name: "name0", Value: "foobar"},
{Name: "name1", Value: "foobar"}}}}},
{Name: "name1", Value: "foobar"},
}},
}},
{Name: "names", Children: []*parser.Node{
{Name: "name0", Value: "foobar"},
{Name: "name1", Value: "foobar"}}}}},
{Name: "name1", Value: "foobar"},
}},
}},
{Name: "filePath", Value: "foobar"},
{Name: "filters", Children: []*parser.Node{
{Name: "minDuration", Value: "42"},
{Name: "retryAttempts", Value: "true"},
{Name: "statusCodes", Value: "foobar,foobar"}}},
{Name: "format", Value: "foobar"}}},
{Name: "statusCodes", Value: "foobar,foobar"},
}},
{Name: "format", Value: "foobar"},
}},
{Name: "api", Children: []*parser.Node{
{Name: "dashboard", Value: "true"},
{Name: "entryPoint", Value: "foobar"},
{Name: "middlewares", Value: "foobar,foobar"},
{Name: "statistics", Children: []*parser.Node{
{Name: "recentErrors", Value: "42"}}}}},
{Name: "recentErrors", Value: "42"},
}},
}},
{Name: "certificatesResolvers", Children: []*parser.Node{
{Name: "default", Children: []*parser.Node{
{Name: "acme",
{
Name: "acme",
Children: []*parser.Node{
{Name: "acmeLogging", Value: "true"},
{Name: "caServer", Value: "foobar"},
@ -363,7 +420,8 @@ func Test_decodeFileToNode_Yaml(t *testing.T) {
{Name: "email", Value: "foobar"},
{Name: "entryPoint", Value: "foobar"},
{Name: "httpChallenge", Children: []*parser.Node{
{Name: "entryPoint", Value: "foobar"}}},
{Name: "entryPoint", Value: "foobar"},
}},
{Name: "keyType", Value: "foobar"},
{Name: "storage", Value: "foobar"},
{Name: "tlsChallenge"},
@ -376,33 +434,44 @@ func Test_decodeFileToNode_Yaml(t *testing.T) {
{Name: "address", Value: "foobar"},
{Name: "forwardedHeaders", Children: []*parser.Node{
{Name: "insecure", Value: "true"},
{Name: "trustedIPs", Value: "foobar,foobar"}}},
{Name: "trustedIPs", Value: "foobar,foobar"},
}},
{Name: "proxyProtocol", Children: []*parser.Node{
{Name: "insecure", Value: "true"},
{Name: "trustedIPs", Value: "foobar,foobar"}}},
{Name: "trustedIPs", Value: "foobar,foobar"},
}},
{Name: "transport", Children: []*parser.Node{
{Name: "lifeCycle", Children: []*parser.Node{
{Name: "graceTimeOut", Value: "42"},
{Name: "requestAcceptGraceTimeout", Value: "42"}}},
{Name: "requestAcceptGraceTimeout", Value: "42"},
}},
{Name: "respondingTimeouts", Children: []*parser.Node{
{Name: "idleTimeout", Value: "42"},
{Name: "readTimeout", Value: "42"},
{Name: "writeTimeout", Value: "42"}}}}}}}}},
{Name: "writeTimeout", Value: "42"},
}},
}},
}},
}},
{Name: "global", Children: []*parser.Node{
{Name: "checkNewVersion", Value: "true"},
{Name: "sendAnonymousUsage", Value: "true"}}},
{Name: "sendAnonymousUsage", Value: "true"},
}},
{Name: "hostResolver", Children: []*parser.Node{
{Name: "cnameFlattening", Value: "true"},
{Name: "resolvConfig", Value: "foobar"},
{Name: "resolvDepth", Value: "42"}}},
{Name: "resolvDepth", Value: "42"},
}},
{Name: "log", Children: []*parser.Node{
{Name: "filePath", Value: "foobar"},
{Name: "format", Value: "foobar"},
{Name: "level", Value: "foobar"}}},
{Name: "level", Value: "foobar"},
}},
{Name: "metrics", Children: []*parser.Node{
{Name: "datadog", Children: []*parser.Node{
{Name: "address", Value: "foobar"},
{Name: "pushInterval", Value: "10s"}}},
{Name: "pushInterval", Value: "10s"},
}},
{Name: "influxDB", Children: []*parser.Node{
{Name: "address", Value: "foobar"},
{Name: "database", Value: "foobar"},
@ -410,17 +479,22 @@ func Test_decodeFileToNode_Yaml(t *testing.T) {
{Name: "protocol", Value: "foobar"},
{Name: "pushInterval", Value: "10s"},
{Name: "retentionPolicy", Value: "foobar"},
{Name: "username", Value: "foobar"}}},
{Name: "username", Value: "foobar"},
}},
{Name: "prometheus", Children: []*parser.Node{
{Name: "buckets", Value: "42,42"},
{Name: "entryPoint", Value: "foobar"},
{Name: "middlewares", Value: "foobar,foobar"}}},
{Name: "middlewares", Value: "foobar,foobar"},
}},
{Name: "statsD", Children: []*parser.Node{
{Name: "address", Value: "foobar"},
{Name: "pushInterval", Value: "10s"}}}}},
{Name: "pushInterval", Value: "10s"},
}},
}},
{Name: "ping", Children: []*parser.Node{
{Name: "entryPoint", Value: "foobar"},
{Name: "middlewares", Value: "foobar,foobar"}}},
{Name: "middlewares", Value: "foobar,foobar"},
}},
{Name: "providers", Children: []*parser.Node{
{Name: "docker", Children: []*parser.Node{
{Name: "constraints", Value: "foobar"},
@ -435,15 +509,19 @@ func Test_decodeFileToNode_Yaml(t *testing.T) {
{Name: "caOptional", Value: "true"},
{Name: "cert", Value: "foobar"},
{Name: "insecureSkipVerify", Value: "true"},
{Name: "key", Value: "foobar"}}},
{Name: "key", Value: "foobar"},
}},
{Name: "useBindPortIP", Value: "true"},
{Name: "watch", Value: "true"}}},
{Name: "watch", Value: "true"},
}},
{Name: "file", Children: []*parser.Node{
{Name: "debugLogGeneratedTemplate", Value: "true"},
{Name: "directory", Value: "foobar"},
{Name: "filename", Value: "foobar"},
{Name: "watch", Value: "true"}}},
{Name: "kubernetesCRD",
{Name: "watch", Value: "true"},
}},
{
Name: "kubernetesCRD",
Children: []*parser.Node{
{Name: "certAuthFilePath", Value: "foobar"},
{Name: "disablePassHostHeaders", Value: "true"},
@ -451,7 +529,9 @@ func Test_decodeFileToNode_Yaml(t *testing.T) {
{Name: "ingressClass", Value: "foobar"},
{Name: "labelSelector", Value: "foobar"},
{Name: "namespaces", Value: "foobar,foobar"},
{Name: "token", Value: "foobar"}}},
{Name: "token", Value: "foobar"},
},
},
{Name: "kubernetesIngress", Children: []*parser.Node{
{Name: "certAuthFilePath", Value: "foobar"},
{Name: "disablePassHostHeaders", Value: "true"},
@ -460,14 +540,17 @@ func Test_decodeFileToNode_Yaml(t *testing.T) {
{Name: "ingressEndpoint", Children: []*parser.Node{
{Name: "hostname", Value: "foobar"},
{Name: "ip", Value: "foobar"},
{Name: "publishedService", Value: "foobar"}}},
{Name: "publishedService", Value: "foobar"},
}},
{Name: "labelSelector", Value: "foobar"},
{Name: "namespaces", Value: "foobar,foobar"},
{Name: "token", Value: "foobar"}}},
{Name: "token", Value: "foobar"},
}},
{Name: "marathon", Children: []*parser.Node{
{Name: "basic", Children: []*parser.Node{
{Name: "httpBasicAuthUser", Value: "foobar"},
{Name: "httpBasicPassword", Value: "foobar"}}},
{Name: "httpBasicPassword", Value: "foobar"},
}},
{Name: "constraints", Value: "foobar"},
{Name: "dcosToken", Value: "foobar"},
{Name: "defaultRule", Value: "foobar"},
@ -483,10 +566,12 @@ func Test_decodeFileToNode_Yaml(t *testing.T) {
{Name: "caOptional", Value: "true"},
{Name: "cert", Value: "foobar"},
{Name: "insecureSkipVerify", Value: "true"},
{Name: "key", Value: "foobar"}}},
{Name: "key", Value: "foobar"},
}},
{Name: "tlsHandshakeTimeout", Value: "42"},
{Name: "trace", Value: "true"},
{Name: "watch", Value: "true"}}},
{Name: "watch", Value: "true"},
}},
{Name: "providersThrottleDuration", Value: "42"},
{Name: "rancher", Children: []*parser.Node{
{Name: "constraints", Value: "foobar"},
@ -496,17 +581,22 @@ func Test_decodeFileToNode_Yaml(t *testing.T) {
{Name: "intervalPoll", Value: "true"},
{Name: "prefix", Value: "foobar"},
{Name: "refreshSeconds", Value: "42"},
{Name: "watch", Value: "true"}}},
{Name: "watch", Value: "true"},
}},
{Name: "rest", Children: []*parser.Node{
{Name: "entryPoint", Value: "foobar"}}}}},
{Name: "entryPoint", Value: "foobar"},
}},
}},
{Name: "serversTransport", Children: []*parser.Node{
{Name: "forwardingTimeouts", Children: []*parser.Node{
{Name: "dialTimeout", Value: "42"},
{Name: "idleConnTimeout", Value: "42"},
{Name: "responseHeaderTimeout", Value: "42"}}},
{Name: "responseHeaderTimeout", Value: "42"},
}},
{Name: "insecureSkipVerify", Value: "true"},
{Name: "maxIdleConnsPerHost", Value: "42"},
{Name: "rootCAs", Value: "foobar,foobar"}}},
{Name: "rootCAs", Value: "foobar,foobar"},
}},
{Name: "tracing", Children: []*parser.Node{
{Name: "datadog", Children: []*parser.Node{
{Name: "bagagePrefixHeaderName", Value: "foobar"},
@ -516,18 +606,21 @@ func Test_decodeFileToNode_Yaml(t *testing.T) {
{Name: "parentIDHeaderName", Value: "foobar"},
{Name: "prioritySampling", Value: "true"},
{Name: "samplingPriorityHeaderName", Value: "foobar"},
{Name: "traceIDHeaderName", Value: "foobar"}}},
{Name: "traceIDHeaderName", Value: "foobar"},
}},
{Name: "haystack", Children: []*parser.Node{
{Name: "globalTag", Value: "foobar"},
{Name: "localAgentHost", Value: "foobar"},
{Name: "localAgentPort", Value: "42"},
{Name: "parentIDHeaderName", Value: "foobar"},
{Name: "spanIDHeaderName", Value: "foobar"},
{Name: "traceIDHeaderName", Value: "foobar"}}},
{Name: "traceIDHeaderName", Value: "foobar"},
}},
{Name: "instana", Children: []*parser.Node{
{Name: "localAgentHost", Value: "foobar"},
{Name: "localAgentPort", Value: "42"},
{Name: "logLevel", Value: "foobar"}}},
{Name: "logLevel", Value: "foobar"},
}},
{Name: "jaeger", Children: []*parser.Node{
{Name: "gen128Bit", Value: "true"},
{Name: "localAgentHostPort", Value: "foobar"},
@ -535,14 +628,17 @@ func Test_decodeFileToNode_Yaml(t *testing.T) {
{Name: "samplingParam", Value: "42"},
{Name: "samplingServerURL", Value: "foobar"},
{Name: "samplingType", Value: "foobar"},
{Name: "traceContextHeaderName", Value: "foobar"}}},
{Name: "traceContextHeaderName", Value: "foobar"},
}},
{Name: "serviceName", Value: "foobar"},
{Name: "spanNameLimit", Value: "42"},
{Name: "zipkin", Children: []*parser.Node{
{Name: "httpEndpoint", Value: "foobar"},
{Name: "id128Bit", Value: "true"},
{Name: "sameSpan", Value: "true"},
{Name: "sampleRate", Value: "42"}}}}},
{Name: "sampleRate", Value: "42"},
}},
}},
},
}

View file

@ -101,7 +101,7 @@ func (f *flagSet) parseOne() (bool, error) {
return true, nil
}
func (f *flagSet) setValue(name string, value string) {
func (f *flagSet) setValue(name, value string) {
srcKey := parser.DefaultRootName + "." + name
neutralKey := strings.ToLower(srcKey)

View file

@ -81,8 +81,8 @@ func filterPairs(pairs []*store.KVPair, filters []string) []*store.KVPair {
return pairs[i].Key < pairs[j].Key
})
var simplePairs = map[string]*store.KVPair{}
var slicePairs = map[string][]string{}
simplePairs := map[string]*store.KVPair{}
slicePairs := map[string][]string{}
for _, pair := range pairs {
if len(filters) == 0 {

View file

@ -498,27 +498,31 @@ func TestFill(t *testing.T) {
Children: []*Node{
{Name: "Fii", FieldName: "Fii", Value: "huu", Kind: reflect.String},
{Name: "Fuu", FieldName: "Fuu", Value: "6", Kind: reflect.Int},
}},
}},
},
},
},
},
element: &struct {
Foo struct {
Fii string
Fuu int
}
}{},
expected: expected{element: &struct {
Foo struct {
Fii string
Fuu int
}
}{
Foo: struct {
Fii string
Fuu int
expected: expected{
element: &struct {
Foo struct {
Fii string
Fuu int
}
}{
Fii: "huu",
Fuu: 6,
}},
Foo: struct {
Fii string
Fuu int
}{
Fii: "huu",
Fuu: 6,
},
},
},
},
{
@ -534,27 +538,31 @@ func TestFill(t *testing.T) {
Children: []*Node{
{Name: "Fii", FieldName: "Fii", Value: "huu", Kind: reflect.String},
{Name: "Fuu", FieldName: "Fuu", Value: "6", Kind: reflect.Int},
}},
}},
},
},
},
},
element: &struct {
Foo *struct {
Fii string
Fuu int
}
}{},
expected: expected{element: &struct {
Foo *struct {
Fii string
Fuu int
}
}{
Foo: &struct {
Fii string
Fuu int
expected: expected{
element: &struct {
Foo *struct {
Fii string
Fuu int
}
}{
Fii: "huu",
Fuu: 6,
}},
Foo: &struct {
Fii string
Fuu int
}{
Fii: "huu",
Fuu: 6,
},
},
},
},
{
@ -568,23 +576,26 @@ func TestFill(t *testing.T) {
FieldName: "Foo",
Kind: reflect.Ptr,
},
}},
},
},
element: &struct {
Foo *struct {
Fii string
Fuu int
} `label:"allowEmpty"`
}{},
expected: expected{element: &struct {
Foo *struct {
Fii string
Fuu int
} `label:"allowEmpty"`
}{
Foo: &struct {
Fii string
Fuu int
}{}},
expected: expected{
element: &struct {
Foo *struct {
Fii string
Fuu int
} `label:"allowEmpty"`
}{
Foo: &struct {
Fii string
Fuu int
}{},
},
},
},
{
@ -599,19 +610,21 @@ func TestFill(t *testing.T) {
Kind: reflect.Ptr,
Disabled: true,
},
}},
},
},
element: &struct {
Foo *struct {
Fii string
Fuu int
} `label:"allowEmpty"`
}{},
expected: expected{element: &struct {
Foo *struct {
Fii string
Fuu int
} `label:"allowEmpty"`
}{},
expected: expected{
element: &struct {
Foo *struct {
Fii string
Fuu int
} `label:"allowEmpty"`
}{},
},
},
{
@ -628,20 +641,23 @@ func TestFill(t *testing.T) {
Children: []*Node{
{Name: "Fii", FieldName: "Fii", Value: "huu", Kind: reflect.String},
{Name: "Fuu", FieldName: "Fuu", Value: "6", Kind: reflect.Int},
}},
}},
},
},
},
},
element: &struct {
Foo *struct {
Fii string
Fuu int
} `label:"allowEmpty"`
}{},
expected: expected{element: &struct {
Foo *struct {
Fii string
Fuu int
} `label:"allowEmpty"`
}{},
expected: expected{
element: &struct {
Foo *struct {
Fii string
Fuu int
} `label:"allowEmpty"`
}{},
},
},
{
@ -657,18 +673,22 @@ func TestFill(t *testing.T) {
Children: []*Node{
{Name: "name1", Value: "hii", Kind: reflect.String},
{Name: "name2", Value: "huu", Kind: reflect.String},
}},
}},
},
},
},
},
element: &struct {
Foo map[string]string
}{},
expected: expected{element: &struct {
Foo map[string]string
}{
Foo: map[string]string{
"name1": "hii",
"name2": "huu",
}},
expected: expected{
element: &struct {
Foo map[string]string
}{
Foo: map[string]string{
"name1": "hii",
"name2": "huu",
},
},
},
},
{
@ -696,18 +716,22 @@ func TestFill(t *testing.T) {
{Name: "Fii", FieldName: "Fii", Kind: reflect.String, Value: "huu"},
},
},
}},
}},
},
},
},
},
element: &struct {
Foo map[string]struct{ Fii string }
}{},
expected: expected{element: &struct {
Foo map[string]struct{ Fii string }
}{
Foo: map[string]struct{ Fii string }{
"name1": {Fii: "hii"},
"name2": {Fii: "huu"},
}},
expected: expected{
element: &struct {
Foo map[string]struct{ Fii string }
}{
Foo: map[string]struct{ Fii string }{
"name1": {Fii: "hii"},
"name2": {Fii: "huu"},
},
},
},
},
{
@ -1186,8 +1210,10 @@ func TestFill(t *testing.T) {
Kind: reflect.Struct,
Children: []*Node{
{Name: "Fuu", FieldName: "Fuu", Value: "huu", Kind: reflect.String},
}},
}},
},
},
},
},
element: &struct {
Foo *InitializedFoo
}{},
@ -1212,8 +1238,10 @@ func TestFill(t *testing.T) {
Kind: reflect.Struct,
Children: []*Node{
{Name: "Fuu", FieldName: "Fuu", Value: "huu", Kind: reflect.String},
}},
}},
},
},
},
},
element: &struct {
Foo *wrongInitialledFoo
}{},
@ -1273,8 +1301,10 @@ func TestFill(t *testing.T) {
Kind: reflect.Struct,
Children: []*Node{
{Name: "Fuu", FieldName: "Fuu", Value: "huu", Kind: reflect.String},
}},
}},
},
},
},
},
element: &struct {
Foo struct {
FiiFoo
@ -1401,8 +1431,10 @@ func TestFill(t *testing.T) {
}
}
type NamedType string
type NamedTypeInt int
type (
NamedType string
NamedTypeInt int
)
type InitializedFoo struct {
Fii string

View file

@ -23,9 +23,10 @@ func TestEncodeToNode(t *testing.T) {
element: struct {
Foo string `description:"text"`
}{Foo: "bar"},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "bar", Description: "text"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "bar", Description: "text"},
}},
},
},
{
@ -33,9 +34,10 @@ func TestEncodeToNode(t *testing.T) {
element: struct {
Foo string
}{Foo: "bar"},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "bar"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "bar"},
}},
},
},
{
@ -44,10 +46,11 @@ func TestEncodeToNode(t *testing.T) {
Foo string
Fii string
}{Foo: "bar", Fii: "hii"},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "bar"},
{Name: "Fii", FieldName: "Fii", Value: "hii"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "bar"},
{Name: "Fii", FieldName: "Fii", Value: "hii"},
}},
},
},
{
@ -55,9 +58,10 @@ func TestEncodeToNode(t *testing.T) {
element: struct {
Foo int
}{Foo: 1},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "1"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "1"},
}},
},
},
{
@ -65,9 +69,10 @@ func TestEncodeToNode(t *testing.T) {
element: struct {
Foo int8
}{Foo: 2},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "2"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "2"},
}},
},
},
{
@ -75,9 +80,10 @@ func TestEncodeToNode(t *testing.T) {
element: struct {
Foo int16
}{Foo: 2},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "2"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "2"},
}},
},
},
{
@ -85,9 +91,10 @@ func TestEncodeToNode(t *testing.T) {
element: struct {
Foo int32
}{Foo: 2},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "2"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "2"},
}},
},
},
{
@ -95,9 +102,10 @@ func TestEncodeToNode(t *testing.T) {
element: struct {
Foo int64
}{Foo: 2},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "2"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "2"},
}},
},
},
{
@ -105,9 +113,10 @@ func TestEncodeToNode(t *testing.T) {
element: struct {
Foo uint
}{Foo: 1},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "1"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "1"},
}},
},
},
{
@ -115,9 +124,10 @@ func TestEncodeToNode(t *testing.T) {
element: struct {
Foo uint8
}{Foo: 2},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "2"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "2"},
}},
},
},
{
@ -125,9 +135,10 @@ func TestEncodeToNode(t *testing.T) {
element: struct {
Foo uint16
}{Foo: 2},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "2"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "2"},
}},
},
},
{
@ -135,9 +146,10 @@ func TestEncodeToNode(t *testing.T) {
element: struct {
Foo uint32
}{Foo: 2},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "2"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "2"},
}},
},
},
{
@ -145,9 +157,10 @@ func TestEncodeToNode(t *testing.T) {
element: struct {
Foo uint64
}{Foo: 2},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "2"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "2"},
}},
},
},
{
@ -155,9 +168,10 @@ func TestEncodeToNode(t *testing.T) {
element: struct {
Foo float32
}{Foo: 1.12},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "1.120000"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "1.120000"},
}},
},
},
{
@ -165,9 +179,10 @@ func TestEncodeToNode(t *testing.T) {
element: struct {
Foo float64
}{Foo: 1.12},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "1.120000"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "1.120000"},
}},
},
},
{
@ -175,9 +190,10 @@ func TestEncodeToNode(t *testing.T) {
element: struct {
Foo bool
}{Foo: true},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "true"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "true"},
}},
},
},
{
@ -196,12 +212,13 @@ func TestEncodeToNode(t *testing.T) {
Fuu: "huu",
},
},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Children: []*Node{
{Name: "Fii", FieldName: "Fii", Value: "hii"},
{Name: "Fuu", FieldName: "Fuu", Value: "huu"},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Children: []*Node{
{Name: "Fii", FieldName: "Fii", Value: "hii"},
{Name: "Fuu", FieldName: "Fuu", Value: "huu"},
}},
}},
}},
},
},
{
@ -220,11 +237,12 @@ func TestEncodeToNode(t *testing.T) {
fuu: "huu",
},
},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Children: []*Node{
{Name: "Fii", FieldName: "Fii", Value: "hii"},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Children: []*Node{
{Name: "Fii", FieldName: "Fii", Value: "hii"},
}},
}},
}},
},
},
{
@ -243,12 +261,13 @@ func TestEncodeToNode(t *testing.T) {
Fuu: "huu",
},
},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Children: []*Node{
{Name: "Fii", FieldName: "Fii", Value: "hii"},
{Name: "Fuu", FieldName: "Fuu", Value: "huu"},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Children: []*Node{
{Name: "Fii", FieldName: "Fii", Value: "hii"},
{Name: "Fuu", FieldName: "Fuu", Value: "huu"},
}},
}},
}},
},
},
{
@ -267,12 +286,13 @@ func TestEncodeToNode(t *testing.T) {
Fuu: "huu",
},
},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Children: []*Node{
{Name: "Fii", FieldName: "Fii", Value: "hii"},
{Name: "Fuu", FieldName: "Fuu", Value: "huu"},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Children: []*Node{
{Name: "Fii", FieldName: "Fii", Value: "hii"},
{Name: "Fuu", FieldName: "Fuu", Value: "huu"},
}},
}},
}},
},
},
{
@ -291,11 +311,12 @@ func TestEncodeToNode(t *testing.T) {
Fuu: "huu",
},
},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Children: []*Node{
{Name: "Fuu", FieldName: "Fuu", Value: "huu"},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Children: []*Node{
{Name: "Fuu", FieldName: "Fuu", Value: "huu"},
}},
}},
}},
},
},
{
@ -314,12 +335,13 @@ func TestEncodeToNode(t *testing.T) {
Fuu: 4,
},
},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Children: []*Node{
{Name: "Fii", FieldName: "Fii", Value: "6"},
{Name: "Fuu", FieldName: "Fuu", Value: "4"},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Children: []*Node{
{Name: "Fii", FieldName: "Fii", Value: "6"},
{Name: "Fuu", FieldName: "Fuu", Value: "4"},
}},
}},
}},
},
},
{
@ -338,12 +360,13 @@ func TestEncodeToNode(t *testing.T) {
Fuu: true,
},
},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Children: []*Node{
{Name: "Fii", FieldName: "Fii", Value: "true"},
{Name: "Fuu", FieldName: "Fuu", Value: "true"},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Children: []*Node{
{Name: "Fii", FieldName: "Fii", Value: "true"},
{Name: "Fuu", FieldName: "Fuu", Value: "true"},
}},
}},
}},
},
},
{
@ -386,9 +409,10 @@ func TestEncodeToNode(t *testing.T) {
Fuu string
}{},
},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "true"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Value: "true"},
}},
},
},
{
@ -452,113 +476,127 @@ func TestEncodeToNode(t *testing.T) {
{
desc: "slice of string",
element: struct{ Bar []string }{Bar: []string{"huu", "hii"}},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "huu, hii"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "huu, hii"},
}},
},
},
{
desc: "slice of int",
element: struct{ Bar []int }{Bar: []int{4, 2, 3}},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
}},
},
},
{
desc: "slice of int8",
element: struct{ Bar []int8 }{Bar: []int8{4, 2, 3}},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
}},
},
},
{
desc: "slice of int16",
element: struct{ Bar []int16 }{Bar: []int16{4, 2, 3}},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
}},
},
},
{
desc: "slice of int32",
element: struct{ Bar []int32 }{Bar: []int32{4, 2, 3}},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
}},
},
},
{
desc: "slice of int64",
element: struct{ Bar []int64 }{Bar: []int64{4, 2, 3}},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
}},
},
},
{
desc: "slice of uint",
element: struct{ Bar []uint }{Bar: []uint{4, 2, 3}},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
}},
},
},
{
desc: "slice of uint8",
element: struct{ Bar []uint8 }{Bar: []uint8{4, 2, 3}},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
}},
},
},
{
desc: "slice of uint16",
element: struct{ Bar []uint16 }{Bar: []uint16{4, 2, 3}},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
}},
},
},
{
desc: "slice of uint32",
element: struct{ Bar []uint32 }{Bar: []uint32{4, 2, 3}},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
}},
},
},
{
desc: "slice of uint64",
element: struct{ Bar []uint64 }{Bar: []uint64{4, 2, 3}},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
}},
},
},
{
desc: "slice of float32",
element: struct{ Bar []float32 }{Bar: []float32{4.1, 2, 3.2}},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "4.100000, 2.000000, 3.200000"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "4.100000, 2.000000, 3.200000"},
}},
},
},
{
desc: "slice of float64",
element: struct{ Bar []float64 }{Bar: []float64{4.1, 2, 3.2}},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "4.100000, 2.000000, 3.200000"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "4.100000, 2.000000, 3.200000"},
}},
},
},
{
desc: "slice of bool",
element: struct{ Bar []bool }{Bar: []bool{true, false, true}},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "true, false, true"},
}},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "true, false, true"},
}},
},
},
{
@ -708,12 +746,13 @@ func TestEncodeToNode(t *testing.T) {
},
},
},
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Children: []*Node{
{Name: "Fii", FieldName: "Fii", Value: "hii"},
{Name: "Fuu", FieldName: "Fuu", Value: "huu"},
expected: expected{
node: &Node{Name: "traefik", Children: []*Node{
{Name: "Foo", FieldName: "Foo", Children: []*Node{
{Name: "Fii", FieldName: "Fii", Value: "hii"},
{Name: "Fuu", FieldName: "Fuu", Value: "huu"},
}},
}},
}},
},
},
}

View file

@ -682,7 +682,8 @@ func TestAddMetadata(t *testing.T) {
Children: []*Node{
{Name: "Bar", FieldName: "Bar", Value: "bir", Kind: reflect.String},
{Name: "Bur", FieldName: "Bur", Value: "fuu", Kind: reflect.String},
}},
},
},
},
},
},
@ -728,8 +729,10 @@ func TestAddMetadata(t *testing.T) {
Kind: reflect.Struct,
Children: []*Node{
{Name: "Bur", FieldName: "Bur", Value: "fuu", Kind: reflect.String},
}},
}},
},
},
},
},
},
},
},
@ -797,22 +800,26 @@ func TestAddMetadata(t *testing.T) {
Children: []*Node{
{Name: "Fii", FieldName: "Fii", Kind: reflect.String, Value: "fii"},
{Name: "Fee", FieldName: "Fee", Kind: reflect.Int, Value: "1"},
}},
},
},
{
Name: "Bur",
FieldName: "Bur",
Kind: reflect.Struct,
Children: []*Node{
{Name: "Faa", FieldName: "Faa", Kind: reflect.String, Value: "faa"},
}},
}},
},
},
},
},
{
Name: "Fii",
FieldName: "Fii",
Kind: reflect.Struct,
Children: []*Node{
{Name: "FiiBar", FieldName: "FiiBar", Kind: reflect.String, Value: "fiiBar"},
}},
},
},
},
},
},

View file

@ -168,7 +168,7 @@ func (s *ServiceInfo) AddError(err error, critical bool) {
// UpdateServerStatus sets the status of the server in the ServiceInfo.
// It is the responsibility of the caller to check that s is not nil.
func (s *ServiceInfo) UpdateServerStatus(server string, status string) {
func (s *ServiceInfo) UpdateServerStatus(server, status string) {
s.serverStatusMu.Lock()
defer s.serverStatusMu.Unlock()

View file

@ -79,6 +79,7 @@ type CertificateResolver struct {
type Global struct {
CheckNewVersion bool `description:"Periodically check if a new version has been released." json:"checkNewVersion,omitempty" toml:"checkNewVersion,omitempty" yaml:"checkNewVersion,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
SendAnonymousUsage bool `description:"Periodically send anonymous usage statistics. If the option is not specified, it will be enabled by default." json:"sendAnonymousUsage,omitempty" toml:"sendAnonymousUsage,omitempty" yaml:"sendAnonymousUsage,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
InsecureSNI bool `description:"Allow domain fronting. If the option is not specified, it will be disabled by default." json:"insecureSNI,omitempty" toml:"insecureSNI,omitempty" yaml:"insecureSNI,omitempty" label:"allowEmpty" export:"true"`
}
// ServersTransport options to configure communication between Traefik and the servers.

View file

@ -22,8 +22,10 @@ const (
serverDown = "DOWN"
)
var singleton *HealthCheck
var once sync.Once
var (
singleton *HealthCheck
once sync.Once
)
// Balancer is the set of operations required to manage the list of servers in a load-balancer.
type Balancer interface {

View file

@ -16,8 +16,10 @@ import (
"github.com/vulcand/oxy/roundrobin"
)
const healthCheckInterval = 200 * time.Millisecond
const healthCheckTimeout = 100 * time.Millisecond
const (
healthCheckInterval = 200 * time.Millisecond
healthCheckTimeout = 100 * time.Millisecond
)
type testHandler struct {
done func()
@ -148,7 +150,7 @@ func TestSetBackendsConfiguration(t *testing.T) {
assert.Equal(t, test.expectedNumRemovedServers, lb.numRemovedServers, "removed servers")
assert.Equal(t, test.expectedNumUpsertedServers, lb.numUpsertedServers, "upserted servers")
// FIXME re add metrics
//assert.Equal(t, test.expectedGaugeValue, collectingMetrics.Gauge.GaugeValue, "ServerUp Gauge")
// assert.Equal(t, test.expectedGaugeValue, collectingMetrics.Gauge.GaugeValue, "ServerUp Gauge")
})
}
}

View file

@ -6,9 +6,7 @@ import (
"github.com/cenkalti/backoff/v4"
)
var (
_ backoff.BackOff = (*BackOff)(nil)
)
var _ backoff.BackOff = (*BackOff)(nil)
const (
defaultMinJobInterval = 30 * time.Second

View file

@ -24,21 +24,21 @@ func TestJobBackOff(t *testing.T) {
exp.MinJobInterval = testMinJobInterval
exp.Reset()
var expectedResults = []time.Duration{500, 500, 500, 1000, 2000, 4000, 5000, 5000, 500, 1000, 2000, 4000, 5000, 5000}
expectedResults := []time.Duration{500, 500, 500, 1000, 2000, 4000, 5000, 5000, 500, 1000, 2000, 4000, 5000, 5000}
for i, d := range expectedResults {
expectedResults[i] = d * time.Millisecond
}
for i, expected := range expectedResults {
// Assert that the next backoff falls in the expected range.
var minInterval = expected - time.Duration(testRandomizationFactor*float64(expected))
var maxInterval = expected + time.Duration(testRandomizationFactor*float64(expected))
minInterval := expected - time.Duration(testRandomizationFactor*float64(expected))
maxInterval := expected + time.Duration(testRandomizationFactor*float64(expected))
if i < 3 || i == 8 {
time.Sleep(2 * time.Second)
}
var actualInterval = exp.NextBackOff()
actualInterval := exp.NextBackOff()
if !(minInterval <= actualInterval && actualInterval <= maxInterval) {
t.Error("error")
}

View file

@ -101,7 +101,7 @@ func OpenFile(path string) error {
logFilePath = path
var err error
logFile, err = os.OpenFile(logFilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
logFile, err = os.OpenFile(logFilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o666)
if err != nil {
return err
}

View file

@ -11,8 +11,10 @@ import (
"github.com/go-kit/kit/metrics/statsd"
)
var statsdClient *statsd.Statsd
var statsdTicker *time.Ticker
var (
statsdClient *statsd.Statsd
statsdTicker *time.Ticker
)
const (
statsdMetricsServiceReqsName = "service.request.total"

View file

@ -9,9 +9,7 @@ import (
"github.com/containous/traefik/v2/pkg/middlewares"
)
var (
_ middlewares.Stateful = &captureResponseWriterWithCloseNotify{}
)
var _ middlewares.Stateful = &captureResponseWriterWithCloseNotify{}
type capturer interface {
http.ResponseWriter

View file

@ -19,7 +19,7 @@ type FieldHandler struct {
}
// NewFieldHandler creates a Field handler.
func NewFieldHandler(next http.Handler, name string, value string, applyFn FieldApply) http.Handler {
func NewFieldHandler(next http.Handler, name, value string, applyFn FieldApply) http.Handler {
return &FieldHandler{next: next, name: name, value: value, applyFn: applyFn}
}

View file

@ -131,11 +131,11 @@ func NewHandler(config *types.AccessLog) (*Handler, error) {
func openAccessLogFile(filePath string) (*os.File, error) {
dir := filepath.Dir(filePath)
if err := os.MkdirAll(dir, 0755); err != nil {
if err := os.MkdirAll(dir, 0o755); err != nil {
return nil, fmt.Errorf("failed to create log path %s: %w", dir, err)
}
file, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0664)
file, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o664)
if err != nil {
return nil, fmt.Errorf("error opening file %s: %w", filePath, err)
}
@ -249,7 +249,7 @@ func (h *Handler) Rotate() error {
}
var err error
h.file, err = os.OpenFile(h.config.FilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0664)
h.file, err = os.OpenFile(h.config.FilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o664)
if err != nil {
return err
}
@ -259,7 +259,7 @@ func (h *Handler) Rotate() error {
return nil
}
func silentSplitHostPort(value string) (host string, port string) {
func silentSplitHostPort(value string) (host, port string) {
host, port, err := net.SplitHostPort(value)
if err != nil {
return value, "-"

View file

@ -21,7 +21,7 @@ type CommonLogFormatter struct{}
func (f *CommonLogFormatter) Format(entry *logrus.Entry) ([]byte, error) {
b := &bytes.Buffer{}
var timestamp = defaultValue
timestamp := defaultValue
if v, ok := entry.Data[StartUTC]; ok {
timestamp = v.(time.Time).Format(commonLogTimeFormat)
} else if v, ok := entry.Data[StartLocal]; ok {
@ -52,7 +52,7 @@ func (f *CommonLogFormatter) Format(entry *logrus.Entry) ([]byte, error) {
return b.Bytes(), err
}
func toLog(fields logrus.Fields, key string, defaultValue string, quoted bool) interface{} {
func toLog(fields logrus.Fields, key, defaultValue string, quoted bool) interface{} {
if v, ok := fields[key]; ok {
if v == nil {
return defaultValue
@ -73,7 +73,7 @@ func toLog(fields logrus.Fields, key string, defaultValue string, quoted bool) i
return defaultValue
}
func toLogEntry(s string, defaultValue string, quote bool) string {
func toLogEntry(s, defaultValue string, quote bool) string {
if len(s) == 0 {
return defaultValue
}

View file

@ -62,29 +62,39 @@ func (b *basicAuth) GetTracingInformation() (string, ext.SpanKindEnum) {
func (b *basicAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
logger := log.FromContext(middlewares.GetLoggerCtx(req.Context(), b.name, basicTypeName))
if username := b.auth.CheckAuth(req); username == "" {
user, password, ok := req.BasicAuth()
if ok {
secret := b.auth.Secrets(user, b.auth.Realm)
if secret == "" || !goauth.CheckSecret(password, secret) {
ok = false
}
}
logData := accesslog.GetLogData(req)
if logData != nil {
logData.Core[accesslog.ClientUsername] = user
}
if !ok {
logger.Debug("Authentication failed")
tracing.SetErrorWithEvent(req, "Authentication failed")
b.auth.RequireAuth(rw, req)
} else {
logger.Debug("Authentication succeeded")
req.URL.User = url.User(username)
logData := accesslog.GetLogData(req)
if logData != nil {
logData.Core[accesslog.ClientUsername] = username
}
if b.headerField != "" {
req.Header[b.headerField] = []string{username}
}
if b.removeHeader {
logger.Debug("Removing authorization header")
req.Header.Del(authorizationHeader)
}
b.next.ServeHTTP(rw, req)
return
}
logger.Debug("Authentication succeeded")
req.URL.User = url.User(user)
if b.headerField != "" {
req.Header[b.headerField] = []string{user}
}
if b.removeHeader {
logger.Debug("Removing authorization header")
req.Header.Del(authorizationHeader)
}
b.next.ServeHTTP(rw, req)
}
func (b *basicAuth) secretBasic(user, realm string) string {

View file

@ -63,6 +63,19 @@ func (d *digestAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
username, authinfo := d.auth.CheckAuth(req)
if username == "" {
headerField := d.headerField
if d.headerField == "" {
headerField = "Authorization"
}
auth := goauth.DigestAuthParams(req.Header.Get(headerField))
if auth["username"] != "" {
logData := accesslog.GetLogData(req)
if logData != nil {
logData.Core[accesslog.ClientUsername] = auth["username"]
}
}
if authinfo != nil && *authinfo == "stale" {
logger.Debug("Digest authentication failed, possibly because out of order requests")
tracing.SetErrorWithEvent(req, "Digest authentication failed, possibly because out of order requests")

View file

@ -158,7 +158,7 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
fa.next.ServeHTTP(rw, req)
}
func writeHeader(req *http.Request, forwardReq *http.Request, trustForwardHeader bool) {
func writeHeader(req, forwardReq *http.Request, trustForwardHeader bool) {
utils.CopyHeaders(forwardReq.Header, req.Header)
utils.RemoveHeaders(forwardReq.Header, forward.HopHeaders...)

View file

@ -325,7 +325,8 @@ func Test_writeHeader(t *testing.T) {
"X-Forwarded-Host": "foo.bar",
"X-Forwarded-Uri": "/path?q=1",
},
}, {
},
{
name: "trust Forward Header with forwarded request Method",
headers: map[string]string{
"X-Forwarded-Method": "OPTIONS",

View file

@ -246,7 +246,8 @@ func TestServeHTTP(t *testing.T) {
expectedHeaders: map[string]string{
xForwardedHost: "foo.com:8080",
},
}, {
},
{
desc: "xForwardedServer from req XForwarded",
host: "foo.com:8080",
expectedHeaders: map[string]string{

View file

@ -54,13 +54,13 @@ func New(ctx context.Context, next http.Handler, cfg dynamic.Headers, name strin
nextHandler := next
if hasSecureHeaders {
logger.Debug("Setting up secureHeaders from %v", cfg)
logger.Debugf("Setting up secureHeaders from %v", cfg)
handler = newSecure(next, cfg, name)
nextHandler = handler
}
if hasCustomHeaders || hasCorsHeaders {
logger.Debug("Setting up customHeaders/Cors from %v", cfg)
logger.Debugf("Setting up customHeaders/Cors from %v", cfg)
handler = NewHeader(nextHandler, cfg)
}

View file

@ -552,7 +552,8 @@ func TestCORSResponses(t *testing.T) {
expected: map[string][]string{
"Access-Control-Allow-Origin": {"*"},
},
}, {
},
{
desc: "Test Simple CustomRequestHeaders Not Hijacked by CORS",
header: NewHeader(emptyHandler, dynamic.Headers{
CustomRequestHeaders: map[string]string{"foo": "bar"},

View file

@ -7,6 +7,6 @@ import (
)
// GetLoggerCtx creates a logger context with the middleware fields.
func GetLoggerCtx(ctx context.Context, middleware string, middlewareType string) context.Context {
func GetLoggerCtx(ctx context.Context, middleware, middlewareType string) context.Context {
return log.With(ctx, log.Str(log.MiddlewareName, middleware), log.Str(log.MiddlewareType, middlewareType))
}

View file

@ -235,7 +235,7 @@ func writeParts(ctx context.Context, content io.StringWriter, entries []string,
}
}
func writePart(ctx context.Context, content io.StringWriter, entry string, prefix string) {
func writePart(ctx context.Context, content io.StringWriter, entry, prefix string) {
if len(entry) > 0 {
_, err := content.WriteString(fmt.Sprintf("%s=%s%s", prefix, entry, subFieldSeparator))
if err != nil {

View file

@ -24,7 +24,7 @@ type redirect struct {
}
// New creates a Redirect middleware.
func newRedirect(next http.Handler, regex string, replacement string, permanent bool, name string) (http.Handler, error) {
func newRedirect(next http.Handler, regex, replacement string, permanent bool, name string) (http.Handler, error) {
re, err := regexp.Compile(regex)
if err != nil {
return nil, err
@ -115,7 +115,7 @@ func rawURL(req *http.Request) string {
port := ""
uri := req.RequestURI
schemeRegex := `^(https?):\/\/([\w\._-]+)(:\d+)?(.*)$`
schemeRegex := `^(https?):\/\/(\[[\w:.]+\]|[\w\._-]+)?(:\d+)?(.*)$`
re, _ := regexp.Compile(schemeRegex)
if re.Match([]byte(req.RequestURI)) {
match := re.FindStringSubmatch(req.RequestURI)

View file

@ -12,7 +12,7 @@ import (
const (
typeSchemeName = "RedirectScheme"
schemeRedirectRegex = `^(https?:\/\/)?([\w\._-]+)(:\d+)?(.*)$`
schemeRedirectRegex = `^(https?:\/\/)?(\[[\w:.]+\]|[\w\._-]+)?(:\d+)?(.*)$`
)
// NewRedirectScheme creates a new RedirectScheme middleware.

View file

@ -186,6 +186,44 @@ func TestRedirectSchemeHandler(t *testing.T) {
expectedURL: "https://foo",
expectedStatus: http.StatusFound,
},
{
desc: "IPV6 HTTP to HTTPS redirection without port",
config: dynamic.RedirectScheme{
Scheme: "https",
},
url: "http://[::1]",
expectedURL: "https://[::1]",
expectedStatus: http.StatusFound,
},
{
desc: "IPV6 HTTP to HTTPS redirection with port",
config: dynamic.RedirectScheme{
Scheme: "https",
Port: "8443",
},
url: "http://[::1]",
expectedURL: "https://[::1]:8443",
expectedStatus: http.StatusFound,
},
{
desc: "IPV6 HTTP with port 80 to HTTPS redirection without port",
config: dynamic.RedirectScheme{
Scheme: "https",
},
url: "http://[::1]:80",
expectedURL: "https://[::1]",
expectedStatus: http.StatusFound,
},
{
desc: "IPV6 HTTP with port 80 to HTTPS redirection with port",
config: dynamic.RedirectScheme{
Scheme: "https",
Port: "8443",
},
url: "http://[::1]:80",
expectedURL: "https://[::1]:8443",
expectedStatus: http.StatusFound,
},
}
for _, test := range testCases {
@ -235,7 +273,7 @@ func TestRedirectSchemeHandler(t *testing.T) {
require.Errorf(t, err, "Location %v", location)
}
schemeRegex := `^(https?):\/\/([\w\._-]+)(:\d+)?(.*)$`
schemeRegex := `^(https?):\/\/(\[[\w:.]+\]|[\w\._-]+)?(:\d+)?(.*)$`
re, _ := regexp.Compile(schemeRegex)
if re.Match([]byte(test.url)) {

View file

@ -47,7 +47,7 @@ func (hr *Resolver) CNAMEFlatten(ctx context.Context, host string) string {
}
logger := log.FromContext(ctx)
var cacheDuration = 0 * time.Second
cacheDuration := 0 * time.Second
for depth := 0; depth < hr.ResolvDepth; depth++ {
resolv, err := cnameResolve(ctx, request, hr.ResolvConfig)
if err != nil {
@ -73,7 +73,7 @@ func (hr *Resolver) CNAMEFlatten(ctx context.Context, host string) string {
}
// cnameResolve resolves CNAME if exists, and return with the highest TTL.
func cnameResolve(ctx context.Context, host string, resolvPath string) (*cnameResolv, error) {
func cnameResolve(ctx context.Context, host, resolvPath string) (*cnameResolv, error) {
config, err := dns.ClientConfigFromFile(resolvPath)
if err != nil {
return nil, fmt.Errorf("invalid resolver configuration file: %s", resolvPath)
@ -102,7 +102,7 @@ func cnameResolve(ctx context.Context, host string, resolvPath string) (*cnameRe
return result[0], nil
}
func getRecord(client *dns.Client, msg *dns.Msg, server string, port string) (*cnameResolv, error) {
func getRecord(client *dns.Client, msg *dns.Msg, server, port string) (*cnameResolv, error) {
resp, _, err := client.Exchange(msg, net.JoinHostPort(server, port))
if err != nil {
return nil, fmt.Errorf("exchange error for server %s: %w", server, err)

View file

@ -45,7 +45,8 @@ func TestNewForwarder(t *testing.T) {
},
OperationName: "forward some-service.domain.tld/some-service.domain.tld",
},
}, {
},
{
desc: "Simple Forward Tracer with truncation and hashing",
spanNameLimit: 101,
tracing: &trackingBackenMock{

View file

@ -18,12 +18,12 @@ func (n MockTracer) StartSpan(operationName string, opts ...opentracing.StartSpa
}
// Inject belongs to the Tracer interface.
func (n MockTracer) Inject(sp opentracing.SpanContext, format interface{}, carrier interface{}) error {
func (n MockTracer) Inject(sp opentracing.SpanContext, format, carrier interface{}) error {
return nil
}
// Extract belongs to the Tracer interface.
func (n MockTracer) Extract(format interface{}, carrier interface{}) (opentracing.SpanContext, error) {
func (n MockTracer) Extract(format, carrier interface{}) (opentracing.SpanContext, error) {
return nil, opentracing.ErrSpanContextNotFound
}

View file

@ -26,7 +26,7 @@ const (
)
// NewAccount creates an account.
func NewAccount(ctx context.Context, email string, keyTypeValue string) (*Account, error) {
func NewAccount(ctx context.Context, email, keyTypeValue string) (*Account, error) {
keyType := GetKeyType(ctx, keyTypeValue)
// Create a user. New accounts need an email and private key to start

View file

@ -103,7 +103,7 @@ func (s *LocalStore) listenSaveAction() {
logger.Error(err)
}
err = ioutil.WriteFile(s.filename, data, 0600)
err = ioutil.WriteFile(s.filename, data, 0o600)
if err != nil {
logger.Error(err)
}

View file

@ -16,7 +16,7 @@ func CheckFile(name string) (bool, error) {
if err != nil {
return false, err
}
return false, f.Chmod(0600)
return false, f.Chmod(0o600)
}
return false, err
}
@ -27,7 +27,7 @@ func CheckFile(name string) (bool, error) {
return false, err
}
if fi.Mode().Perm()&0077 != 0 {
if fi.Mode().Perm()&0o077 != 0 {
return false, fmt.Errorf("permissions %o for %s are too open, please use 600", fi.Mode().Perm(), name)
}

View file

@ -12,7 +12,7 @@ func CheckFile(name string) (bool, error) {
if err != nil {
return false, err
}
return false, f.Chmod(0600)
return false, f.Chmod(0o600)
}
return false, err
}

View file

@ -27,10 +27,8 @@ import (
"github.com/go-acme/lego/v3/registration"
)
var (
// oscpMustStaple enables OSCP stapling as from https://github.com/go-acme/lego/issues/270.
oscpMustStaple = false
)
// oscpMustStaple enables OSCP stapling as from https://github.com/go-acme/lego/issues/270.
var oscpMustStaple = false
// Configuration holds ACME configuration provided by users.
type Configuration struct {
@ -145,7 +143,7 @@ func (p *Provider) Init() error {
return nil
}
func isAccountMatchingCaServer(ctx context.Context, accountURI string, serverURI string) bool {
func isAccountMatchingCaServer(ctx context.Context, accountURI, serverURI string) bool {
logger := log.FromContext(ctx)
aru, err := url.Parse(accountURI)
@ -428,13 +426,11 @@ func (p *Provider) resolveCertificate(ctx context.Context, domain types.Domain,
return nil, err
}
// Check provided certificates
// Check if provided certificates are not already in progress and lock them if needed
uncheckedDomains := p.getUncheckedDomains(ctx, domains, tlsStore)
if len(uncheckedDomains) == 0 {
return nil, nil
}
p.addResolvingDomains(uncheckedDomains)
defer p.removeResolvingDomains(uncheckedDomains)
logger := log.FromContext(ctx)
@ -483,16 +479,7 @@ func (p *Provider) removeResolvingDomains(resolvingDomains []string) {
}
}
func (p *Provider) addResolvingDomains(resolvingDomains []string) {
p.resolvingDomainsMutex.Lock()
defer p.resolvingDomainsMutex.Unlock()
for _, domain := range resolvingDomains {
p.resolvingDomains[domain] = struct{}{}
}
}
func (p *Provider) addCertificateForDomain(domain types.Domain, certificate []byte, key []byte, tlsStore string) {
func (p *Provider) addCertificateForDomain(domain types.Domain, certificate, key []byte, tlsStore string) {
p.certsChan <- &CertAndStore{Certificate: Certificate{Certificate: certificate, Key: key, Domain: domain}, Store: tlsStore}
}
@ -640,7 +627,6 @@ func (p *Provider) renewCertificates(ctx context.Context) {
PrivateKey: cert.Key,
Certificate: cert.Certificate.Certificate,
}, true, oscpMustStaple)
if err != nil {
logger.Errorf("Error renewing certificate from LE: %v, %v", cert.Domain, err)
continue
@ -659,8 +645,8 @@ func (p *Provider) renewCertificates(ctx context.Context) {
// Get provided certificate which check a domains list (Main and SANs)
// from static and dynamic provided certificates.
func (p *Provider) getUncheckedDomains(ctx context.Context, domainsToCheck []string, tlsStore string) []string {
p.resolvingDomainsMutex.RLock()
defer p.resolvingDomainsMutex.RUnlock()
p.resolvingDomainsMutex.Lock()
defer p.resolvingDomainsMutex.Unlock()
log.FromContext(ctx).Debugf("Looking for provided certificate(s) to validate %q...", domainsToCheck)
@ -676,10 +662,17 @@ func (p *Provider) getUncheckedDomains(ctx context.Context, domainsToCheck []str
allDomains = append(allDomains, domain)
}
return searchUncheckedDomains(ctx, domainsToCheck, allDomains)
uncheckedDomains := searchUncheckedDomains(ctx, domainsToCheck, allDomains)
// Lock domains that will be resolved by this routine
for _, domain := range uncheckedDomains {
p.resolvingDomains[domain] = struct{}{}
}
return uncheckedDomains
}
func searchUncheckedDomains(ctx context.Context, domainsToCheck []string, existentDomains []string) []string {
func searchUncheckedDomains(ctx context.Context, domainsToCheck, existentDomains []string) []string {
var uncheckedDomains []string
for _, domainToCheck := range domainsToCheck {
if !isDomainAlreadyChecked(domainToCheck, existentDomains) {

View file

@ -95,7 +95,7 @@ func taskSlot(slot int) func(*swarm.Task) {
}
}
func taskNetworkAttachment(id string, name string, driver string, addresses []string) func(*swarm.Task) {
func taskNetworkAttachment(id, name, driver string, addresses []string) func(*swarm.Task) {
return func(task *swarm.Task) {
task.NetworksAttachments = append(task.NetworksAttachments, swarm.NetworkAttachment{
Network: swarm.Network{

View file

@ -350,7 +350,6 @@ func (p Provider) getIPAddress(ctx context.Context, container dockerData) string
// the network specified on the current container.
containerParsed := parseContainer(containerInspected)
extraConf, err := p.getConfiguration(containerParsed)
if err != nil {
logger.Warnf("Unable to get IP address for container %s : failed to get extra configuration for container %s: %s", container.Name, containerInspected.Name, err)
return ""

View file

@ -55,7 +55,7 @@ func getStringMultipleStrict(labels map[string]string, labelNames ...string) (ma
}
// getStringValue get string value associated to a label.
func getStringValue(labels map[string]string, labelName string, defaultValue string) string {
func getStringValue(labels map[string]string, labelName, defaultValue string) string {
if value, ok := labels[labelName]; ok && len(value) > 0 {
return value
}

View file

@ -48,7 +48,6 @@ func (p *Provider) Init() error {
// using the given configuration channel.
func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.Pool) error {
configuration, err := p.BuildConfiguration()
if err != nil {
return err
}
@ -356,7 +355,7 @@ func (p *Provider) CreateConfiguration(ctx context.Context, filename string, fun
return nil, fmt.Errorf("error reading configuration file: %s - %w", filename, err)
}
var defaultFuncMap = sprig.TxtFuncMap()
defaultFuncMap := sprig.TxtFuncMap()
defaultFuncMap["normalize"] = provider.Normalize
defaultFuncMap["split"] = strings.Split
for funcID, funcElement := range funcMap {
@ -376,7 +375,7 @@ func (p *Provider) CreateConfiguration(ctx context.Context, filename string, fun
return nil, err
}
var renderedTemplate = buffer.String()
renderedTemplate := buffer.String()
if p.DebugLogGeneratedTemplate {
logger := log.FromContext(ctx)
logger.Debugf("Template content: %s", tmplContent)
@ -396,7 +395,7 @@ func (p *Provider) DecodeConfiguration(filename string) (*dynamic.Configuration,
return p.decodeConfiguration(filename, content)
}
func (p *Provider) decodeConfiguration(filePath string, content string) (*dynamic.Configuration, error) {
func (p *Provider) decodeConfiguration(filePath, content string) (*dynamic.Configuration, error) {
configuration := &dynamic.Configuration{
HTTP: &dynamic.HTTPConfiguration{
Routers: make(map[string]*dynamic.Router),

View file

@ -293,7 +293,7 @@ func createTempDir(t *testing.T, dir string) string {
}
func copyFile(srcPath, dstPath string) error {
dst, err := os.OpenFile(dstPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
dst, err := os.OpenFile(dstPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o666)
if err != nil {
return err
}

View file

@ -1,15 +0,0 @@
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRouteTCP
metadata:
name: test.route
namespace: default
spec:
entryPoints:
- web
routes:
- match: HostSNI(`foo.com"0"`)
services:
- name: whoamitcp
port: 8000

View file

@ -1,17 +0,0 @@
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: test.route
namespace: default
spec:
entryPoints:
- web
routes:
- match: Host(`foo.com"0"`) && PathPrefix(`/bar`)
kind: Rule
priority: 12
services:
- name: whoami
port: 80

View file

@ -35,12 +35,14 @@ import (
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
)
var scheme = runtime.NewScheme()
var codecs = serializer.NewCodecFactory(scheme)
var parameterCodec = runtime.NewParameterCodec(scheme)
var localSchemeBuilder = runtime.SchemeBuilder{
traefikv1alpha1.AddToScheme,
}
var (
scheme = runtime.NewScheme()
codecs = serializer.NewCodecFactory(scheme)
parameterCodec = runtime.NewParameterCodec(scheme)
localSchemeBuilder = runtime.SchemeBuilder{
traefikv1alpha1.AddToScheme,
}
)
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
// of clientsets, like in:

View file

@ -35,12 +35,14 @@ import (
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
)
var Scheme = runtime.NewScheme()
var Codecs = serializer.NewCodecFactory(Scheme)
var ParameterCodec = runtime.NewParameterCodec(Scheme)
var localSchemeBuilder = runtime.SchemeBuilder{
traefikv1alpha1.AddToScheme,
}
var (
Scheme = runtime.NewScheme()
Codecs = serializer.NewCodecFactory(Scheme)
ParameterCodec = runtime.NewParameterCodec(Scheme)
localSchemeBuilder = runtime.SchemeBuilder{
traefikv1alpha1.AddToScheme,
}
)
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
// of clientsets, like in:

View file

@ -85,7 +85,6 @@ func (c *FakeIngressRoutes) List(ctx context.Context, opts v1.ListOptions) (resu
func (c *FakeIngressRoutes) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(ingressroutesResource, c.ns, opts))
}
// Create takes the representation of a ingressRoute and creates it. Returns the server's representation of the ingressRoute, and an error, if there is any.

View file

@ -85,7 +85,6 @@ func (c *FakeIngressRouteTCPs) List(ctx context.Context, opts v1.ListOptions) (r
func (c *FakeIngressRouteTCPs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(ingressroutetcpsResource, c.ns, opts))
}
// Create takes the representation of a ingressRouteTCP and creates it. Returns the server's representation of the ingressRouteTCP, and an error, if there is any.

View file

@ -85,7 +85,6 @@ func (c *FakeIngressRouteUDPs) List(ctx context.Context, opts v1.ListOptions) (r
func (c *FakeIngressRouteUDPs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(ingressrouteudpsResource, c.ns, opts))
}
// Create takes the representation of a ingressRouteUDP and creates it. Returns the server's representation of the ingressRouteUDP, and an error, if there is any.

View file

@ -85,7 +85,6 @@ func (c *FakeMiddlewares) List(ctx context.Context, opts v1.ListOptions) (result
func (c *FakeMiddlewares) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(middlewaresResource, c.ns, opts))
}
// Create takes the representation of a middleware and creates it. Returns the server's representation of the middleware, and an error, if there is any.

View file

@ -85,7 +85,6 @@ func (c *FakeTLSOptions) List(ctx context.Context, opts v1.ListOptions) (result
func (c *FakeTLSOptions) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(tlsoptionsResource, c.ns, opts))
}
// Create takes the representation of a tLSOption and creates it. Returns the server's representation of the tLSOption, and an error, if there is any.

View file

@ -85,7 +85,6 @@ func (c *FakeTLSStores) List(ctx context.Context, opts v1.ListOptions) (result *
func (c *FakeTLSStores) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(tlsstoresResource, c.ns, opts))
}
// Create takes the representation of a tLSStore and creates it. Returns the server's representation of the tLSStore, and an error, if there is any.

View file

@ -85,7 +85,6 @@ func (c *FakeTraefikServices) List(ctx context.Context, opts v1.ListOptions) (re
func (c *FakeTraefikServices) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(traefikservicesResource, c.ns, opts))
}
// Create takes the representation of a traefikService and creates it. Returns the server's representation of the traefikService, and an error, if there is any.

View file

@ -9,7 +9,6 @@ import (
"fmt"
"os"
"sort"
"strconv"
"strings"
"time"
@ -102,7 +101,6 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
pool.GoCtx(func(ctxPool context.Context) {
operation := func() error {
eventsChan, err := k8sClient.WatchAll(p.Namespaces, ctxPool.Done())
if err != nil {
logger.Errorf("Error watching kubernetes events: %v", err)
timer := time.NewTimer(1 * time.Second)
@ -609,11 +607,6 @@ func buildTLSStores(ctx context.Context, client Client) map[string]tls.Store {
return tlsStores
}
func checkStringQuoteValidity(value string) error {
_, err := strconv.Unquote(`"` + value + `"`)
return err
}
func makeServiceKey(rule, ingressName string) (string, error) {
h := sha256.New()
if _, err := h.Write([]byte(rule)); err != nil {
@ -633,7 +626,7 @@ func makeID(namespace, name string) string {
return namespace + "-" + name
}
func shouldProcessIngress(ingressClass string, ingressClassAnnotation string) bool {
func shouldProcessIngress(ingressClass, ingressClassAnnotation string) bool {
return ingressClass == ingressClassAnnotation ||
(len(ingressClass) == 0 && ingressClassAnnotation == traefikDefaultIngressClass)
}

View file

@ -58,11 +58,6 @@ func (p *Provider) loadIngressRouteConfiguration(ctx context.Context, client Cli
continue
}
if err := checkStringQuoteValidity(route.Match); err != nil {
logger.Errorf("Invalid syntax for match rule: %s", route.Match)
continue
}
serviceKey, err := makeServiceKey(route.Match, ingressName)
if err != nil {
logger.Error(err)
@ -437,7 +432,7 @@ func getTLSHTTP(ctx context.Context, ingressRoute *v1alpha1.IngressRoute, k8sCli
// parseServiceProtocol parses the scheme, port name, and number to determine the correct protocol.
// an error is returned if the scheme provided is invalid.
func parseServiceProtocol(providedScheme string, portName string, portNumber int32) (string, error) {
func parseServiceProtocol(providedScheme, portName string, portNumber int32) (string, error) {
switch providedScheme {
case httpProtocol, httpsProtocol, "h2c":
return providedScheme, nil

View file

@ -44,11 +44,6 @@ func (p *Provider) loadIngressRouteTCPConfiguration(ctx context.Context, client
continue
}
if err := checkStringQuoteValidity(route.Match); err != nil {
logger.Errorf("Invalid syntax for match rule: %s", route.Match)
continue
}
key, err := makeServiceKey(route.Match, ingressName)
if err != nil {
logger.Error(err)

View file

@ -372,26 +372,6 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "check rule quoting validity",
paths: []string{"tcp/services.yml", "tcp/with_bad_host_rule.yml"},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Services: map[string]*dynamic.TCPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "TLS",
paths: []string{"tcp/services.yml", "tcp/with_tls.yml"},
@ -2149,26 +2129,6 @@ func TestLoadIngressRoutes(t *testing.T) {
},
},
},
{
desc: "check rule quoting validity",
paths: []string{"services.yml", "with_bad_host_rule.yml"},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TLS: &dynamic.TLSConfiguration{},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Services: map[string]*dynamic.TCPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
},
},
},
{
desc: "TLS",
paths: []string{"services.yml", "with_tls.yml"},
@ -2980,7 +2940,8 @@ func TestLoadIngressRoutes(t *testing.T) {
EntryPoints: []string{"foo"},
Service: "default-test-route-6f97418635c7e18853da",
Rule: "Host(`foo.com`)",
}},
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-test-route-6f97418635c7e18853da": {
@ -3016,7 +2977,8 @@ func TestLoadIngressRoutes(t *testing.T) {
EntryPoints: []string{"foo"},
Service: "default-test-route-6f97418635c7e18853da",
Rule: "Host(`foo.com`)",
}},
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-test-route-6f97418635c7e18853da": {
@ -3052,7 +3014,8 @@ func TestLoadIngressRoutes(t *testing.T) {
EntryPoints: []string{"foo"},
Service: "default-test-route-6f97418635c7e18853da",
Rule: "Host(`foo.com`)",
}},
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-test-route-6f97418635c7e18853da": {

View file

@ -107,6 +107,7 @@ func loadUDPServers(client Client, namespace string, svc v1alpha1.ServiceUDP) ([
var portSpec *corev1.ServicePort
for _, p := range service.Spec.Ports {
p := p
if svc.Port == p.Port {
portSpec = &p
break

View file

@ -105,7 +105,7 @@ func Test_parseServiceConfig(t *testing.T) {
"traefik.ingress.kubernetes.io/foo": "bar",
"traefik.ingress.kubernetes.io/service.serversscheme": "protocol",
"traefik.ingress.kubernetes.io/service.passhostheader": "true",
"traefik.ingress.kubernetes.io/service.sticky": "true",
"traefik.ingress.kubernetes.io/service.sticky.cookie": "true",
"traefik.ingress.kubernetes.io/service.sticky.cookie.httponly": "true",
"traefik.ingress.kubernetes.io/service.sticky.cookie.name": "foobar",
"traefik.ingress.kubernetes.io/service.sticky.cookie.secure": "true",
@ -129,11 +129,11 @@ func Test_parseServiceConfig(t *testing.T) {
{
desc: "simple sticky annotation",
annotations: map[string]string{
"traefik.ingress.kubernetes.io/service.sticky": "true",
"traefik.ingress.kubernetes.io/service.sticky.cookie": "true",
},
expected: &ServiceConfig{
Service: &ServiceIng{
Sticky: &dynamic.Sticky{},
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{}},
PassHostHeader: Bool(true),
},
},
@ -206,7 +206,7 @@ func Test_convertAnnotations(t *testing.T) {
annotations: map[string]string{
"traefik.ingress.kubernetes.io/service.serversscheme": "protocol",
"traefik.ingress.kubernetes.io/service.passhostheader": "true",
"traefik.ingress.kubernetes.io/service.sticky": "true",
"traefik.ingress.kubernetes.io/service.sticky.cookie": "true",
"traefik.ingress.kubernetes.io/service.sticky.cookie.httponly": "true",
"traefik.ingress.kubernetes.io/service.sticky.cookie.name": "foobar",
"traefik.ingress.kubernetes.io/service.sticky.cookie.secure": "true",
@ -214,7 +214,7 @@ func Test_convertAnnotations(t *testing.T) {
expected: map[string]string{
"traefik.service.passhostheader": "true",
"traefik.service.serversscheme": "protocol",
"traefik.service.sticky": "true",
"traefik.service.sticky.cookie": "true",
"traefik.service.sticky.cookie.httponly": "true",
"traefik.service.sticky.cookie.name": "foobar",
"traefik.service.sticky.cookie.secure": "true",

View file

@ -1,22 +0,0 @@
kind: Ingress
apiVersion: networking.k8s.io/v1beta1
metadata:
name: ""
namespace: testing
spec:
rules:
- host: traefik.tchouk"0"
http:
paths:
- path: /foo
backend:
serviceName: service1
servicePort: 80
- host: traefik.courgette
http:
paths:
- path: /carotte
backend:
serviceName: service1
servicePort: 80

View file

@ -1,23 +0,0 @@
kind: Ingress
apiVersion: networking.k8s.io/v1beta1
metadata:
name: ""
namespace: testing
spec:
rules:
- host: ""
http:
paths:
- path: /foo
backend:
serviceName: service1
servicePort: 80
- path: /bar-"0"
backend:
serviceName: service1
servicePort: 80
- path: /bar
backend:
serviceName: service1
servicePort: 80

View file

@ -1,15 +0,0 @@
kind: Ingress
apiVersion: networking.k8s.io/v1beta1
metadata:
name: ""
namespace: testing
spec:
rules:
- host: traefik.tchouk"0"
http:
paths:
- path: /foo
backend:
serviceName: service1
servicePort: 80

View file

@ -1,14 +0,0 @@
kind: Ingress
apiVersion: networking.k8s.io/v1beta1
metadata:
name: ""
namespace: testing
spec:
rules:
- http:
paths:
- path: /bar-"0"
backend:
serviceName: service1
servicePort: 80

View file

@ -7,7 +7,6 @@ import (
"math"
"os"
"sort"
"strconv"
"strings"
"time"
@ -235,11 +234,6 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl
}
for _, rule := range ingress.Spec.Rules {
if err := checkStringQuoteValidity(rule.Host); err != nil {
log.FromContext(ctx).Errorf("Invalid syntax for host: %s", rule.Host)
continue
}
if err := p.updateIngressStatus(ingress, client); err != nil {
log.FromContext(ctx).Errorf("Error while updating ingress status: %v", err)
}
@ -249,11 +243,6 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl
}
for _, pa := range rule.HTTP.Paths {
if err = checkStringQuoteValidity(pa.Path); err != nil {
log.FromContext(ctx).Errorf("Invalid syntax for path: %s", pa.Path)
continue
}
service, err := loadService(client, ingress.Namespace, pa.Backend)
if err != nil {
log.FromContext(ctx).
@ -330,7 +319,7 @@ func buildHostRule(host string) string {
return "Host(`" + host + "`)"
}
func shouldProcessIngress(ingressClass string, ingressClassAnnotation string) bool {
func shouldProcessIngress(ingressClass, ingressClassAnnotation string) bool {
return ingressClass == ingressClassAnnotation ||
(len(ingressClass) == 0 && ingressClassAnnotation == traefikDefaultIngressClass)
}
@ -559,11 +548,6 @@ func loadRouter(rule v1beta1.IngressRule, pa v1beta1.HTTPIngressPath, rtConfig *
return rt
}
func checkStringQuoteValidity(value string) error {
_, err := strconv.Unquote(`"` + value + `"`)
return err
}
func throttleEvents(ctx context.Context, throttleDuration time.Duration, pool *safe.Pool, eventsChan <-chan interface{}) chan interface{} {
if throttleDuration == 0 {
return nil

View file

@ -327,92 +327,6 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
},
},
},
{
desc: "Ingress with a bad path syntax",
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{},
HTTP: &dynamic.HTTPConfiguration{
Middlewares: map[string]*dynamic.Middleware{},
Routers: map[string]*dynamic.Router{
"testing-bar": {
Rule: "PathPrefix(`/bar`)",
Service: "testing-service1-80",
},
"testing-foo": {
Rule: "PathPrefix(`/foo`)",
Service: "testing-service1-80",
},
},
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:8080",
},
{
URL: "http://10.21.0.1:8080",
},
},
},
},
},
},
},
},
{
desc: "Ingress with only a bad path syntax",
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{},
HTTP: &dynamic.HTTPConfiguration{
Middlewares: map[string]*dynamic.Middleware{},
Routers: map[string]*dynamic.Router{},
Services: map[string]*dynamic.Service{},
},
},
},
{
desc: "Ingress with a bad host syntax",
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{},
HTTP: &dynamic.HTTPConfiguration{
Middlewares: map[string]*dynamic.Middleware{},
Routers: map[string]*dynamic.Router{
"testing-traefik-courgette-carotte": {
Rule: "Host(`traefik.courgette`) && PathPrefix(`/carotte`)",
Service: "testing-service1-80",
},
},
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:8080",
},
{
URL: "http://10.21.0.1:8080",
},
},
},
},
},
},
},
},
{
desc: "Ingress with only a bad host syntax",
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{},
HTTP: &dynamic.HTTPConfiguration{
Middlewares: map[string]*dynamic.Middleware{},
Routers: map[string]*dynamic.Router{},
Services: map[string]*dynamic.Service{},
},
},
},
{
desc: "Ingress with two services",
expected: &dynamic.Configuration{

View file

@ -129,7 +129,7 @@ func (_m *Marathon) ApplicationBy(name string, opts *marathon.GetAppOpts) (*mara
}
// ApplicationByVersion provides a mock function with given fields: name, version
func (_m *Marathon) ApplicationByVersion(name string, version string) (*marathon.Application, error) {
func (_m *Marathon) ApplicationByVersion(name, version string) (*marathon.Application, error) {
ret := _m.Called(name, version)
var r0 *marathon.Application
@ -394,7 +394,7 @@ func (_m *Marathon) DeletePod(name string, force bool) (*marathon.DeploymentID,
}
// DeletePodInstance provides a mock function with given fields: name, instance
func (_m *Marathon) DeletePodInstance(name string, instance string) (*marathon.PodInstance, error) {
func (_m *Marathon) DeletePodInstance(name, instance string) (*marathon.PodInstance, error) {
ret := _m.Called(name, instance)
var r0 *marathon.PodInstance
@ -583,7 +583,7 @@ func (_m *Marathon) GroupsBy(opts *marathon.GetGroupOpts) (*marathon.Groups, err
}
// HasApplicationVersion provides a mock function with given fields: name, version
func (_m *Marathon) HasApplicationVersion(name string, version string) (bool, error) {
func (_m *Marathon) HasApplicationVersion(name, version string) (bool, error) {
ret := _m.Called(name, version)
var r0 bool
@ -817,7 +817,7 @@ func (_m *Marathon) Pod(name string) (*marathon.Pod, error) {
}
// PodByVersion provides a mock function with given fields: name, version
func (_m *Marathon) PodByVersion(name string, version string) (*marathon.Pod, error) {
func (_m *Marathon) PodByVersion(name, version string) (*marathon.Pod, error) {
ret := _m.Called(name, version)
var r0 *marathon.Pod

View file

@ -25,7 +25,7 @@
"middlewares": {
"dashboard_redirect": {
"redirectRegex": {
"regex": "^(http:\\/\\/[^:\\/]+(:\\d+)?)\\/$",
"regex": "^(http:\\/\\/(\\[[\\w:.]+\\]|[\\w\\._-]+)(:\\d+)?)\\/$",
"replacement": "${1}/dashboard/",
"permanent": true
}

View file

@ -57,7 +57,7 @@
"middlewares": {
"dashboard_redirect": {
"redirectRegex": {
"regex": "^(http:\\/\\/[^:\\/]+(:\\d+)?)\\/$",
"regex": "^(http:\\/\\/(\\[[\\w:.]+\\]|[\\w\\._-]+)(:\\d+)?)\\/$",
"replacement": "${1}/dashboard/",
"permanent": true
}

View file

@ -197,7 +197,7 @@ func (i *Provider) apiConfiguration(cfg *dynamic.Configuration) {
cfg.HTTP.Middlewares["dashboard_redirect"] = &dynamic.Middleware{
RedirectRegex: &dynamic.RedirectRegex{
Regex: `^(http:\/\/[^:\/]+(:\d+)?)\/$`,
Regex: `^(http:\/\/(\[[\w:.]+\]|[\w\._-]+)(:\d+)?)\/$`,
Replacement: "${1}/dashboard/",
Permanent: true,
},

View file

@ -209,7 +209,8 @@ func Test_createConfiguration(t *testing.T) {
},
},
},
}, {
},
{
desc: "redirection_port.json",
staticCfg: static.Configuration{
EntryPoints: map[string]*static.EntryPoint{
@ -248,7 +249,7 @@ func Test_createConfiguration(t *testing.T) {
newJSON, err := json.MarshalIndent(cfg, "", " ")
require.NoError(t, err)
err = ioutil.WriteFile(filename, newJSON, 0644)
err = ioutil.WriteFile(filename, newJSON, 0o644)
require.NoError(t, err)
}

View file

@ -8,6 +8,6 @@ import (
)
// getLogger creates a logger configured with the middleware fields.
func getLogger(ctx context.Context, middleware string, middlewareType string) logrus.FieldLogger {
func getLogger(ctx context.Context, middleware, middlewareType string) logrus.FieldLogger {
return log.FromContext(ctx).WithField(log.MiddlewareName, middleware).WithField(log.MiddlewareType, middlewareType)
}

View file

@ -19,6 +19,7 @@ type Builder struct {
}
// Build Builds the response modifier.
// It returns nil if there is no modifier to apply.
func (f *Builder) Build(ctx context.Context, names []string) func(*http.Response) error {
var modifiers []func(*http.Response) error
@ -44,7 +45,10 @@ func (f *Builder) Build(ctx context.Context, names []string) func(*http.Response
for _, name := range conf.Chain.Middlewares {
qualifiedNames = append(qualifiedNames, provider.GetQualifiedName(chainCtx, name))
}
modifiers = append(modifiers, f.Build(ctx, qualifiedNames))
if rm := f.Build(ctx, qualifiedNames); rm != nil {
modifiers = append(modifiers, rm)
}
}
}
@ -60,5 +64,5 @@ func (f *Builder) Build(ctx context.Context, names []string) func(*http.Response
}
}
return func(response *http.Response) error { return nil }
return nil
}

View file

@ -169,6 +169,21 @@ func TestBuilderBuild(t *testing.T) {
},
assertResponse: func(t *testing.T, resp *http.Response) {},
},
{
desc: "chain without headers",
middlewares: []string{"chain"},
buildResponse: stubResponse,
conf: map[string]*dynamic.Middleware{
"foo": {IPWhiteList: &dynamic.IPWhiteList{}},
"chain": {
Chain: &dynamic.Chain{
Middlewares: []string{"foo"},
},
},
},
assertResponse: func(t *testing.T, resp *http.Response) {},
},
}
for _, test := range testCases {
@ -184,6 +199,9 @@ func TestBuilderBuild(t *testing.T) {
builder := NewBuilder(rtConf.Middlewares)
rm := builder.Build(context.Background(), test.middlewares)
if rm == nil {
return
}
resp := test.buildResponse(test.conf)

View file

@ -12,7 +12,9 @@ import (
)
var funcs = map[string]func(*mux.Route, ...string) error{
"Host": host,
"Host": hostSecure,
"HostHeader": host,
"HostSNI": hostSNI,
"HostRegexp": hostRegexp,
"Path": path,
"PathPrefix": pathPrefix,
@ -22,6 +24,18 @@ var funcs = map[string]func(*mux.Route, ...string) error{
"Query": query,
}
// EnableDomainFronting initialize the matcher functions to used on routers.
// InsecureSNI defines if the domain fronting is allowed.
func EnableDomainFronting(ok bool) {
if ok {
log.WithoutContext().Warn("With insecureSNI enabled, router rules do not prevent domain fronting techniques. Please use `HostHeader` and `HostSNI` rules if domain fronting is not desired.")
funcs["Host"] = host
return
}
funcs["Host"] = hostSecure
}
// Router handle routing with rules.
type Router struct {
*mux.Router
@ -98,46 +112,125 @@ func host(route *mux.Route, hosts ...string) error {
}
route.MatcherFunc(func(req *http.Request, _ *mux.RouteMatch) bool {
reqHost := requestdecorator.GetCanonizedHost(req.Context())
if len(reqHost) == 0 {
log.FromContext(req.Context()).Warnf("Could not retrieve CanonizedHost, rejecting %s", req.Host)
return false
}
return matchHost(req, true, hosts...)
})
return nil
}
flatH := requestdecorator.GetCNAMEFlatten(req.Context())
if len(flatH) > 0 {
for _, host := range hosts {
if strings.EqualFold(reqHost, host) || strings.EqualFold(flatH, host) {
return true
}
log.FromContext(req.Context()).Debugf("CNAMEFlattening: request %s which resolved to %s, is not matched to route %s", reqHost, flatH, host)
}
return false
}
func matchHost(req *http.Request, insecureSNI bool, hosts ...string) bool {
logger := log.FromContext(req.Context())
reqHost := requestdecorator.GetCanonizedHost(req.Context())
if len(reqHost) == 0 {
logger.Warnf("Could not retrieve CanonizedHost, rejecting %s", req.Host)
return false
}
flatH := requestdecorator.GetCNAMEFlatten(req.Context())
if len(flatH) > 0 {
for _, host := range hosts {
if reqHost == host {
if strings.EqualFold(reqHost, host) || strings.EqualFold(flatH, host) {
return true
}
// Check for match on trailing period on host
if last := len(host) - 1; last >= 0 && host[last] == '.' {
h := host[:last]
if reqHost == h {
return true
}
}
// Check for match on trailing period on request
if last := len(reqHost) - 1; last >= 0 && reqHost[last] == '.' {
h := reqHost[:last]
if h == host {
return true
}
}
logger.Debugf("CNAMEFlattening: request %s which resolved to %s, is not matched to route %s", reqHost, flatH, host)
}
return false
}
for _, host := range hosts {
if reqHost == host {
logHostSNI(insecureSNI, req, reqHost)
return true
}
// Check for match on trailing period on host
if last := len(host) - 1; last >= 0 && host[last] == '.' {
h := host[:last]
if reqHost == h {
logHostSNI(insecureSNI, req, reqHost)
return true
}
}
// Check for match on trailing period on request
if last := len(reqHost) - 1; last >= 0 && reqHost[last] == '.' {
h := reqHost[:last]
if h == host {
logHostSNI(insecureSNI, req, reqHost)
return true
}
}
}
return false
}
func logHostSNI(insecureSNI bool, req *http.Request, reqHost string) {
if insecureSNI && req.TLS != nil && !strings.EqualFold(reqHost, req.TLS.ServerName) {
log.FromContext(req.Context()).Debugf("Router reached with Host(%q) different from SNI(%q)", reqHost, req.TLS.ServerName)
}
}
func hostSNI(route *mux.Route, hosts ...string) error {
for i, host := range hosts {
hosts[i] = strings.ToLower(host)
}
route.MatcherFunc(func(req *http.Request, _ *mux.RouteMatch) bool {
return matchSNI(req, hosts...)
})
return nil
}
func matchSNI(req *http.Request, hosts ...string) bool {
if req.TLS == nil {
return true
}
if req.TLS.ServerName == "" {
return false
}
for _, host := range hosts {
if strings.EqualFold(req.TLS.ServerName, host) {
return true
}
// Check for match on trailing period on host
if last := len(host) - 1; last >= 0 && host[last] == '.' {
h := host[:last]
if strings.EqualFold(req.TLS.ServerName, h) {
return true
}
}
// Check for match on trailing period on request
if last := len(req.TLS.ServerName) - 1; last >= 0 && req.TLS.ServerName[last] == '.' {
h := req.TLS.ServerName[:last]
if strings.EqualFold(h, host) {
return true
}
}
}
return false
}
func hostSecure(route *mux.Route, hosts ...string) error {
for i, host := range hosts {
hosts[i] = strings.ToLower(host)
}
route.MatcherFunc(func(req *http.Request, _ *mux.RouteMatch) bool {
for _, host := range hosts {
if matchSNI(req, host) && matchHost(req, false, host) {
return true
}
}
return false
})
return nil
}

View file

@ -681,6 +681,18 @@ func TestParseDomains(t *testing.T) {
domain: []string{"foo.bar", "test.bar"},
errorExpected: false,
},
{
description: "Many host rules upper",
expression: "HOST(`foo.bar`,`test.bar`)",
domain: []string{"foo.bar", "test.bar"},
errorExpected: false,
},
{
description: "Many host rules lower",
expression: "host(`foo.bar`,`test.bar`)",
domain: []string{"foo.bar", "test.bar"},
errorExpected: false,
},
{
description: "No host rule",
expression: "Path(`/test`)",

View file

@ -224,8 +224,8 @@ func (c *ConfigurationWatcher) throttleProviderConfigReload(ctx context.Context,
logger.Info("Skipping same configuration")
continue
}
previousConfig = nextConfig
ring.In() <- nextConfig
previousConfig = *nextConfig.DeepCopy()
ring.In() <- *nextConfig.DeepCopy()
}
}
}

View file

@ -301,3 +301,96 @@ func TestListenProvidersPublishesConfigForEachProvider(t *testing.T) {
assert.Equal(t, expected, publishedProviderConfig)
}
func TestPublishConfigUpdatedByProvider(t *testing.T) {
routinesPool := safe.NewPool(context.Background())
pvdConfiguration := dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"foo": {},
},
},
}
pvd := &mockProvider{
wait: 10 * time.Millisecond,
messages: []dynamic.Message{
{
ProviderName: "mock",
Configuration: &pvdConfiguration,
},
{
ProviderName: "mock",
Configuration: &pvdConfiguration,
},
},
}
watcher := NewConfigurationWatcher(routinesPool, pvd, 30*time.Millisecond, []string{})
publishedConfigCount := 0
watcher.AddListener(func(configuration dynamic.Configuration) {
publishedConfigCount++
// Update the provider configuration published in next dynamic Message which should trigger a new publish.
pvdConfiguration.TCP.Routers["bar"] = &dynamic.TCPRouter{}
})
watcher.Start()
defer watcher.Stop()
// give some time so that the configuration can be processed.
time.Sleep(100 * time.Millisecond)
assert.Equal(t, 2, publishedConfigCount)
}
func TestPublishConfigUpdatedByConfigWatcherListener(t *testing.T) {
routinesPool := safe.NewPool(context.Background())
pvd := &mockProvider{
wait: 10 * time.Millisecond,
messages: []dynamic.Message{
{
ProviderName: "mock",
Configuration: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"foo": {},
},
},
},
},
{
ProviderName: "mock",
Configuration: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"foo": {},
},
},
},
},
},
}
watcher := NewConfigurationWatcher(routinesPool, pvd, 30*time.Millisecond, []string{})
publishedConfigCount := 0
watcher.AddListener(func(configuration dynamic.Configuration) {
publishedConfigCount++
// Modify the provided configuration. This should not modify the configuration stored in the configuration
// watcher and cause a new publish.
configuration.TCP.Routers["foo@mock"].Rule = "bar"
})
watcher.Start()
defer watcher.Stop()
// give some time so that the configuration can be processed.
time.Sleep(100 * time.Millisecond)
assert.Equal(t, 1, publishedConfigCount)
}

View file

@ -11,7 +11,7 @@ import (
const cookieNameLength = 6
// GetName of a cookie.
func GetName(cookieName string, backendName string) string {
func GetName(cookieName, backendName string) string {
if len(cookieName) != 0 {
return sanitizeName(cookieName)
}

View file

@ -40,6 +40,6 @@ func GetQualifiedName(ctx context.Context, elementName string) string {
}
// MakeQualifiedName Creates a qualified name for an element.
func MakeQualifiedName(providerName string, elementName string) string {
func MakeQualifiedName(providerName, elementName string) string {
return elementName + "@" + providerName
}

View file

@ -2,6 +2,7 @@ package router
import (
"context"
"crypto/tls"
"io/ioutil"
"net/http"
"net/http/httptest"
@ -14,6 +15,7 @@ import (
"github.com/containous/traefik/v2/pkg/middlewares/accesslog"
"github.com/containous/traefik/v2/pkg/middlewares/requestdecorator"
"github.com/containous/traefik/v2/pkg/responsemodifiers"
"github.com/containous/traefik/v2/pkg/rules"
"github.com/containous/traefik/v2/pkg/server/middleware"
"github.com/containous/traefik/v2/pkg/server/service"
"github.com/containous/traefik/v2/pkg/testhelpers"
@ -25,6 +27,8 @@ import (
func TestRouterManager_Get(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
t.Cleanup(func() { server.Close() })
type expectedResult struct {
StatusCode int
RequestHeaders map[string]string
@ -310,9 +314,230 @@ func TestRouterManager_Get(t *testing.T) {
}
}
func TestRouterManager_SNI(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
t.Cleanup(func() { server.Close() })
type expectedResult struct {
StatusCode int
RequestHeaders map[string]string
}
testCases := []struct {
desc string
routersConfig map[string]*dynamic.Router
serviceConfig map[string]*dynamic.Service
middlewaresConfig map[string]*dynamic.Middleware
entryPoint string
sni string
insecureSNI bool
expected expectedResult
}{
{
desc: "Insecure SNI without TLS",
routersConfig: map[string]*dynamic.Router{
"foo@provider-1": {
EntryPoints: []string{"web"},
Service: "foo-service",
Rule: "Host(`foo.bar`)",
Priority: 0,
},
},
serviceConfig: map[string]*dynamic.Service{
"foo-service@provider-1": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: server.URL,
},
},
},
},
},
insecureSNI: true,
entryPoint: "web",
expected: expectedResult{StatusCode: http.StatusOK},
},
{
desc: "Secure SNI without TLS",
routersConfig: map[string]*dynamic.Router{
"foo@provider-1": {
EntryPoints: []string{"web"},
Service: "foo-service",
Rule: "Host(`foo.bar`)",
Priority: 0,
},
},
serviceConfig: map[string]*dynamic.Service{
"foo-service@provider-1": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: server.URL,
},
},
},
},
},
entryPoint: "web",
expected: expectedResult{StatusCode: http.StatusOK},
},
{
desc: "Secure SNI with TLS without sni",
routersConfig: map[string]*dynamic.Router{
"foo@provider-1": {
EntryPoints: []string{"websecure"},
Service: "foo-service",
Rule: "Host(`foo.bar`)",
Priority: 0,
TLS: &dynamic.RouterTLSConfig{},
},
},
serviceConfig: map[string]*dynamic.Service{
"foo-service@provider-1": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: server.URL,
},
},
},
},
},
entryPoint: "websecure",
expected: expectedResult{StatusCode: http.StatusNotFound},
},
{
desc: "Secure SNI with TLS with sni request",
routersConfig: map[string]*dynamic.Router{
"foo@provider-1": {
EntryPoints: []string{"websecure"},
Service: "foo-service",
Rule: "Host(`foo.bar`)",
Priority: 0,
TLS: &dynamic.RouterTLSConfig{},
},
},
serviceConfig: map[string]*dynamic.Service{
"foo-service@provider-1": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: server.URL,
},
},
},
},
},
entryPoint: "websecure",
sni: "foo.bar",
expected: expectedResult{StatusCode: http.StatusOK},
},
{
desc: "Insecure SNI with TLS without sni",
routersConfig: map[string]*dynamic.Router{
"foo@provider-1": {
EntryPoints: []string{"websecure"},
Service: "foo-service",
Rule: "Host(`foo.bar`)",
Priority: 0,
TLS: &dynamic.RouterTLSConfig{},
},
},
serviceConfig: map[string]*dynamic.Service{
"foo-service@provider-1": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: server.URL,
},
},
},
},
},
entryPoint: "websecure",
insecureSNI: true,
expected: expectedResult{StatusCode: http.StatusOK},
},
{
desc: "Secure SNI with TLS with sni uppercase",
routersConfig: map[string]*dynamic.Router{
"foo@provider-1": {
EntryPoints: []string{"websecure"},
Service: "foo-service",
Rule: "Host(`Foo.bar`)",
Priority: 0,
TLS: &dynamic.RouterTLSConfig{},
},
},
serviceConfig: map[string]*dynamic.Service{
"foo-service@provider-1": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: server.URL,
},
},
},
},
},
entryPoint: "websecure",
sni: "Foo.bar",
expected: expectedResult{StatusCode: http.StatusOK},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
rtConf := runtime.NewConfig(dynamic.Configuration{
HTTP: &dynamic.HTTPConfiguration{
Services: test.serviceConfig,
Routers: test.routersConfig,
Middlewares: test.middlewaresConfig,
},
})
rules.EnableDomainFronting(test.insecureSNI)
serviceManager := service.NewManager(rtConf.Services, http.DefaultTransport, nil, nil)
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager)
responseModifierFactory := responsemodifiers.NewBuilder(rtConf.Middlewares)
chainBuilder := middleware.NewChainBuilder(static.Configuration{}, nil, nil)
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory, chainBuilder)
handlers := routerManager.BuildHandlers(context.Background(), []string{test.entryPoint}, test.entryPoint == "websecure")
w := httptest.NewRecorder()
req := testhelpers.MustNewRequest(http.MethodGet, "https://foo.bar/", nil)
if test.entryPoint == "websecure" {
req.TLS = &tls.ConnectionState{}
if test.sni != "" {
req.TLS.ServerName = test.sni
}
}
reqHost := requestdecorator.New(nil)
reqHost.ServeHTTP(w, req, handlers[test.entryPoint].ServeHTTP)
assert.Equal(t, test.expected.StatusCode, w.Code)
for key, value := range test.expected.RequestHeaders {
assert.Equal(t, value, req.Header.Get(key))
}
})
}
}
func TestAccessLog(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
t.Cleanup(func() { server.Close() })
testCases := []struct {
desc string
routersConfig map[string]*dynamic.Router
@ -683,7 +908,6 @@ func TestRuntimeConfiguration(t *testing.T) {
chainBuilder := middleware.NewChainBuilder(static.Configuration{}, nil, nil)
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory, chainBuilder)
_ = routerManager.BuildHandlers(context.Background(), entryPoints, false)
// even though rtConf was passed by argument to the manager builders above,
@ -778,13 +1002,15 @@ type staticTransport struct {
res *http.Response
}
func (t *staticTransport) RoundTrip(r *http.Request) (*http.Response, error) {
func (t *staticTransport) RoundTrip(_ *http.Request) (*http.Response, error) {
return t.res, nil
}
func BenchmarkRouterServe(b *testing.B) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
b.Cleanup(func() { server.Close() })
res := &http.Response{
StatusCode: 200,
Body: ioutil.NopCloser(strings.NewReader("")),

View file

@ -90,7 +90,7 @@ type nameAndConfig struct {
TLSConfig *tls.Config
}
func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string]*runtime.TCPRouterInfo, configsHTTP map[string]*runtime.RouterInfo, handlerHTTP http.Handler, handlerHTTPS http.Handler) (*tcp.Router, error) {
func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string]*runtime.TCPRouterInfo, configsHTTP map[string]*runtime.RouterInfo, handlerHTTP, handlerHTTPS http.Handler) (*tcp.Router, error) {
router := &tcp.Router{}
router.HTTPHandler(handlerHTTP)

View file

@ -379,7 +379,6 @@ func buildProxyProtocolListener(ctx context.Context, entryPoint *static.EntryPoi
func buildListener(ctx context.Context, entryPoint *static.EntryPoint) (net.Listener, error) {
listener, err := net.Listen("tcp", entryPoint.GetAddress())
if err != nil {
return nil, fmt.Errorf("error opening listener: %w", err)
}

View file

@ -8,6 +8,7 @@ import (
"strings"
"github.com/containous/traefik/v2/pkg/config/runtime"
"github.com/containous/traefik/v2/pkg/log"
)
type serviceManager interface {
@ -26,7 +27,7 @@ type InternalHandlers struct {
}
// NewInternalHandlers creates a new InternalHandlers.
func NewInternalHandlers(api func(configuration *runtime.Configuration) http.Handler, configuration *runtime.Configuration, rest http.Handler, metricsHandler http.Handler, pingHandler http.Handler, dashboard http.Handler, next serviceManager) *InternalHandlers {
func NewInternalHandlers(api func(configuration *runtime.Configuration) http.Handler, configuration *runtime.Configuration, rest, metricsHandler, pingHandler, dashboard http.Handler, next serviceManager) *InternalHandlers {
var apiHandler http.Handler
if api != nil {
apiHandler = api(configuration)
@ -42,13 +43,87 @@ func NewInternalHandlers(api func(configuration *runtime.Configuration) http.Han
}
}
// BuildHTTP builds an HTTP handler.
func (m *InternalHandlers) BuildHTTP(rootCtx context.Context, serviceName string, responseModifier func(*http.Response) error) (http.Handler, error) {
if strings.HasSuffix(serviceName, "@internal") {
return m.get(serviceName)
type responseModifier struct {
r *http.Request
w http.ResponseWriter
headersSent bool // whether headers have already been sent
code int // status code, must default to 200
modifier func(*http.Response) error // can be nil
modified bool // whether modifier has already been called for the current request
modifierErr error // returned by modifier call
}
// modifier can be nil.
func newResponseModifier(w http.ResponseWriter, r *http.Request, modifier func(*http.Response) error) *responseModifier {
return &responseModifier{
r: r,
w: w,
modifier: modifier,
code: http.StatusOK,
}
}
func (w *responseModifier) WriteHeader(code int) {
if w.headersSent {
return
}
defer func() {
w.code = code
w.headersSent = true
}()
if w.modifier == nil || w.modified {
w.w.WriteHeader(code)
return
}
return m.serviceManager.BuildHTTP(rootCtx, serviceName, responseModifier)
resp := http.Response{
Header: w.w.Header(),
Request: w.r,
}
if err := w.modifier(&resp); err != nil {
w.modifierErr = err
// we are propagating when we are called in Write, but we're logging anyway,
// because we could be called from another place which does not take care of
// checking w.modifierErr.
log.Errorf("Error when applying response modifier: %v", err)
w.w.WriteHeader(http.StatusInternalServerError)
return
}
w.modified = true
w.w.WriteHeader(code)
}
func (w *responseModifier) Header() http.Header {
return w.w.Header()
}
func (w *responseModifier) Write(b []byte) (int, error) {
w.WriteHeader(w.code)
if w.modifierErr != nil {
return 0, w.modifierErr
}
return w.w.Write(b)
}
// BuildHTTP builds an HTTP handler.
func (m *InternalHandlers) BuildHTTP(rootCtx context.Context, serviceName string, respModifier func(*http.Response) error) (http.Handler, error) {
if !strings.HasSuffix(serviceName, "@internal") {
return m.serviceManager.BuildHTTP(rootCtx, serviceName, respModifier)
}
internalHandler, err := m.get(serviceName)
if err != nil {
return nil, err
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
internalHandler.ServeHTTP(newResponseModifier(w, r, respModifier), r)
}), nil
}
func (m *InternalHandlers) get(serviceName string) (http.Handler, error) {

View file

@ -63,7 +63,7 @@ func TestWebSocketPingPong(t *testing.T) {
require.NoError(t, err)
var upgrader = gorillawebsocket.Upgrader{
upgrader := gorillawebsocket.Upgrader{
HandshakeTimeout: 10 * time.Second,
CheckOrigin: func(*http.Request) bool {
return true
@ -670,7 +670,7 @@ func (w *websocketRequest) send() (string, error) {
if _, err := conn.Write([]byte(w.Data)); err != nil {
return "", err
}
var msg = make([]byte, 512)
msg := make([]byte, 512)
var n int
n, err = conn.Read(msg)
if err != nil {

View file

@ -102,7 +102,7 @@ func (r *Router) AddRouteTLS(sniHost string, target Handler, config *tls.Config)
})
}
// AddRouteHTTPTLS defines a handler for a given sniHost and sets the matching tlsConfig.
// AddRouteHTTPTLS defines the matching tlsConfig for a given sniHost.
func (r *Router) AddRouteHTTPTLS(sniHost string, config *tls.Config) {
if r.hostHTTPTLSConfig == nil {
r.hostHTTPTLSConfig = map[string]*tls.Config{}

View file

@ -118,7 +118,7 @@ func (c CertificateStore) ResetCache() {
}
// MatchDomain return true if a domain match the cert domain.
func MatchDomain(domain string, certDomain string) bool {
func MatchDomain(domain, certDomain string) bool {
if domain == certDomain {
return true
}

View file

@ -81,7 +81,7 @@ func (m *Manager) UpdateConfigs(ctx context.Context, stores map[string]Store, co
}
// Get gets the TLS configuration to use for a given store / configuration.
func (m *Manager) Get(storeName string, configName string) (*tls.Config, error) {
func (m *Manager) Get(storeName, configName string) (*tls.Config, error) {
m.lock.RLock()
defer m.lock.RUnlock()

View file

@ -80,12 +80,12 @@ func (t *Tracing) StartSpanf(r *http.Request, spanKind ext.SpanKindEnum, opPrefi
}
// Inject delegates to opentracing.Tracer.
func (t *Tracing) Inject(sm opentracing.SpanContext, format interface{}, carrier interface{}) error {
func (t *Tracing) Inject(sm opentracing.SpanContext, format, carrier interface{}) error {
return t.tracer.Inject(sm, format, carrier)
}
// Extract delegates to opentracing.Tracer.
func (t *Tracing) Extract(format interface{}, carrier interface{}) (opentracing.SpanContext, error) {
func (t *Tracing) Extract(format, carrier interface{}) (opentracing.SpanContext, error) {
return t.tracer.Extract(format, carrier)
}

View file

@ -30,7 +30,7 @@ func (d *Domain) Set(domains []string) {
}
// MatchDomain returns true if a domain match the cert domain.
func MatchDomain(domain string, certDomain string) bool {
func MatchDomain(domain, certDomain string) bool {
if domain == certDomain {
return true
}

View file

@ -113,7 +113,7 @@ func checkFieldValue(value string, defaultKeep bool) bool {
}
}
func checkFieldHeaderValue(value string, defaultValue string) string {
func checkFieldHeaderValue(value, defaultValue string) string {
if value == AccessLogKeep || value == AccessLogDrop || value == AccessLogRedact {
return value
}

View file

@ -24,11 +24,9 @@ var (
// Handler expose version routes.
type Handler struct{}
var (
templatesRenderer = render.New(render.Options{
Directory: "nowhere",
})
)
var templatesRenderer = render.New(render.Options{
Directory: "nowhere",
})
// Append adds version routes on a router.
func (v Handler) Append(router *mux.Router) {