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..frontend.*= except the port/portIndex/weight/protocol/backend directly after traefik.. SegmentPropertiesRegexp = regexp.MustCompile(`^traefik\.(?P.+?)\.(?Pport|portIndex|portName|weight|protocol|backend|frontend\.(.+))$`) // PortRegexp used to extract the port label of the segment PortRegexp = regexp.MustCompile(`^traefik\.(?P.+?)\.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 } // 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", originLabels) log.Debug("allLabels", 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 }