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  }