2018-03-23 12:30:03 +00:00
package label
import (
"regexp"
"strings"
"github.com/containous/traefik/log"
)
var (
// SegmentPropertiesRegexp used to extract the name of the segment and the name of the property for this segment
// All properties are under the format traefik.<segment_name>.frontend.*= except the port/portIndex/weight/protocol/backend directly after traefik.<segment_name>.
SegmentPropertiesRegexp = regexp . MustCompile ( ` ^traefik\.(?P<segment_name>.+?)\.(?P<property_name>port|portIndex|weight|protocol|backend|frontend\.(.+))$ ` )
// PortRegexp used to extract the port label of the segment
PortRegexp = regexp . MustCompile ( ` ^traefik\.(?P<segment_name>.+?)\.port$ ` )
)
// SegmentPropertyValues is a map of segment properties
// an example value is: weight=42
type SegmentPropertyValues map [ string ] string
// SegmentProperties is a map of segment properties per segment,
// which we can get with label[segmentName][propertyName].
// It yields a property value.
type SegmentProperties map [ string ] SegmentPropertyValues
// FindSegmentSubmatch split segment labels
func FindSegmentSubmatch ( name string ) [ ] string {
matches := SegmentPropertiesRegexp . FindStringSubmatch ( name )
if matches == nil ||
strings . HasPrefix ( name , TraefikFrontend + "." ) ||
strings . HasPrefix ( name , TraefikBackend + "." ) {
return nil
}
return matches
}
// ExtractServicePropertiesP Extract services labels
// Deprecated
func ExtractServicePropertiesP ( labels * map [ string ] string ) SegmentProperties {
if labels == nil {
return make ( SegmentProperties )
}
return ExtractServiceProperties ( * labels )
}
// ExtractServiceProperties Extract services labels
// Deprecated
func ExtractServiceProperties ( labels map [ string ] string ) SegmentProperties {
v := make ( SegmentProperties )
for name , value := range labels {
matches := FindSegmentSubmatch ( name )
if matches == nil {
continue
}
var segmentName string
var propertyName string
for i , name := range SegmentPropertiesRegexp . SubexpNames ( ) {
// the group 0 is anonymous because it's always the root expression
if i != 0 {
if name == "segment_name" {
segmentName = matches [ i ]
} else if name == "property_name" {
propertyName = matches [ i ]
}
}
}
if _ , ok := v [ segmentName ] ; ! ok {
v [ segmentName ] = make ( SegmentPropertyValues )
}
v [ segmentName ] [ propertyName ] = value
}
return v
}
// GetServiceLabel converts a key value of Label*, given a serviceName,
// into a pattern <LabelPrefix>.<serviceName>.<property>
// i.e. For LabelFrontendRule and serviceName=app it will return "traefik.app.frontend.rule"
// Deprecated
func GetServiceLabel ( labelName , serviceName string ) string {
if len ( serviceName ) > 0 {
property := strings . TrimPrefix ( labelName , Prefix )
return Prefix + serviceName + "." + property
}
return labelName
}
// ExtractTraefikLabels transform labels to segment labels
func ExtractTraefikLabels ( originLabels map [ string ] string ) SegmentProperties {
allLabels := make ( SegmentProperties )
if _ , ok := allLabels [ "" ] ; ! ok {
allLabels [ "" ] = make ( SegmentPropertyValues )
}
for name , value := range originLabels {
if ! strings . HasPrefix ( name , Prefix ) {
continue
}
matches := FindSegmentSubmatch ( name )
if matches == nil {
// Classic labels
allLabels [ "" ] [ name ] = value
} else {
// segments labels
var segmentName string
var propertyName string
for i , name := range SegmentPropertiesRegexp . SubexpNames ( ) {
// the group 0 is anonymous because it's always the root expression
if i != 0 {
if name == "segment_name" {
segmentName = matches [ i ]
} else if name == "property_name" {
propertyName = matches [ i ]
}
}
}
if _ , ok := allLabels [ segmentName ] ; ! ok {
allLabels [ segmentName ] = make ( SegmentPropertyValues )
}
allLabels [ segmentName ] [ Prefix + propertyName ] = value
}
}
2018-03-28 15:18:04 +00:00
log . Debug ( "originLabels" , originLabels )
log . Debug ( "allLabels" , allLabels )
2018-03-23 12:30:03 +00:00
allLabels . mergeDefault ( )
return allLabels
}
func ( s SegmentProperties ) mergeDefault ( ) {
// if SegmentProperties contains the default segment, merge each segments with the default segment
if defaultLabels , okDefault := s [ "" ] ; okDefault {
segmentsNames := s . GetSegmentNames ( )
if len ( defaultLabels ) > 0 {
for _ , name := range segmentsNames {
segmentLabels := s [ name ]
for key , value := range defaultLabels {
if _ , ok := segmentLabels [ key ] ; ! ok {
segmentLabels [ key ] = value
}
}
}
}
if len ( segmentsNames ) > 1 {
delete ( s , "" )
}
}
}
// GetSegmentNames get all segment names
func ( s SegmentProperties ) GetSegmentNames ( ) [ ] string {
var names [ ] string
for name := range s {
names = append ( names , name )
}
return names
}