traefik/provider/rancher/config.go

203 lines
6.6 KiB
Go
Raw Normal View History

package rancher
import (
2018-01-10 17:08:03 +00:00
"fmt"
"strconv"
"strings"
"text/template"
"github.com/BurntSushi/ty/fun"
"github.com/containous/traefik/log"
"github.com/containous/traefik/provider"
"github.com/containous/traefik/provider/label"
"github.com/containous/traefik/types"
)
2018-03-26 13:32:04 +00:00
func (p *Provider) buildConfigurationV2(services []rancherData) *types.Configuration {
var RancherFuncMap = template.FuncMap{
2018-03-26 13:32:04 +00:00
"getLabelValue": label.GetStringValue,
"getDomain": label.GetFuncString(label.TraefikDomain, p.Domain),
// Backend functions
2018-03-26 13:32:04 +00:00
"getCircuitBreaker": label.GetCircuitBreaker,
"getLoadBalancer": label.GetLoadBalancer,
"getMaxConn": label.GetMaxConn,
"getHealthCheck": label.GetHealthCheck,
"getBuffering": label.GetBuffering,
2018-01-10 17:08:03 +00:00
"getServers": getServers,
// Frontend functions
"getBackendName": getBackendName,
"getFrontendRule": p.getFrontendRule,
2018-04-11 14:30:04 +00:00
"getPriority": label.GetFuncInt(label.TraefikFrontendPriority, label.DefaultFrontendPriority),
"getPassHostHeader": label.GetFuncBool(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader),
2018-03-26 13:32:04 +00:00
"getPassTLSCert": label.GetFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert),
"getEntryPoints": label.GetFuncSliceString(label.TraefikFrontendEntryPoints),
"getBasicAuth": label.GetFuncSliceString(label.TraefikFrontendAuthBasic),
"getErrorPages": label.GetErrorPages,
"getRateLimit": label.GetRateLimit,
"getRedirect": label.GetRedirect,
"getHeaders": label.GetHeaders,
"getWhiteList": label.GetWhiteList,
}
// filter services
filteredServices := fun.Filter(p.serviceFilter, services).([]rancherData)
frontends := map[string]rancherData{}
backends := map[string]rancherData{}
for _, service := range filteredServices {
2018-03-26 13:32:04 +00:00
segmentProperties := label.ExtractTraefikLabels(service.Labels)
for segmentName, labels := range segmentProperties {
service.SegmentLabels = labels
service.SegmentName = segmentName
frontendName := p.getFrontendName(service)
frontends[frontendName] = service
backendName := getBackendName(service)
backends[backendName] = service
}
}
templateObjects := struct {
Frontends map[string]rancherData
Backends map[string]rancherData
Domain string
}{
2017-12-16 13:25:10 +00:00
Frontends: frontends,
Backends: backends,
Domain: p.Domain,
}
configuration, err := p.GetConfiguration("templates/rancher.tmpl", RancherFuncMap, templateObjects)
if err != nil {
log.Error(err)
}
return configuration
}
func (p *Provider) serviceFilter(service rancherData) bool {
2018-03-26 13:32:04 +00:00
segmentProperties := label.ExtractTraefikLabels(service.Labels)
for segmentName, labels := range segmentProperties {
_, err := checkSegmentPort(labels, segmentName)
if err != nil {
log.Debugf("Filtering service %s %s without traefik.port label", service.Name, segmentName)
return false
}
2018-03-28 15:18:04 +00:00
if len(p.getFrontendRule(service.Name, labels)) == 0 {
2018-03-26 13:32:04 +00:00
log.Debugf("Filtering container with empty frontend rule %s %s", service.Name, segmentName)
return false
}
}
if !label.IsEnabled(service.Labels, p.ExposedByDefault) {
log.Debugf("Filtering disabled service %s", service.Name)
return false
}
constraintTags := label.GetSliceStringValue(service.Labels, label.TraefikTags)
if ok, failingConstraint := p.MatchConstraints(constraintTags); !ok {
if failingConstraint != nil {
log.Debugf("Filtering service %s with constraint %s", service.Name, failingConstraint.String())
}
return false
}
// Only filter services by Health (HealthState) and State if EnableServiceHealthFilter is true
if p.EnableServiceHealthFilter {
if service.Health != "" && service.Health != healthy && service.Health != updatingHealthy {
log.Debugf("Filtering service %s with healthState of %s", service.Name, service.Health)
return false
}
2018-03-15 21:22:03 +00:00
if service.State != "" && service.State != active && service.State != updatingActive && service.State != upgraded && service.State != upgrading {
log.Debugf("Filtering service %s with state of %s", service.Name, service.State)
return false
}
}
return true
}
2018-03-28 15:18:04 +00:00
func (p *Provider) getFrontendRule(serviceName string, labels map[string]string) string {
domain := label.GetStringValue(labels, label.TraefikDomain, p.Domain)
defaultRule := "Host:" + strings.ToLower(strings.Replace(serviceName, "/", ".", -1)) + "." + domain
2018-03-28 15:18:04 +00:00
return label.GetStringValue(labels, label.TraefikFrontendRule, defaultRule)
}
func (p *Provider) getFrontendName(service rancherData) string {
2018-03-26 13:32:04 +00:00
var name string
if len(service.SegmentName) > 0 {
name = getBackendName(service)
} else {
2018-03-28 15:18:04 +00:00
name = p.getFrontendRule(service.Name, service.SegmentLabels)
}
2018-03-26 13:32:04 +00:00
return provider.Normalize(name)
}
2018-01-10 17:08:03 +00:00
func getBackendName(service rancherData) string {
2018-03-26 13:32:04 +00:00
if len(service.SegmentName) > 0 {
return getSegmentBackendName(service)
2018-01-10 17:08:03 +00:00
}
2018-03-26 13:32:04 +00:00
return getDefaultBackendName(service)
2018-01-10 17:08:03 +00:00
}
2018-03-26 13:32:04 +00:00
func getSegmentBackendName(service rancherData) string {
if value := label.GetStringValue(service.SegmentLabels, label.TraefikFrontendBackend, ""); len(value) > 0 {
return provider.Normalize(service.Name + "-" + value)
2018-01-10 17:08:03 +00:00
}
2018-03-26 13:32:04 +00:00
return provider.Normalize(service.Name + "-" + getDefaultBackendName(service) + "-" + service.SegmentName)
2018-01-10 17:08:03 +00:00
}
2018-03-26 13:32:04 +00:00
func getDefaultBackendName(service rancherData) string {
backend := label.GetStringValue(service.SegmentLabels, label.TraefikBackend, service.Name)
return provider.Normalize(backend)
2018-01-31 14:32:04 +00:00
}
2018-01-10 17:08:03 +00:00
func getServers(service rancherData) map[string]types.Server {
var servers map[string]types.Server
for index, ip := range service.Containers {
if len(ip) == 0 {
log.Warnf("Unable to find the IP address for a container in the service %q: this container is ignored.", service.Name)
continue
}
2018-01-10 17:08:03 +00:00
if servers == nil {
servers = make(map[string]types.Server)
}
2018-03-26 13:32:04 +00:00
protocol := label.GetStringValue(service.SegmentLabels, label.TraefikProtocol, label.DefaultProtocol)
port := label.GetStringValue(service.SegmentLabels, label.TraefikPort, "")
2018-04-11 14:30:04 +00:00
weight := label.GetIntValue(service.SegmentLabels, label.TraefikWeight, label.DefaultWeight)
2018-01-10 17:08:03 +00:00
serverName := "server-" + strconv.Itoa(index)
servers[serverName] = types.Server{
URL: fmt.Sprintf("%s://%s:%s", protocol, ip, port),
Weight: weight,
}
}
return servers
}
2018-03-26 13:32:04 +00:00
func checkSegmentPort(labels map[string]string, segmentName string) (int, error) {
if rawPort, ok := labels[label.TraefikPort]; ok {
port, err := strconv.Atoi(rawPort)
if err != nil {
return port, fmt.Errorf("invalid port value %q for the segment %q: %v", rawPort, segmentName, err)
2018-01-10 17:08:03 +00:00
}
2018-03-26 13:32:04 +00:00
} else {
return 0, fmt.Errorf("port label is missing, please use %s as default value or define port label for all segments ('traefik.<segment_name>.port')", label.TraefikPort)
2018-01-10 17:08:03 +00:00
}
2018-03-26 13:32:04 +00:00
return 0, nil
}