2017-12-02 18:29:09 +00:00
package rancher
import (
2018-01-10 17:08:03 +00:00
"fmt"
2018-06-13 08:08:03 +00:00
"net"
2018-01-10 17:08:03 +00:00
"strconv"
2017-12-02 18:29:09 +00:00
"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-07-23 09:56:02 +00:00
func ( p * Provider ) buildConfiguration ( services [ ] rancherData ) * types . Configuration {
2017-12-02 18:29:09 +00:00
var RancherFuncMap = template . FuncMap {
2018-03-26 13:32:04 +00:00
"getLabelValue" : label . GetStringValue ,
"getDomain" : label . GetFuncString ( label . TraefikDomain , p . Domain ) ,
2017-12-20 15:33:26 +00:00
// 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 ,
2017-12-20 15:33:26 +00:00
// Frontend functions
2018-08-29 09:36:03 +00:00
"getBackendName" : getBackendName ,
"getFrontendRule" : p . getFrontendRule ,
"getPriority" : label . GetFuncInt ( label . TraefikFrontendPriority , label . DefaultFrontendPriority ) ,
"getPassHostHeader" : label . GetFuncBool ( label . TraefikFrontendPassHostHeader , label . DefaultPassHostHeader ) ,
"getPassTLSCert" : label . GetFuncBool ( label . TraefikFrontendPassTLSCert , label . DefaultPassTLSCert ) ,
"getPassTLSClientCert" : label . GetTLSClientCert ,
"getEntryPoints" : label . GetFuncSliceString ( label . TraefikFrontendEntryPoints ) ,
"getBasicAuth" : label . GetFuncSliceString ( label . TraefikFrontendAuthBasic ) , // Deprecated
"getAuth" : label . GetAuth ,
"getErrorPages" : label . GetErrorPages ,
"getRateLimit" : label . GetRateLimit ,
"getRedirect" : label . GetRedirect ,
"getHeaders" : label . GetHeaders ,
"getWhiteList" : label . GetWhiteList ,
2017-12-02 18:29:09 +00:00
}
// 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
}
2017-12-02 18:29:09 +00:00
}
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 ,
2017-12-02 18:29:09 +00:00
}
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
}
2017-12-02 18:29:09 +00:00
}
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 {
2017-12-02 18:29:09 +00:00
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 {
2018-04-17 18:58:24 +00:00
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 )
2017-12-02 18:29:09 +00:00
}
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 )
2017-12-02 18:29:09 +00:00
}
2018-03-26 13:32:04 +00:00
return provider . Normalize ( name )
2017-12-02 18:29:09 +00:00
}
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 {
2018-05-14 08:18:03 +00:00
if value := label . GetStringValue ( service . SegmentLabels , label . TraefikBackend , "" ) ; len ( value ) > 0 {
2018-03-26 13:32:04 +00:00
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 {
2018-04-22 07:10:03 +00:00
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 {
2018-06-13 08:08:03 +00:00
URL : fmt . Sprintf ( "%s://%s" , protocol , net . JoinHostPort ( ip , port ) ) ,
2018-01-10 17:08:03 +00:00
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
2017-12-02 18:29:09 +00:00
}