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  }