istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/config/analysis/analyzer.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 analysis 16 17 import ( 18 "istio.io/istio/pkg/config" 19 "istio.io/istio/pkg/config/analysis/scope" 20 "istio.io/istio/pkg/config/schema/collection" 21 "istio.io/istio/pkg/util/sets" 22 ) 23 24 // Analyzer is an interface for analyzing configuration. 25 type Analyzer interface { 26 Metadata() Metadata 27 Analyze(c Context) 28 } 29 30 // CombinedAnalyzer is an interface used to combine and run multiple analyzers into one 31 type CombinedAnalyzer interface { 32 Analyzer 33 RelevantSubset(kinds sets.Set[config.GroupVersionKind]) CombinedAnalyzer 34 RemoveSkipped(schemas collection.Schemas) []string 35 AnalyzerNames() []string 36 } 37 38 // InternalCombinedAnalyzer is an implementation of CombinedAnalyzer, a special analyzer that combines multiple analyzers into one 39 type InternalCombinedAnalyzer struct { 40 name string 41 analyzers []Analyzer 42 } 43 44 // Combine multiple analyzers into a single one. 45 // For input metadata, use the union of the component analyzers 46 func Combine(name string, analyzers ...Analyzer) CombinedAnalyzer { 47 return &InternalCombinedAnalyzer{ 48 name: name, 49 analyzers: analyzers, 50 } 51 } 52 53 func (c *InternalCombinedAnalyzer) RelevantSubset(kinds sets.Set[config.GroupVersionKind]) CombinedAnalyzer { 54 var selected []Analyzer 55 for _, a := range c.analyzers { 56 for _, inputKind := range a.Metadata().Inputs { 57 if kinds.Contains(inputKind) { 58 selected = append(selected, a) 59 break 60 } 61 } 62 } 63 return Combine("subset", selected...) 64 } 65 66 // Metadata implements Analyzer 67 func (c *InternalCombinedAnalyzer) Metadata() Metadata { 68 return Metadata{ 69 Name: c.name, 70 Inputs: combineInputs(c.analyzers), 71 } 72 } 73 74 // Analyze implements Analyzer 75 func (c *InternalCombinedAnalyzer) Analyze(ctx Context) { 76 for _, a := range c.analyzers { 77 scope.Analysis.Debugf("Started analyzer %q...", a.Metadata().Name) 78 if ctx.Canceled() { 79 scope.Analysis.Debugf("Analyzer %q has been cancelled...", c.Metadata().Name) 80 return 81 } 82 ctx.SetAnalyzer(a.Metadata().Name) 83 a.Analyze(ctx) 84 scope.Analysis.Debugf("Completed analyzer %q...", a.Metadata().Name) 85 } 86 } 87 88 // RemoveSkipped removes analyzers that should be skipped, meaning they meet one of the following criteria: 89 // 1. The analyzer requires disabled input collections. The names of removed analyzers are returned. 90 // Transformer information is used to determine, based on the disabled input collections, which output collections 91 // should be disabled. Any analyzers that require those output collections will be removed. 92 // 2. The analyzer requires a collection not available in the current snapshot(s) 93 func (c *InternalCombinedAnalyzer) RemoveSkipped(schemas collection.Schemas) []string { 94 allSchemas := schemas.All() 95 s := sets.NewWithLength[config.GroupVersionKind](len(allSchemas)) 96 for _, sc := range allSchemas { 97 s.Insert(sc.GroupVersionKind()) 98 } 99 100 var enabled []Analyzer 101 var removedNames []string 102 mainloop: 103 for _, a := range c.analyzers { 104 for _, in := range a.Metadata().Inputs { 105 if !s.Contains(in) { 106 scope.Analysis.Infof("Skipping analyzer %q because collection %s is not in the snapshot(s).", a.Metadata().Name, in) 107 removedNames = append(removedNames, a.Metadata().Name) 108 continue mainloop 109 } 110 } 111 112 enabled = append(enabled, a) 113 } 114 115 c.analyzers = enabled 116 return removedNames 117 } 118 119 // AnalyzerNames returns the names of analyzers in this combined analyzer 120 func (c *InternalCombinedAnalyzer) AnalyzerNames() []string { 121 result := make([]string, 0, len(c.analyzers)) 122 for _, a := range c.analyzers { 123 result = append(result, a.Metadata().Name) 124 } 125 return result 126 } 127 128 func combineInputs(analyzers []Analyzer) []config.GroupVersionKind { 129 result := sets.NewWithLength[config.GroupVersionKind](len(analyzers)) 130 for _, a := range analyzers { 131 result.InsertAll(a.Metadata().Inputs...) 132 } 133 return result.UnsortedList() 134 }