traefik/provider/label/segment.go
2018-03-23 13:30:03 +01:00

167 lines
4.5 KiB
Go

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
}
}
log.Debug(originLabels, allLabels)
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
}