github.com/cilium/cilium@v1.16.2/pkg/hubble/filters/labels.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Hubble 3 4 package filters 5 6 import ( 7 "context" 8 "fmt" 9 10 flowpb "github.com/cilium/cilium/api/v1/flow" 11 v1 "github.com/cilium/cilium/pkg/hubble/api/v1" 12 k8sLabels "github.com/cilium/cilium/pkg/k8s/slim/k8s/apis/labels" 13 ciliumLabels "github.com/cilium/cilium/pkg/labels" 14 ) 15 16 func sourceLabels(ev *v1.Event) k8sLabels.Labels { 17 labels := ev.GetFlow().GetSource().GetLabels() 18 return ciliumLabels.ParseLabelArrayFromArray(labels) 19 } 20 21 func destinationLabels(ev *v1.Event) k8sLabels.Labels { 22 labels := ev.GetFlow().GetDestination().GetLabels() 23 return ciliumLabels.ParseLabelArrayFromArray(labels) 24 } 25 26 func nodeLabels(ev *v1.Event) k8sLabels.Labels { 27 labels := ev.GetFlow().GetNodeLabels() 28 return ciliumLabels.ParseLabelArrayFromArray(labels) 29 } 30 31 func parseSelector(selector string) (k8sLabels.Selector, error) { 32 // ciliumLabels.LabelArray extends the k8sLabels.Selector logic with 33 // support for Cilium source prefixes such as "k8s:foo" or "any:bar". 34 // It does this by treating the string before the first dot as the source 35 // prefix, i.e. `k8s.foo` is treated like `k8s:foo`. This translation is 36 // needed because k8sLabels.Selector does not support colons in label names. 37 // 38 // We do not want to expose this implementation detail to the user, 39 // therefore we translate any user-specified source prefixes by 40 // replacing colon-based source prefixes in labels with dot-based prefixes, 41 // i.e. "k8s:foo in (bar, baz)" becomes "k8s.foo in (bar, baz)". 42 // 43 // We also prefix any key that doesn ot specify with "any." 44 // i.e. "example.com in (bar, buzz)" becomes "any.example.com in (bar, buzz)" 45 translated, err := translateSelector(selector) 46 if err != nil { 47 return nil, err 48 } 49 return k8sLabels.Parse(translated) 50 } 51 52 // FilterByLabelSelectors returns a FilterFunc. The FilterFunc returns true if and only if any of the 53 // specified selectors select the event. The caller specifies how to extract labels from the event. 54 func FilterByLabelSelectors(labelSelectors []string, getLabels func(*v1.Event) k8sLabels.Labels) (FilterFunc, error) { 55 selectors := make([]k8sLabels.Selector, 0, len(labelSelectors)) 56 for _, selector := range labelSelectors { 57 s, err := parseSelector(selector) 58 if err != nil { 59 return nil, err 60 } 61 selectors = append(selectors, s) 62 } 63 64 return func(ev *v1.Event) bool { 65 labels := getLabels(ev) 66 for _, selector := range selectors { 67 if selector.Matches(labels) { 68 return true 69 } 70 } 71 return false 72 }, nil 73 } 74 75 // LabelsFilter implements filtering based on labels 76 type LabelsFilter struct{} 77 78 // OnBuildFilter builds a labels filter 79 func (l *LabelsFilter) OnBuildFilter(ctx context.Context, ff *flowpb.FlowFilter) ([]FilterFunc, error) { 80 var fs []FilterFunc 81 82 if ff.GetSourceLabel() != nil { 83 slf, err := FilterByLabelSelectors(ff.GetSourceLabel(), sourceLabels) 84 if err != nil { 85 return nil, fmt.Errorf("invalid source label filter: %w", err) 86 } 87 fs = append(fs, slf) 88 } 89 90 if ff.GetDestinationLabel() != nil { 91 dlf, err := FilterByLabelSelectors(ff.GetDestinationLabel(), destinationLabels) 92 if err != nil { 93 return nil, fmt.Errorf("invalid destination label filter: %w", err) 94 } 95 fs = append(fs, dlf) 96 } 97 98 if ff.GetNodeLabels() != nil { 99 nlf, err := FilterByLabelSelectors(ff.GetNodeLabels(), nodeLabels) 100 if err != nil { 101 return nil, fmt.Errorf("invalid node label filter: %w", err) 102 } 103 fs = append(fs, nlf) 104 } 105 106 return fs, nil 107 }