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 }