github.com/cilium/cilium@v1.16.2/pkg/hubble/filters/labelparser.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Hubble 3 4 package filters 5 6 import ( 7 "errors" 8 "fmt" 9 "io" 10 "strings" 11 "unicode" 12 ) 13 14 // translateSelector takes a label selector with colon-based source prefixes 15 // and translates it to a valid k8s label selector with dot-based prefixes, 16 // i.e. "k8s:foo in (bar, baz)" becomes "k8s.foo in (bar, baz)". 17 // It also makes sure that bare keys without an explicit source will get an 18 // `any` source prefix. 19 func translateSelector(selector string) (string, error) { 20 out := &strings.Builder{} 21 in := strings.NewReader(selector) 22 23 for in.Len() > 0 { 24 err := advanceToNextKey(in, out) 25 if err != nil { 26 return "", err 27 } 28 err = translateKey(in, out) 29 if err != nil { 30 return "", err 31 } 32 err = advanceToNextSelector(in, out) 33 if err != nil { 34 return "", err 35 } 36 } 37 return out.String(), nil 38 } 39 40 // advanceToNextKey scans from the beginning of a selector to the next 41 // key and writes everything before the start of the key from in to out. 42 func advanceToNextKey(in *strings.Reader, out *strings.Builder) error { 43 for { 44 r, _, err := in.ReadRune() 45 if errors.Is(err, io.EOF) { 46 return nil 47 } 48 if err != nil { 49 return err 50 } 51 if !unicode.IsSpace(r) && r != '!' { 52 return in.UnreadRune() 53 } 54 out.WriteRune(r) 55 } 56 } 57 58 // translateKey takes a reader that point to the start of a key. It reads 59 // until the end of the key and writes the translated key (with dot prefixes 60 // instead of colon-based source prefixes) to out 61 func translateKey(in *strings.Reader, out *strings.Builder) error { 62 key := &strings.Builder{} 63 defer func() { 64 ckey := key.String() 65 if !strings.Contains(ckey, ":") { 66 ckey = fmt.Sprintf("any:%s", ckey) 67 } 68 ckey = strings.Replace(ckey, ":", ".", 1) 69 out.WriteString(ckey) 70 }() 71 for { 72 r, _, err := in.ReadRune() 73 if errors.Is(err, io.EOF) { 74 return nil 75 } 76 if err != nil { 77 return err 78 } 79 if unicode.IsSpace(r) || r == '=' || r == '!' || r == ',' { 80 return in.UnreadRune() 81 } 82 key.WriteRune(r) 83 } 84 } 85 86 // advanceToNextSelector takes a read that points to the end of a key and will 87 // advance the reader to the beginning of the next selector and writes everything 88 // it scans to out. 89 func advanceToNextSelector(in *strings.Reader, out *strings.Builder) error { 90 nesting := 0 91 for { 92 r, _, err := in.ReadRune() 93 if errors.Is(err, io.EOF) { 94 return nil 95 } 96 if err != nil { 97 return err 98 } 99 switch r { 100 case '(': 101 nesting++ 102 case ')': 103 nesting-- 104 } 105 out.WriteRune(r) 106 if r == ',' && nesting == 0 { 107 return nil 108 } 109 } 110 }