feat(kv): constants and generic methods.

This commit is contained in:
Fernandez Ludovic 2018-01-03 15:57:36 +01:00 committed by Traefiker
parent 61ecb4cd18
commit 6573634012
3 changed files with 228 additions and 10 deletions

View file

@ -4,19 +4,68 @@ const (
pathBackends = "/backends/"
pathBackendCircuitBreakerExpression = "/circuitbreaker/expression"
pathBackendHealthCheckPath = "/healthcheck/path"
pathBackendHealthCheckPort = "/healthcheck/port"
pathBackendHealthCheckInterval = "/healthcheck/interval"
pathBackendLoadBalancerMethod = "/loadbalancer/method"
pathBackendLoadBalancerSticky = "/loadbalancer/sticky"
pathBackendLoadBalancerStickiness = "/loadbalancer/stickiness"
pathBackendLoadBalancerStickinessCookieName = "/loadbalancer/stickiness/cookiename"
pathBackendMaxConnAmount = "/maxconn/amount"
pathBackendMaxConnExtractorFunc = "/maxconn/extractorfunc"
pathBackendServers = "/servers/"
pathBackendServerURL = "/url"
pathBackendServerWeight = "/weight"
pathFrontends = "/frontends/"
pathFrontendBackend = "/backend"
pathFrontendPriority = "/priority"
pathFrontendPassHostHeader = "/passHostHeader"
pathFrontendEntryPoints = "/entrypoints"
pathFrontends = "/frontends/"
pathFrontendBackend = "/backend"
pathFrontendPriority = "/priority"
pathFrontendPassHostHeader = "/passHostHeader"
pathFrontendPassTLSCert = "/passtlscert"
pathFrontendWhiteListSourceRange = "/whitelistsourcerange"
pathFrontendBasicAuth = "/basicauth"
pathFrontendEntryPoints = "/entrypoints"
pathFrontendRedirectEntryPoint = "/redirect/entrypoint"
pathFrontendRedirectRegex = "/redirect/regex"
pathFrontendRedirectReplacement = "/redirect/replacement"
pathFrontendErrorPages = "/errors/"
pathFrontendErrorPagesBackend = "/backend"
pathFrontendErrorPagesQuery = "/query"
pathFrontendErrorPagesStatus = "/status"
pathFrontendRateLimit = "/ratelimit/"
pathFrontendRateLimitRateSet = pathFrontendRateLimit + "rateset/"
pathFrontendRateLimitExtractorFunc = pathFrontendRateLimit + "extractorfunc"
pathFrontendRateLimitPeriod = "/period"
pathFrontendRateLimitAverage = "/average"
pathFrontendRateLimitBurst = "/burst"
pathFrontendCustomRequestHeaders = "/headers/customrequestheaders/"
pathFrontendCustomResponseHeaders = "/headers/customresponseheaders/"
pathFrontendAllowedHosts = "/headers/allowedhosts"
pathFrontendHostsProxyHeaders = "/headers/hostsproxyheaders"
pathFrontendSSLRedirect = "/headers/sslredirect"
pathFrontendSSLTemporaryRedirect = "/headers/ssltemporaryredirect"
pathFrontendSSLHost = "/headers/sslhost"
pathFrontendSSLProxyHeaders = "/headers/sslproxyheaders/"
pathFrontendSTSSeconds = "/headers/stsseconds"
pathFrontendSTSIncludeSubdomains = "/headers/stsincludesubdomains"
pathFrontendSTSPreload = "/headers/stspreload"
pathFrontendForceSTSHeader = "/headers/forcestsheader"
pathFrontendFrameDeny = "/headers/framedeny"
pathFrontendCustomFrameOptionsValue = "/headers/customframeoptionsvalue"
pathFrontendContentTypeNosniff = "/headers/contenttypenosniff"
pathFrontendBrowserXSSFilter = "/headers/browserxssfilter"
pathFrontendContentSecurityPolicy = "/headers/contentsecuritypolicy"
pathFrontendPublicKey = "/headers/publickey"
pathFrontendReferrerPolicy = "/headers/referrerpolicy"
pathFrontendIsDevelopment = "/headers/isdevelopment"
pathFrontendRoutes = "/routes/"
pathFrontendRule = "/rule"
pathTLSConfiguration = "/tlsconfiguration/"
pathTLSConfigurationEntryPoints = "/entrypoints"
pathTLSConfigurationCertFile = "/certificate/certfile"
pathTLSConfigurationKeyFile = "/certificate/keyfile"
pathTags = "/tags"
pathAlias = "/alias"

View file

@ -26,8 +26,12 @@ func (p *Provider) buildConfiguration() *types.Configuration {
"List": p.list,
"ListServers": p.listServers,
"Get": p.get,
"GetBool": p.getBool,
"GetInt": p.getInt,
"GetInt64": p.getInt64,
"SplitGet": p.splitGet,
"Last": p.last,
"Has": p.has,
// Backend functions
"getSticky": p.getSticky,
@ -143,6 +147,41 @@ func (p *Provider) getBool(defaultValue bool, keyParts ...string) bool {
return value
}
func (p *Provider) has(keyParts ...string) bool {
value := p.get("", keyParts...)
return len(value) > 0
}
func (p *Provider) getInt(defaultValue int, keyParts ...string) int {
rawValue := p.get("", keyParts...)
if len(rawValue) == 0 {
return defaultValue
}
value, err := strconv.Atoi(rawValue)
if err != nil {
log.Errorf("Invalid value for %v: %s", keyParts, rawValue)
return defaultValue
}
return value
}
func (p *Provider) getInt64(defaultValue int64, keyParts ...string) int64 {
rawValue := p.get("", keyParts...)
if len(rawValue) == 0 {
return defaultValue
}
value, err := strconv.ParseInt(rawValue, 10, 64)
if err != nil {
log.Errorf("Invalid value for %v: %s", keyParts, rawValue)
return defaultValue
}
return value
}
func (p *Provider) list(keyParts ...string) []string {
rootKey := strings.Join(keyParts, "")

View file

@ -62,16 +62,16 @@ func TestProviderBuildConfiguration(t *testing.T) {
desc: "all parameters",
kvPairs: filler("traefik",
backend("backend1",
withPair("healthcheck/path", "/health"),
withPair("healthcheck/port", "80"),
withPair("healthcheck/interval", "30s"),
withPair("maxconn/amount", "5"),
withPair("maxconn/extractorfunc", "client.ip"),
withPair(pathBackendCircuitBreakerExpression, label.DefaultCircuitBreakerExpression),
withPair(pathBackendLoadBalancerMethod, "drr"),
withPair(pathBackendLoadBalancerSticky, "true"),
withPair(pathBackendLoadBalancerStickiness, "true"),
withPair(pathBackendLoadBalancerStickinessCookieName, "tomate"),
withPair(pathBackendHealthCheckPath, "/health"),
withPair(pathBackendHealthCheckPort, "80"),
withPair(pathBackendHealthCheckInterval, "30s"),
withPair(pathBackendMaxConnAmount, "5"),
withPair(pathBackendMaxConnExtractorFunc, "client.ip"),
withPair("servers/server1/url", "http://172.17.0.2:80"),
withPair("servers/server1/weight", "0"),
withPair("servers/server2/weight", "0")),
@ -525,6 +525,136 @@ func TestProviderGetBool(t *testing.T) {
}
}
func TestProviderGetInt(t *testing.T) {
defaultValue := 666
testCases := []struct {
desc string
kvPairs []*store.KVPair
kvError error
keyParts []string
expected int
}{
{
desc: "when has value",
kvPairs: filler("traefik",
frontend("foo",
withPair("bar", "6"),
),
),
keyParts: []string{"traefik/frontends/foo/bar"},
expected: 6,
},
{
desc: "when empty value",
kvPairs: filler("traefik",
frontend("foo",
withPair("bar", ""),
),
),
keyParts: []string{"traefik/frontends/foo/bar"},
expected: defaultValue,
},
{
desc: "when not existing key",
kvPairs: nil,
keyParts: []string{"traefik/frontends/foo/bar"},
expected: defaultValue,
},
{
desc: "when KV error",
kvError: store.ErrNotReachable,
kvPairs: filler("traefik",
frontend("foo",
withPair("bar", "true"),
),
),
keyParts: []string{"traefik/frontends/foo/bar"},
expected: defaultValue,
},
}
for i, test := range testCases {
test := test
t.Run(strconv.Itoa(i), func(t *testing.T) {
t.Parallel()
p := &Provider{
kvClient: newKvClientMock(test.kvPairs, test.kvError),
}
actual := p.getInt(defaultValue, test.keyParts...)
assert.Equal(t, test.expected, actual, "key: %v", test.keyParts)
})
}
}
func TestProviderGetInt64(t *testing.T) {
var defaultValue int64 = 666
testCases := []struct {
desc string
kvPairs []*store.KVPair
kvError error
keyParts []string
expected int64
}{
{
desc: "when has value",
kvPairs: filler("traefik",
frontend("foo",
withPair("bar", "6"),
),
),
keyParts: []string{"traefik/frontends/foo/bar"},
expected: 6,
},
{
desc: "when empty value",
kvPairs: filler("traefik",
frontend("foo",
withPair("bar", ""),
),
),
keyParts: []string{"traefik/frontends/foo/bar"},
expected: defaultValue,
},
{
desc: "when not existing key",
kvPairs: nil,
keyParts: []string{"traefik/frontends/foo/bar"},
expected: defaultValue,
},
{
desc: "when KV error",
kvError: store.ErrNotReachable,
kvPairs: filler("traefik",
frontend("foo",
withPair("bar", "true"),
),
),
keyParts: []string{"traefik/frontends/foo/bar"},
expected: defaultValue,
},
}
for i, test := range testCases {
test := test
t.Run(strconv.Itoa(i), func(t *testing.T) {
t.Parallel()
p := &Provider{
kvClient: newKvClientMock(test.kvPairs, test.kvError),
}
actual := p.getInt64(defaultValue, test.keyParts...)
assert.Equal(t, test.expected, actual, "key: %v", test.keyParts)
})
}
}
func TestProviderHasStickinessLabel(t *testing.T) {
testCases := []struct {
desc string