1 Star 0 Fork 0

东海苍月/traefik

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
kv_config.go 17.18 KB
一键复制 编辑 原始数据 按行查看 历史
Ludovic Fernandez 提交于 2018-04-11 16:30 . Server weight zero
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
package kv
import (
"fmt"
"math"
"net/http"
"sort"
"strconv"
"strings"
"text/template"
"github.com/BurntSushi/ty/fun"
"github.com/abronan/valkeyrie/store"
"github.com/containous/flaeg"
"github.com/containous/traefik/log"
"github.com/containous/traefik/provider/label"
"github.com/containous/traefik/tls"
"github.com/containous/traefik/types"
)
func (p *Provider) buildConfiguration() *types.Configuration {
templateObjects := struct {
Prefix string
}{
// Allow `/traefik/alias` to supersede `p.Prefix`
Prefix: strings.TrimSuffix(p.get(p.Prefix, p.Prefix+pathAlias), pathSeparator),
}
var KvFuncMap = template.FuncMap{
"List": p.list,
"ListServers": p.listServers,
"Get": p.get,
"GetBool": p.getBool,
"GetInt": p.getInt,
"GetInt64": p.getInt64,
"GetList": p.getList,
"SplitGet": p.splitGet,
"Last": p.last,
"Has": p.has,
"getTLSSection": p.getTLSSection,
// Frontend functions
"getBackendName": p.getFuncString(pathFrontendBackend, ""),
"getPriority": p.getFuncInt(pathFrontendPriority, label.DefaultFrontendPriority),
"getPassHostHeader": p.getPassHostHeader(),
"getPassTLSCert": p.getFuncBool(pathFrontendPassTLSCert, label.DefaultPassTLSCert),
"getEntryPoints": p.getFuncList(pathFrontendEntryPoints),
"getBasicAuth": p.getFuncList(pathFrontendBasicAuth),
"getRoutes": p.getRoutes,
"getRedirect": p.getRedirect,
"getErrorPages": p.getErrorPages,
"getRateLimit": p.getRateLimit,
"getHeaders": p.getHeaders,
"getWhiteList": p.getWhiteList,
// Backend functions
"getServers": p.getServers,
"getCircuitBreaker": p.getCircuitBreaker,
"getLoadBalancer": p.getLoadBalancer,
"getMaxConn": p.getMaxConn,
"getHealthCheck": p.getHealthCheck,
"getBuffering": p.getBuffering,
"getSticky": p.getSticky, // Deprecated [breaking]
"hasStickinessLabel": p.hasStickinessLabel, // Deprecated [breaking]
"getStickinessCookieName": p.getStickinessCookieName, // Deprecated [breaking]
}
configuration, err := p.GetConfiguration("templates/kv.tmpl", KvFuncMap, templateObjects)
if err != nil {
log.Error(err)
}
for key, frontend := range configuration.Frontends {
if _, ok := configuration.Backends[frontend.Backend]; !ok {
delete(configuration.Frontends, key)
}
}
return configuration
}
// Deprecated
func (p *Provider) getPassHostHeader() func(rootPath string) bool {
return func(rootPath string) bool {
rawValue := p.get("", rootPath, pathFrontendPassHostHeader)
if len(rawValue) > 0 {
value, err := strconv.ParseBool(rawValue)
if err != nil {
log.Errorf("Invalid value for %s %s: %s", rootPath, pathFrontendPassHostHeader, rawValue)
return label.DefaultPassHostHeader
}
return value
}
return p.getBool(label.DefaultPassHostHeader, rootPath, pathFrontendPassHostHeaderDeprecated)
}
}
// Deprecated
func (p *Provider) getSticky(rootPath string) bool {
stickyValue := p.get("", rootPath, pathBackendLoadBalancerSticky)
if len(stickyValue) > 0 {
log.Warnf("Deprecated configuration found: %s. Please use %s.", pathBackendLoadBalancerSticky, pathBackendLoadBalancerStickiness)
} else {
return false
}
sticky, err := strconv.ParseBool(stickyValue)
if err != nil {
log.Warnf("Invalid %s value: %s.", pathBackendLoadBalancerSticky, stickyValue)
}
return sticky
}
// Deprecated
func (p *Provider) hasStickinessLabel(rootPath string) bool {
return p.getBool(false, rootPath, pathBackendLoadBalancerStickiness)
}
// Deprecated
func (p *Provider) getStickinessCookieName(rootPath string) string {
return p.get("", rootPath, pathBackendLoadBalancerStickinessCookieName)
}
func (p *Provider) getWhiteList(rootPath string) *types.WhiteList {
ranges := p.getList(rootPath, pathFrontendWhiteListSourceRange)
if len(ranges) > 0 {
return &types.WhiteList{
SourceRange: ranges,
UseXForwardedFor: p.getBool(false, rootPath, pathFrontendWhiteListUseXForwardedFor),
}
}
return nil
}
func (p *Provider) getRedirect(rootPath string) *types.Redirect {
permanent := p.getBool(false, rootPath, pathFrontendRedirectPermanent)
if p.has(rootPath, pathFrontendRedirectEntryPoint) {
return &types.Redirect{
EntryPoint: p.get("", rootPath, pathFrontendRedirectEntryPoint),
Permanent: permanent,
}
}
if p.has(rootPath, pathFrontendRedirectRegex) && p.has(rootPath, pathFrontendRedirectReplacement) {
return &types.Redirect{
Regex: p.get("", rootPath, pathFrontendRedirectRegex),
Replacement: p.get("", rootPath, pathFrontendRedirectReplacement),
Permanent: permanent,
}
}
return nil
}
func (p *Provider) getErrorPages(rootPath string) map[string]*types.ErrorPage {
var errorPages map[string]*types.ErrorPage
pathErrors := p.list(rootPath, pathFrontendErrorPages)
for _, pathPage := range pathErrors {
if errorPages == nil {
errorPages = make(map[string]*types.ErrorPage)
}
pageName := p.last(pathPage)
errorPages[pageName] = &types.ErrorPage{
Backend: p.get("", pathPage, pathFrontendErrorPagesBackend),
Query: p.get("", pathPage, pathFrontendErrorPagesQuery),
Status: p.getList(pathPage, pathFrontendErrorPagesStatus),
}
}
return errorPages
}
func (p *Provider) getRateLimit(rootPath string) *types.RateLimit {
extractorFunc := p.get("", rootPath, pathFrontendRateLimitExtractorFunc)
if len(extractorFunc) == 0 {
return nil
}
var limits map[string]*types.Rate
pathRateSet := p.list(rootPath, pathFrontendRateLimitRateSet)
for _, pathLimits := range pathRateSet {
if limits == nil {
limits = make(map[string]*types.Rate)
}
rawPeriod := p.get("", pathLimits+pathFrontendRateLimitPeriod)
var period flaeg.Duration
err := period.Set(rawPeriod)
if err != nil {
log.Errorf("Invalid %q value: %q", pathLimits+pathFrontendRateLimitPeriod, rawPeriod)
continue
}
limitName := p.last(pathLimits)
limits[limitName] = &types.Rate{
Average: p.getInt64(0, pathLimits+pathFrontendRateLimitAverage),
Burst: p.getInt64(0, pathLimits+pathFrontendRateLimitBurst),
Period: period,
}
}
return &types.RateLimit{
ExtractorFunc: extractorFunc,
RateSet: limits,
}
}
func (p *Provider) getHeaders(rootPath string) *types.Headers {
headers := &types.Headers{
CustomRequestHeaders: p.getMap(rootPath, pathFrontendCustomRequestHeaders),
CustomResponseHeaders: p.getMap(rootPath, pathFrontendCustomResponseHeaders),
SSLProxyHeaders: p.getMap(rootPath, pathFrontendSSLProxyHeaders),
AllowedHosts: p.getList("", rootPath, pathFrontendAllowedHosts),
HostsProxyHeaders: p.getList(rootPath, pathFrontendHostsProxyHeaders),
SSLRedirect: p.getBool(false, rootPath, pathFrontendSSLRedirect),
SSLTemporaryRedirect: p.getBool(false, rootPath, pathFrontendSSLTemporaryRedirect),
SSLHost: p.get("", rootPath, pathFrontendSSLHost),
STSSeconds: p.getInt64(0, rootPath, pathFrontendSTSSeconds),
STSIncludeSubdomains: p.getBool(false, rootPath, pathFrontendSTSIncludeSubdomains),
STSPreload: p.getBool(false, rootPath, pathFrontendSTSPreload),
ForceSTSHeader: p.getBool(false, rootPath, pathFrontendForceSTSHeader),
FrameDeny: p.getBool(false, rootPath, pathFrontendFrameDeny),
CustomFrameOptionsValue: p.get("", rootPath, pathFrontendCustomFrameOptionsValue),
ContentTypeNosniff: p.getBool(false, rootPath, pathFrontendContentTypeNosniff),
BrowserXSSFilter: p.getBool(false, rootPath, pathFrontendBrowserXSSFilter),
CustomBrowserXSSValue: p.get("", rootPath, pathFrontendCustomBrowserXSSValue),
ContentSecurityPolicy: p.get("", rootPath, pathFrontendContentSecurityPolicy),
PublicKey: p.get("", rootPath, pathFrontendPublicKey),
ReferrerPolicy: p.get("", rootPath, pathFrontendReferrerPolicy),
IsDevelopment: p.getBool(false, rootPath, pathFrontendIsDevelopment),
}
if !headers.HasSecureHeadersDefined() && !headers.HasCustomHeadersDefined() {
return nil
}
return headers
}
func (p *Provider) getLoadBalancer(rootPath string) *types.LoadBalancer {
lb := &types.LoadBalancer{
Method: p.get(label.DefaultBackendLoadBalancerMethod, rootPath, pathBackendLoadBalancerMethod),
Sticky: p.getSticky(rootPath),
}
if p.getBool(false, rootPath, pathBackendLoadBalancerStickiness) {
lb.Stickiness = &types.Stickiness{
CookieName: p.get("", rootPath, pathBackendLoadBalancerStickinessCookieName),
}
}
return lb
}
func (p *Provider) getCircuitBreaker(rootPath string) *types.CircuitBreaker {
if !p.has(rootPath, pathBackendCircuitBreakerExpression) {
return nil
}
circuitBreaker := p.get(label.DefaultCircuitBreakerExpression, rootPath, pathBackendCircuitBreakerExpression)
if len(circuitBreaker) == 0 {
return nil
}
return &types.CircuitBreaker{Expression: circuitBreaker}
}
func (p *Provider) getMaxConn(rootPath string) *types.MaxConn {
amount := p.getInt64(math.MinInt64, rootPath, pathBackendMaxConnAmount)
extractorFunc := p.get(label.DefaultBackendMaxconnExtractorFunc, rootPath, pathBackendMaxConnExtractorFunc)
if amount == math.MinInt64 || len(extractorFunc) == 0 {
return nil
}
return &types.MaxConn{
Amount: amount,
ExtractorFunc: extractorFunc,
}
}
func (p *Provider) getHealthCheck(rootPath string) *types.HealthCheck {
path := p.get("", rootPath, pathBackendHealthCheckPath)
if len(path) == 0 {
return nil
}
port := p.getInt(label.DefaultBackendHealthCheckPort, rootPath, pathBackendHealthCheckPort)
interval := p.get("30s", rootPath, pathBackendHealthCheckInterval)
return &types.HealthCheck{
Path: path,
Port: port,
Interval: interval,
}
}
func (p *Provider) getBuffering(rootPath string) *types.Buffering {
pathsBuffering := p.list(rootPath, pathBackendBuffering)
var buffering *types.Buffering
if len(pathsBuffering) > 0 {
if buffering == nil {
buffering = &types.Buffering{}
}
buffering.MaxRequestBodyBytes = p.getInt64(0, rootPath, pathBackendBufferingMaxRequestBodyBytes)
buffering.MaxResponseBodyBytes = p.getInt64(0, rootPath, pathBackendBufferingMaxResponseBodyBytes)
buffering.MemRequestBodyBytes = p.getInt64(0, rootPath, pathBackendBufferingMemRequestBodyBytes)
buffering.MemResponseBodyBytes = p.getInt64(0, rootPath, pathBackendBufferingMemResponseBodyBytes)
buffering.RetryExpression = p.get("", rootPath, pathBackendBufferingRetryExpression)
}
return buffering
}
func (p *Provider) getTLSSection(prefix string) []*tls.Configuration {
var tlsSection []*tls.Configuration
for _, tlsConfPath := range p.list(prefix, pathTLS) {
certFile := p.get("", tlsConfPath, pathTLSCertFile)
keyFile := p.get("", tlsConfPath, pathTLSKeyFile)
if len(certFile) == 0 && len(keyFile) == 0 {
log.Warnf("Invalid TLS configuration (no cert and no key): %s", tlsConfPath)
continue
}
entryPoints := p.getList(tlsConfPath, pathTLSEntryPoints)
if len(entryPoints) == 0 {
log.Warnf("Invalid TLS configuration (no entry points): %s", tlsConfPath)
continue
}
tlsConf := &tls.Configuration{
EntryPoints: entryPoints,
Certificate: &tls.Certificate{
CertFile: tls.FileOrContent(certFile),
KeyFile: tls.FileOrContent(keyFile),
},
}
tlsSection = append(tlsSection, tlsConf)
}
return tlsSection
}
func (p *Provider) getRoutes(rootPath string) map[string]types.Route {
var routes map[string]types.Route
rts := p.list(rootPath, pathFrontendRoutes)
for _, rt := range rts {
rule := p.get("", rt, pathFrontendRule)
if len(rule) == 0 {
continue
}
if routes == nil {
routes = make(map[string]types.Route)
}
routeName := p.last(rt)
routes[routeName] = types.Route{
Rule: rule,
}
}
return routes
}
func (p *Provider) getServers(rootPath string) map[string]types.Server {
var servers map[string]types.Server
serverKeys := p.listServers(rootPath)
for _, serverKey := range serverKeys {
serverURL := p.get("", serverKey, pathBackendServerURL)
if len(serverURL) == 0 {
continue
}
if servers == nil {
servers = make(map[string]types.Server)
}
serverName := p.last(serverKey)
servers[serverName] = types.Server{
URL: serverURL,
Weight: p.getInt(label.DefaultWeight, serverKey, pathBackendServerWeight),
}
}
return servers
}
func (p *Provider) listServers(backend string) []string {
serverNames := p.list(backend, pathBackendServers)
return fun.Filter(p.serverFilter, serverNames).([]string)
}
func (p *Provider) serverFilter(serverName string) bool {
key := fmt.Sprint(serverName, pathBackendServerURL)
if _, err := p.kvClient.Get(key, nil); err != nil {
if err != store.ErrKeyNotFound {
log.Errorf("Failed to retrieve value for key %s: %s", key, err)
}
return false
}
return p.checkConstraints(serverName, pathTags)
}
func (p *Provider) checkConstraints(keys ...string) bool {
joinedKeys := strings.Join(keys, "")
keyPair, err := p.kvClient.Get(joinedKeys, nil)
value := ""
if err == nil && keyPair != nil && keyPair.Value != nil {
value = string(keyPair.Value)
}
constraintTags := label.SplitAndTrimString(value, ",")
ok, failingConstraint := p.MatchConstraints(constraintTags)
if !ok {
if failingConstraint != nil {
log.Debugf("Constraint %v not matching with following tags: %v", failingConstraint.String(), value)
}
return false
}
return true
}
func (p *Provider) getFuncString(key string, defaultValue string) func(rootPath string) string {
return func(rootPath string) string {
return p.get(defaultValue, rootPath, key)
}
}
func (p *Provider) getFuncBool(key string, defaultValue bool) func(rootPath string) bool {
return func(rootPath string) bool {
return p.getBool(defaultValue, rootPath, key)
}
}
func (p *Provider) getFuncInt(key string, defaultValue int) func(rootPath string) int {
return func(rootPath string) int {
return p.getInt(defaultValue, rootPath, key)
}
}
func (p *Provider) getFuncList(key string) func(rootPath string) []string {
return func(rootPath string) []string {
return p.getList(rootPath, key)
}
}
func (p *Provider) get(defaultValue string, keyParts ...string) string {
key := strings.Join(keyParts, "")
if p.storeType == store.ETCD {
key = strings.TrimPrefix(key, pathSeparator)
}
keyPair, err := p.kvClient.Get(key, nil)
if err != nil {
log.Debugf("Cannot get key %s %s, setting default %s", key, err, defaultValue)
return defaultValue
} else if keyPair == nil {
log.Debugf("Cannot get key %s, setting default %s", key, defaultValue)
return defaultValue
}
return string(keyPair.Value)
}
func (p *Provider) getBool(defaultValue bool, keyParts ...string) bool {
rawValue := p.get(strconv.FormatBool(defaultValue), keyParts...)
if len(rawValue) == 0 {
return defaultValue
}
value, err := strconv.ParseBool(rawValue)
if err != nil {
log.Errorf("Invalid value for %v: %s", keyParts, rawValue)
return defaultValue
}
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, "")
keysPairs, err := p.kvClient.List(rootKey, nil)
if err != nil {
log.Debugf("Cannot list keys under %q: %v", rootKey, err)
return nil
}
directoryKeys := make(map[string]string)
for _, key := range keysPairs {
directory := strings.Split(strings.TrimPrefix(key.Key, rootKey), pathSeparator)[0]
directoryKeys[directory] = rootKey + directory
}
keys := fun.Values(directoryKeys).([]string)
sort.Strings(keys)
return keys
}
func (p *Provider) getList(keyParts ...string) []string {
values := p.splitGet(keyParts...)
if len(values) > 0 {
return values
}
return p.getSlice(keyParts...)
}
// get sub keys. ex: foo/0, foo/1, foo/2
func (p *Provider) getSlice(keyParts ...string) []string {
baseKey := strings.Join(keyParts, "")
if !strings.HasSuffix(baseKey, "/") {
baseKey += "/"
}
listKeys := p.list(baseKey)
var values []string
for _, entryKey := range listKeys {
val := p.get("", entryKey)
if len(val) > 0 {
values = append(values, val)
}
}
return values
}
func (p *Provider) splitGet(keyParts ...string) []string {
value := p.get("", keyParts...)
if len(value) == 0 {
return nil
}
return label.SplitAndTrimString(value, ",")
}
func (p *Provider) last(key string) string {
index := strings.LastIndex(key, pathSeparator)
return key[index+1:]
}
func (p *Provider) getMap(keyParts ...string) map[string]string {
var mapData map[string]string
list := p.list(keyParts...)
for _, name := range list {
if mapData == nil {
mapData = make(map[string]string)
}
mapData[http.CanonicalHeaderKey(p.last(name))] = p.get("", name)
}
return mapData
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/dhcy/traefik.git
git@gitee.com:dhcy/traefik.git
dhcy
traefik
traefik
v1.6.2

搜索帮助

0d507c66 1850385 C8b1a773 1850385