From 65736340120231d408a8bd1f61f2984de0c359ec Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Wed, 3 Jan 2018 15:57:36 +0100 Subject: [PATCH] feat(kv): constants and generic methods. --- provider/kv/keynames.go | 59 ++++++++++++-- provider/kv/kv_config.go | 39 ++++++++++ provider/kv/kv_config_test.go | 140 ++++++++++++++++++++++++++++++++-- 3 files changed, 228 insertions(+), 10 deletions(-) diff --git a/provider/kv/keynames.go b/provider/kv/keynames.go index f2217c986..662adf2e9 100644 --- a/provider/kv/keynames.go +++ b/provider/kv/keynames.go @@ -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" diff --git a/provider/kv/kv_config.go b/provider/kv/kv_config.go index 454808419..a228d47fd 100644 --- a/provider/kv/kv_config.go +++ b/provider/kv/kv_config.go @@ -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, "") diff --git a/provider/kv/kv_config_test.go b/provider/kv/kv_config_test.go index 416b929ae..f6f340081 100644 --- a/provider/kv/kv_config_test.go +++ b/provider/kv/kv_config_test.go @@ -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