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