istio.io/istio@v0.0.0-20240520182934-d79c90f27776/tools/bug-report/pkg/filter/filter.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package filter 16 17 import ( 18 "fmt" 19 20 "istio.io/istio/pkg/util/sets" 21 cluster2 "istio.io/istio/tools/bug-report/pkg/cluster" 22 "istio.io/istio/tools/bug-report/pkg/config" 23 "istio.io/istio/tools/bug-report/pkg/util/match" 24 "istio.io/istio/tools/bug-report/pkg/util/path" 25 ) 26 27 // GetMatchingPaths returns a slice of matching paths, given a cluster tree and config. 28 // config is the capture configuration. 29 // cluster is the structure representing the cluster resource hierarchy. 30 func GetMatchingPaths(config *config.BugReportConfig, cluster *cluster2.Resources) ([]string, error) { 31 paths, err := getMatchingPathsForSpec(config, cluster) 32 if err != nil { 33 return nil, err 34 } 35 return sets.SortedList(paths), nil 36 } 37 38 func getMatchingPathsForSpec(config *config.BugReportConfig, cluster *cluster2.Resources) (sets.String, error) { 39 return getMatchingPathsForSpecImpl(config, cluster, cluster.Root, nil, sets.New[string]()) 40 } 41 42 func getMatchingPathsForSpecImpl(config *config.BugReportConfig, cluster *cluster2.Resources, node map[string]any, 43 path path.Path, matchingPaths sets.String, 44 ) (sets.String, error) { 45 for pe, n := range node { 46 np := append(path, pe) 47 if nn, ok := n.(map[string]any); ok { 48 // non-leaf node 49 mp, err := getMatchingPathsForSpecImpl(config, cluster, nn, np, matchingPaths) 50 if err != nil { 51 return nil, err 52 } 53 matchingPaths = matchingPaths.Union(mp) 54 continue 55 } 56 // container name leaf 57 cn, ok := n.(string) 58 if !ok && n != nil { 59 return nil, fmt.Errorf("bad node type at path %s: got %T, expected string", n, cn) 60 } 61 if len(np) != 4 { 62 return nil, fmt.Errorf("unexpected leaf at path %s, expect leaf path to be namespace.deployment.pod.container", np) 63 } 64 if matchesKubeCaptureConfig(config, cluster, np[0], np[1], np[2], np[3]) { 65 matchingPaths[np.String()] = struct{}{} 66 } 67 } 68 return matchingPaths, nil 69 } 70 71 func matchesKubeCaptureConfig(config *config.BugReportConfig, cluster *cluster2.Resources, namespace, deployment, pod, container string) bool { 72 for _, sp := range config.Exclude { 73 if matchesSelectionSpec(sp, cluster, namespace, deployment, pod, container) { 74 return false 75 } 76 } 77 for _, sp := range parseIncluded(config.Include) { 78 if matchesSelectionSpec(sp, cluster, namespace, deployment, pod, container) { 79 return true 80 } 81 } 82 return false 83 } 84 85 // matchesSelectionSpec reports whether the given container path is selected by any SelectionSpec. 86 func matchesSelectionSpec(sp *config.SelectionSpec, cluster *cluster2.Resources, namespace, deployment, pod, container string) bool { 87 // For inclusion, match all if nothing is set. 88 if !match.MatchesGlobs(namespace, sp.Namespaces) { 89 return false 90 } 91 92 if !match.MatchesGlobs(deployment, sp.Deployments) { 93 return false 94 } 95 96 if !match.MatchesGlobs(pod, sp.Pods) && len(sp.Pods) != 0 { 97 return false 98 } 99 100 if !match.MatchesGlobs(container, sp.Containers) { 101 return false 102 } 103 104 if !match.MatchesGlobs(container, sp.Containers) { 105 return false 106 } 107 108 key := cluster2.PodKey(namespace, pod) 109 if !match.MatchesMap(sp.Labels, cluster.Labels[key]) { 110 return false 111 } 112 if !match.MatchesMap(sp.Annotations, cluster.Annotations[key]) { 113 return false 114 } 115 return true 116 } 117 118 func parseIncluded(included []*config.SelectionSpec) []*config.SelectionSpec { 119 if len(included) != 0 { 120 return included 121 } 122 return []*config.SelectionSpec{ 123 { 124 Namespaces: []string{"*"}, 125 }, 126 } 127 }