seems to work, needs tests and a lot of cleanup

This commit is contained in:
Pat Christopher 2021-07-12 20:28:10 -07:00
parent f880187573
commit ef3c344868
No known key found for this signature in database
GPG Key ID: F8BCFE8CB1484819
5 changed files with 124 additions and 3 deletions

View File

@ -60,7 +60,7 @@ func NewKubeletServerCertificateManager(kubeClient clientset.Interface, kubeCfg
Subsystem: metrics.KubeletSubsystem,
Name: "server_expiration_renew_errors",
Help: "Counter of certificate renewal errors.",
StabilityLevel: compbasemetrics.ALPHA,
StabilityLevel: compbasemetrics.STABLE,
},
)
legacyregistry.MustRegister(certificateRenewFailure)

View File

@ -20,6 +20,7 @@ import (
"fmt"
"go/ast"
"go/token"
"os"
"sort"
"strconv"
"strings"
@ -182,7 +183,24 @@ func (c *metricDecoder) decodeOpts(expr ast.Expr) (metric, error) {
if err != nil {
return m, err
}
case *ast.SelectorExpr:
packageName := fmt.Sprintf("%v", v.X)
variableExpr, found := c.variables[packageName + "." + v.Sel.Name]
if !found {
return m, newDecodeErrorf(expr, errBadVariableAttribute)
}
bl, ok := variableExpr.(*ast.BasicLit)
if !ok {
return m, newDecodeErrorf(expr, errNonStringAttribute)
}
value, err = stringValue(bl)
if err != nil {
return m, err
}
default:
fmt.Fprintf(os.Stdout, "key %s is type %T from Default\n", key, v)
return m, newDecodeErrorf(expr, errNonStringAttribute)
}
switch key {

View File

@ -28,7 +28,7 @@ const (
errStabilityLevel = "StabilityLevel should be passed STABLE, ALPHA or removed"
errStableSummary = "Stable summary metric is not supported"
errInvalidNewMetricCall = "Invalid new metric call, please ensure code compiles"
errNonStringAttribute = "Non string attribute it not supported"
errNonStringAttribute = "Non string attribute is not supported"
errBadVariableAttribute = "Metric attribute was not correctly set. Please use only global consts in same file"
errFieldNotSupported = "Field %s is not supported"
errBuckets = "Buckets should be set to list of floats, result from function call of prometheus.LinearBuckets or prometheus.ExponentialBuckets"

View File

@ -23,6 +23,7 @@ import (
"go/ast"
"go/parser"
"go/token"
"io/ioutil"
"os"
"path/filepath"
"sort"
@ -124,6 +125,11 @@ func searchFileForStableMetrics(filename string, src interface{}) ([]metric, []e
}
variables := globalVariableDeclarations(tree)
variables, err = importedGlobalVariableDeclaration(variables, tree.Imports)
if err != nil {
return []metric{}, addFileInformationToErrors([]error{err}, fileset)
}
stableMetricsFunctionCalls, errors := findStableMetricDeclaration(tree, metricsImportName)
metrics, es := decodeMetricCalls(stableMetricsFunctionCalls, metricsImportName, variables)
errors = append(errors, es...)
@ -173,3 +179,100 @@ func globalVariableDeclarations(tree *ast.File) map[string]ast.Expr {
}
return consts
}
func importedGlobalVariableDeclaration(localVariables map[string]ast.Expr, imports []*ast.ImportSpec) (map[string]ast.Expr, error) {
// to test the import will be rooted at GOPATH, so probably import will be something like /test/instrumentation/testpackage
// env gets
//GOMODCACHE := os.Getenv("GOMODCACHE")
GOROOT := os.Getenv("GOROOT")
GOOS := os.Getenv("GOOS")
KUBE_ROOT := os.Getenv("KUBE_ROOT")
KUBE_URL_ROOT := "k8s.io/kubernetes"
KUBE_ROOT_INTERNAL := strings.Replace(KUBE_ROOT, KUBE_URL_ROOT, "", 1) // k8s/k8s refs need this stripped
for _, im := range imports {
// get imported label
importAlias := "unknown"
if im.Name == nil {
pathSegments := strings.Split(im.Path.Value, "/")
importAlias = strings.Trim(pathSegments[len(pathSegments)-1], "\"")
} else {
importAlias = im.Name.String()
}
// parse directory path
pathPrefix := "unknown"
if strings.Contains(im.Path.Value, KUBE_URL_ROOT) {
// search k/k local checkout
pathPrefix = KUBE_ROOT_INTERNAL
} else if strings.Contains(im.Path.Value, "k8s.io/") {
// search k/k/staging local checkout
pathPrefix = KUBE_ROOT + string(os.PathSeparator) + "staging" + string(os.PathSeparator) + "src" //KUBE_ROOT + string(os.PathSeparator) + "vendor" //
} else if strings.Contains(im.Path.Value, ".") {
// not stdlib -> prefix with GOMODCACHE
// pathPrefix = KUBE_ROOT + string(os.PathSeparator) + "vendor"
// this requires implementing SIV, skip for now
continue
} else {
// stdlib -> prefix with GOROOT
pathPrefix = GOROOT + string(os.PathSeparator) + "src"
} // ToDo: support non go mod
importDirectory := pathPrefix + string(os.PathSeparator) + strings.Trim(im.Path.Value, "\"")
files, err := ioutil.ReadDir(importDirectory)
if err != nil {
//fmt.Fprintf(os.Stderr, "failed to read import path directory %s with error %w, skipping\n", importDirectory, err)
continue
}
for _, file := range files {
if file.IsDir() {
// do not grab constants from subpackages
continue
}
if strings.Contains(file.Name(), "_test") {
// do not parse test files
continue
}
if !strings.HasSuffix(file.Name(), ".go") {
// not a go code file, do not attempt to parse
continue
}
fileset := token.NewFileSet()
tree, err := parser.ParseFile(fileset, importDirectory+string(os.PathSeparator)+file.Name(), nil, parser.AllErrors)
if err != nil {
return nil, fmt.Errorf("failed to parse path %s with error %w", im.Path.Value, err)
}
// pass parsed filepath into globalVariableDeclarations
variables := globalVariableDeclarations(tree)
// add returned map into supplied map and prepend import label to all keys
for k, v := range variables {
importK := importAlias + "." + k
if _, ok := localVariables[importK]; !ok {
localVariables[importK] = v
} else {
// cross-platform file that gets included in the correct OS build via OS build tags
// use whatever matches GOOS
if strings.Contains(file.Name(), GOOS) {
// assume at some point we will find the correct OS version of this file
// if we are running on an OS that does not have an OS specific file for something then we will include a constant we shouldn't
// TODO: should we include/exclude based on the build tags?
localVariables[importK] = v
}
}
}
}
}
return localVariables, nil
}

View File

@ -58,7 +58,7 @@ reset=$(tput sgr0)
kube::validate::stablemetrics() {
stability_check_setup
temp_file=$(mktemp)
doValidate=$(find_files_to_check | grep -E ".*.go" | grep -v ".*_test.go" | sort | xargs -L 200 go run "test/instrumentation/main.go" "test/instrumentation/decode_metric.go" "test/instrumentation/find_stable_metric.go" "test/instrumentation/error.go" "test/instrumentation/metric.go" -- 1>"${temp_file}")
doValidate=$(find_files_to_check | grep -E ".*.go" | grep -v ".*_test.go" | sort | KUBE_ROOT=${KUBE_ROOT} xargs -L 200 go run "test/instrumentation/main.go" "test/instrumentation/decode_metric.go" "test/instrumentation/find_stable_metric.go" "test/instrumentation/error.go" "test/instrumentation/metric.go" -- 1>"${temp_file}")
if $doValidate; then
echo -e "${green}Diffing test/instrumentation/testdata/stable-metrics-list.yaml\n${reset}"