github.com/cilium/cilium@v1.16.2/pkg/hubble/observer/local_node_watcher.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Hubble
     3  
     4  package observer
     5  
     6  import (
     7  	"context"
     8  	"slices"
     9  
    10  	flowpb "github.com/cilium/cilium/api/v1/flow"
    11  	"github.com/cilium/cilium/pkg/lock"
    12  	"github.com/cilium/cilium/pkg/node"
    13  )
    14  
    15  // LocalNodeWatcher populate Hubble flows local node related fields (currently
    16  // only labels).
    17  type LocalNodeWatcher struct {
    18  	mu    lock.Mutex
    19  	cache struct {
    20  		// labels are represented as a Go map in node.LocalNode, but we need a
    21  		// key=val slice for Hubble flows.
    22  		labels []string
    23  	}
    24  }
    25  
    26  // NewLocalNodeWatcher return a new LocalNodeWatcher. The given context control
    27  // whether the LocalNodeWatcher gets updated by the localNodeStore. It is safe
    28  // to use the returned LocalNodeWatcher once the context is cancelled, but its
    29  // information might be out-of-date.
    30  func NewLocalNodeWatcher(ctx context.Context, localNodeStore *node.LocalNodeStore) (*LocalNodeWatcher, error) {
    31  	watcher := LocalNodeWatcher{}
    32  	// fetch the initial local node
    33  	n, err := localNodeStore.Get(ctx)
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  	watcher.update(n)
    38  	// subscribe to local node changes.
    39  	localNodeStore.Observe(ctx, watcher.update, watcher.complete)
    40  
    41  	return &watcher, nil
    42  }
    43  
    44  // OnDecodedFlow implements OnDecodedFlow for LocalNodeWatcher. The
    45  // LocalNodeWatcher populate the flow's node_labels field.
    46  func (w *LocalNodeWatcher) OnDecodedFlow(_ context.Context, flow *flowpb.Flow) (bool, error) {
    47  	w.mu.Lock()
    48  	defer w.mu.Unlock()
    49  	flow.NodeLabels = w.cache.labels
    50  	return false, nil
    51  }
    52  
    53  // update synchronize the LocalNodeWatcher cache with the given LocalNode info.
    54  func (w *LocalNodeWatcher) update(n node.LocalNode) {
    55  	labels := sortedLabelSlice(n.Labels)
    56  	w.mu.Lock()
    57  	defer w.mu.Unlock()
    58  	w.cache.labels = labels
    59  }
    60  
    61  // complete clears the LocalNodeWatcher cache.
    62  func (w *LocalNodeWatcher) complete(error) {
    63  	w.mu.Lock()
    64  	defer w.mu.Unlock()
    65  	w.cache.labels = nil
    66  }
    67  
    68  // sortedLabelSlice convert a given map of key/val labels, and return a sorted
    69  // key=val slice.
    70  func sortedLabelSlice(src map[string]string) []string {
    71  	labels := make([]string, 0, len(src))
    72  	for key, val := range src {
    73  		labels = append(labels, key+"="+val)
    74  	}
    75  	slices.Sort(labels)
    76  	return labels
    77  }