...

Source file src/k8s.io/kubernetes/test/instrumentation/find_stable_metric.go

Documentation: k8s.io/kubernetes/test/instrumentation

     1  /*
     2  Copyright 2019 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package main
    18  
    19  import (
    20  	"fmt"
    21  	"go/ast"
    22  
    23  	"k8s.io/component-base/metrics"
    24  )
    25  
    26  var metricsOptionStructuresNames = []string{
    27  	"KubeOpts",
    28  	"CounterOpts",
    29  	"GaugeOpts",
    30  	"HistogramOpts",
    31  	"SummaryOpts",
    32  	"TimingHistogramOpts",
    33  }
    34  
    35  func findStableMetricDeclaration(tree ast.Node, metricsImportName string) ([]*ast.CallExpr, []error) {
    36  	v := stableMetricFinder{
    37  		metricsImportName:          metricsImportName,
    38  		stableMetricsFunctionCalls: []*ast.CallExpr{},
    39  		errors:                     []error{},
    40  	}
    41  	ast.Walk(&v, tree)
    42  	return v.stableMetricsFunctionCalls, v.errors
    43  }
    44  
    45  // Implements visitor pattern for ast.Node that collects all stable metric expressions
    46  type stableMetricFinder struct {
    47  	metricsImportName          string
    48  	currentFunctionCall        *ast.CallExpr
    49  	stableMetricsFunctionCalls []*ast.CallExpr
    50  	errors                     []error
    51  }
    52  
    53  var _ ast.Visitor = (*stableMetricFinder)(nil)
    54  
    55  func contains(v metrics.StabilityLevel, a []metrics.StabilityLevel) bool {
    56  	for _, i := range a {
    57  		if i == v {
    58  			return true
    59  		}
    60  	}
    61  	return false
    62  }
    63  
    64  func (f *stableMetricFinder) Visit(node ast.Node) (w ast.Visitor) {
    65  	switch opts := node.(type) {
    66  	case *ast.CallExpr:
    67  		if se, ok := opts.Fun.(*ast.SelectorExpr); ok {
    68  			if se.Sel.Name == "NewDesc" {
    69  				sl, _ := decodeStabilityLevel(opts.Args[4], f.metricsImportName)
    70  				if sl != nil {
    71  					classes := []metrics.StabilityLevel{metrics.STABLE, metrics.BETA}
    72  					if ALL_STABILITY_CLASSES {
    73  						classes = append(classes, metrics.ALPHA)
    74  					}
    75  					switch {
    76  					case contains(*sl, classes):
    77  						f.stableMetricsFunctionCalls = append(f.stableMetricsFunctionCalls, opts)
    78  						f.currentFunctionCall = nil
    79  					default:
    80  						return nil
    81  					}
    82  				}
    83  			} else {
    84  				f.currentFunctionCall = opts
    85  			}
    86  
    87  		} else {
    88  			f.currentFunctionCall = opts
    89  		}
    90  	case *ast.CompositeLit:
    91  		se, ok := opts.Type.(*ast.SelectorExpr)
    92  		if !ok {
    93  			return f
    94  		}
    95  		if !isMetricOps(se.Sel.Name) {
    96  			return f
    97  		}
    98  		id, ok := se.X.(*ast.Ident)
    99  		if !ok {
   100  			return f
   101  		}
   102  		if id.Name != f.metricsImportName {
   103  			return f
   104  		}
   105  		stabilityLevel, err := getStabilityLevel(opts, f.metricsImportName)
   106  		if err != nil {
   107  			f.errors = append(f.errors, err)
   108  			return nil
   109  		}
   110  		classes := []metrics.StabilityLevel{metrics.STABLE, metrics.BETA}
   111  		if ALL_STABILITY_CLASSES {
   112  			classes = append(classes, metrics.ALPHA)
   113  		}
   114  		switch {
   115  		case contains(*stabilityLevel, classes):
   116  			if f.currentFunctionCall == nil {
   117  				f.errors = append(f.errors, newDecodeErrorf(opts, errNotDirectCall))
   118  				return nil
   119  			}
   120  			f.stableMetricsFunctionCalls = append(f.stableMetricsFunctionCalls, f.currentFunctionCall)
   121  			f.currentFunctionCall = nil
   122  		default:
   123  			return nil
   124  		}
   125  	default:
   126  		if f.currentFunctionCall == nil || node == nil || node.Pos() < f.currentFunctionCall.Rparen {
   127  			return f
   128  		}
   129  		f.currentFunctionCall = nil
   130  	}
   131  	return f
   132  }
   133  
   134  func isMetricOps(name string) bool {
   135  	var found = false
   136  	for _, optsName := range metricsOptionStructuresNames {
   137  		if name == optsName {
   138  			found = true
   139  			break
   140  		}
   141  	}
   142  	return found
   143  }
   144  
   145  func getStabilityLevel(opts *ast.CompositeLit, metricsFrameworkImportName string) (*metrics.StabilityLevel, error) {
   146  	for _, expr := range opts.Elts {
   147  		kv, ok := expr.(*ast.KeyValueExpr)
   148  		if !ok {
   149  			return nil, newDecodeErrorf(expr, errPositionalArguments)
   150  		}
   151  		key := fmt.Sprintf("%v", kv.Key)
   152  		if key != "StabilityLevel" {
   153  			continue
   154  		}
   155  		return decodeStabilityLevel(kv.Value, metricsFrameworkImportName)
   156  	}
   157  	stability := metrics.ALPHA
   158  	return &stability, nil
   159  }
   160  

View as plain text