...
1
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
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