istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/config/analysis/analyzers/schema/validation.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 package schema 15 16 import ( 17 "github.com/hashicorp/go-multierror" 18 19 "istio.io/istio/pkg/config" 20 "istio.io/istio/pkg/config/analysis" 21 "istio.io/istio/pkg/config/analysis/diag" 22 "istio.io/istio/pkg/config/analysis/msg" 23 "istio.io/istio/pkg/config/resource" 24 "istio.io/istio/pkg/config/schema/collections" 25 sresource "istio.io/istio/pkg/config/schema/resource" 26 "istio.io/istio/pkg/config/validation" 27 ) 28 29 // ValidationAnalyzer runs schema validation as an analyzer and reports any violations as messages 30 type ValidationAnalyzer struct { 31 s sresource.Schema 32 } 33 34 var _ analysis.Analyzer = &ValidationAnalyzer{} 35 36 func CollectionValidationAnalyzer(s sresource.Schema) analysis.Analyzer { 37 return &ValidationAnalyzer{s: s} 38 } 39 40 // AllValidationAnalyzers returns a slice with a validation analyzer for each Istio schema 41 // This automation comes with an assumption: that the collection names used by the schema match the metadata used by Galley components 42 func AllValidationAnalyzers() []analysis.Analyzer { 43 result := make([]analysis.Analyzer, 0) 44 collections.Istio.ForEach(func(s sresource.Schema) (done bool) { 45 result = append(result, &ValidationAnalyzer{s: s}) 46 return 47 }) 48 return result 49 } 50 51 // Metadata implements Analyzer 52 func (a *ValidationAnalyzer) Metadata() analysis.Metadata { 53 return analysis.Metadata{ 54 Name: "schema.ValidationAnalyzer." + a.s.Kind(), 55 Description: "Runs schema validation as an analyzer on '" + a.s.Kind() + "' resources", 56 Inputs: []config.GroupVersionKind{a.s.GroupVersionKind()}, 57 } 58 } 59 60 // Analyze implements Analyzer 61 func (a *ValidationAnalyzer) Analyze(ctx analysis.Context) { 62 gv := a.s.GroupVersionKind() 63 ctx.ForEach(gv, func(r *resource.Instance) bool { 64 ns := r.Metadata.FullName.Namespace 65 name := r.Metadata.FullName.Name 66 67 warnings, err := a.s.ValidateConfig(config.Config{ 68 Meta: config.Meta{ 69 Name: string(name), 70 Namespace: string(ns), 71 }, 72 Spec: r.Message, 73 }) 74 if err != nil { 75 if multiErr, ok := err.(*multierror.Error); ok { 76 for _, err := range multiErr.WrappedErrors() { 77 ctx.Report(gv, morePreciseMessage(r, err, true)) 78 } 79 } else { 80 ctx.Report(gv, morePreciseMessage(r, err, true)) 81 } 82 } 83 if warnings != nil { 84 if multiErr, ok := warnings.(*multierror.Error); ok { 85 for _, err := range multiErr.WrappedErrors() { 86 ctx.Report(gv, morePreciseMessage(r, err, false)) 87 } 88 } else { 89 ctx.Report(gv, morePreciseMessage(r, warnings, false)) 90 } 91 } 92 93 return true 94 }) 95 } 96 97 func morePreciseMessage(r *resource.Instance, err error, isError bool) diag.Message { 98 if aae, ok := err.(*validation.AnalysisAwareError); ok { 99 switch aae.Type { 100 case "VirtualServiceUnreachableRule": 101 return msg.NewVirtualServiceUnreachableRule(r, aae.Parameters[0].(string), aae.Parameters[1].(string)) 102 case "VirtualServiceIneffectiveMatch": 103 return msg.NewVirtualServiceIneffectiveMatch(r, aae.Parameters[0].(string), aae.Parameters[1].(string), aae.Parameters[2].(string)) 104 } 105 } 106 if !isError { 107 return msg.NewSchemaWarning(r, err) 108 } 109 return msg.NewSchemaValidationError(r, err) 110 }