istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/config/analysis/analyzers/deprecation/deprecation.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 deprecation
    16  
    17  import (
    18  	"fmt"
    19  
    20  	k8sext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    21  
    22  	"istio.io/api/networking/v1alpha3"
    23  	"istio.io/istio/pkg/config"
    24  	"istio.io/istio/pkg/config/analysis"
    25  	"istio.io/istio/pkg/config/analysis/msg"
    26  	"istio.io/istio/pkg/config/resource"
    27  	"istio.io/istio/pkg/config/schema/gvk"
    28  )
    29  
    30  // FieldAnalyzer checks for deprecated Istio types and fields
    31  type FieldAnalyzer struct{}
    32  
    33  // Tracks Istio CRDs removed from manifests/charts/base/crds/crd-all.gen.yaml
    34  var deprecatedCRDs = []k8sext.CustomResourceDefinitionSpec{
    35  	{
    36  		Group: "rbac.istio.io",
    37  		Names: k8sext.CustomResourceDefinitionNames{Kind: "ClusterRbacConfig"},
    38  	},
    39  	{
    40  		Group: "rbac.istio.io",
    41  		Names: k8sext.CustomResourceDefinitionNames{Kind: "RbacConfig"},
    42  	},
    43  	{
    44  		Group: "rbac.istio.io",
    45  		Names: k8sext.CustomResourceDefinitionNames{Kind: "ServiceRole"},
    46  	},
    47  	{
    48  		Group: "rbac.istio.io",
    49  		Names: k8sext.CustomResourceDefinitionNames{Kind: "ServiceRoleBinding"},
    50  	},
    51  }
    52  
    53  // Currently we don't have an Istio API that tells which Istio API fields are deprecated.
    54  // Run `find . -name "*.proto" -exec grep -i "deprecated=true" \{\} \; -print`
    55  // to see what is deprecated.  This analyzer is hand-crafted.
    56  
    57  // Metadata implements analyzer.Analyzer
    58  func (*FieldAnalyzer) Metadata() analysis.Metadata {
    59  	deprecationInputs := []config.GroupVersionKind{
    60  		gvk.VirtualService,
    61  		gvk.Sidecar,
    62  		gvk.CustomResourceDefinition,
    63  	}
    64  
    65  	return analysis.Metadata{
    66  		Name:        "deprecation.DeprecationAnalyzer",
    67  		Description: "Checks for deprecated Istio types and fields",
    68  		Inputs:      deprecationInputs,
    69  	}
    70  }
    71  
    72  // Analyze implements analysis.Analyzer
    73  func (fa *FieldAnalyzer) Analyze(ctx analysis.Context) {
    74  	ctx.ForEach(gvk.VirtualService, func(r *resource.Instance) bool {
    75  		fa.analyzeVirtualService(r, ctx)
    76  		return true
    77  	})
    78  	ctx.ForEach(gvk.Sidecar, func(r *resource.Instance) bool {
    79  		fa.analyzeSidecar(r, ctx)
    80  		return true
    81  	})
    82  	ctx.ForEach(gvk.CustomResourceDefinition, func(r *resource.Instance) bool {
    83  		fa.analyzeCRD(r, ctx)
    84  		return true
    85  	})
    86  }
    87  
    88  func (*FieldAnalyzer) analyzeCRD(r *resource.Instance, ctx analysis.Context) {
    89  	for _, depCRD := range deprecatedCRDs {
    90  		var group, kind string
    91  		switch crd := r.Message.(type) {
    92  		case *k8sext.CustomResourceDefinition:
    93  			group = crd.Spec.Group
    94  			kind = crd.Spec.Names.Kind
    95  		case *k8sext.CustomResourceDefinitionSpec:
    96  			group = crd.Group
    97  			kind = crd.Names.Kind
    98  		}
    99  		if group == depCRD.Group && kind == depCRD.Names.Kind {
   100  			ctx.Report(gvk.CustomResourceDefinition,
   101  				msg.NewDeprecated(r, crRemovedMessage(depCRD.Group, depCRD.Names.Kind)))
   102  		}
   103  	}
   104  }
   105  
   106  func (*FieldAnalyzer) analyzeSidecar(r *resource.Instance, ctx analysis.Context) {
   107  	sc := r.Message.(*v1alpha3.Sidecar)
   108  
   109  	if sc.OutboundTrafficPolicy != nil {
   110  		if sc.OutboundTrafficPolicy.EgressProxy != nil {
   111  			ctx.Report(gvk.VirtualService,
   112  				msg.NewDeprecated(r, ignoredMessage("OutboundTrafficPolicy.EgressProxy")))
   113  		}
   114  	}
   115  }
   116  
   117  func (*FieldAnalyzer) analyzeVirtualService(r *resource.Instance, ctx analysis.Context) {
   118  	vs := r.Message.(*v1alpha3.VirtualService)
   119  
   120  	for _, httpRoute := range vs.Http {
   121  		if httpRoute.Fault != nil {
   122  			if httpRoute.Fault.Delay != nil {
   123  				// nolint: staticcheck
   124  				if httpRoute.Fault.Delay.Percent > 0 {
   125  					ctx.Report(gvk.VirtualService,
   126  						msg.NewDeprecated(r, replacedMessage("HTTPRoute.fault.delay.percent", "HTTPRoute.fault.delay.percentage")))
   127  				}
   128  			}
   129  		}
   130  	}
   131  }
   132  
   133  func replacedMessage(deprecated, replacement string) string {
   134  	return fmt.Sprintf("%s is deprecated; use %s", deprecated, replacement)
   135  }
   136  
   137  func ignoredMessage(field string) string {
   138  	return fmt.Sprintf("%s ignored", field)
   139  }
   140  
   141  func crRemovedMessage(group, kind string) string {
   142  	return fmt.Sprintf("Custom resource type %s %s is removed", group, kind)
   143  }