From 9e37493b930be8322ac91a07333045a8fad4cad5 Mon Sep 17 00:00:00 2001 From: Aviv Litman <64130977+avlitman@users.noreply.github.com> Date: Sun, 2 Jul 2023 21:54:38 +0300 Subject: [PATCH] [CI] Add metrics name linter (#2774) Signed-off-by: Aviv Litman --- Makefile | 8 +- go.mod | 1 + go.sum | 2 + hack/ci/prom_metric_linter.sh | 68 ++++++++++++++++ .../metrics_collector.go | 78 +++++++++++++++++++ .../metrics_json_generator.go | 37 +++++++++ .../pkg/metrics/parser/metrics_parser.go | 52 +++++++++++++ vendor/modules.txt | 3 + 8 files changed, 247 insertions(+), 2 deletions(-) create mode 100755 hack/ci/prom_metric_linter.sh create mode 100644 tools/prom-metrics-collector/metrics_collector.go create mode 100644 tools/prom-metrics-collector/metrics_json_generator.go create mode 100644 vendor/github.com/kubevirt/monitoring/pkg/metrics/parser/metrics_parser.go diff --git a/Makefile b/Makefile index 8c11dab42..e06e21788 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,8 @@ goveralls \ release-description \ bazel-generate bazel-build bazel-build-images bazel-push-images \ - fossa + fossa \ + lint-metrics DOCKER?=1 ifeq (${DOCKER}, 1) @@ -79,7 +80,7 @@ test-functional: build-functest ./hack/build/run-functional-tests.sh ${WHAT} "${TEST_ARGS}" # test-lint runs gofmt and golint tests against src files -test-lint: +test-lint: lint-metrics ${DO_BAZ} "./hack/build/run-lint-checks.sh" "./hack/ci/language.sh" @@ -166,6 +167,9 @@ build-docgen: fossa: ${DO_BAZ} "FOSSA_TOKEN_FILE=${FOSSA_TOKEN_FILE} PULL_BASE_REF=${PULL_BASE_REF} CI=${CI} ./hack/fossa.sh" +lint-metrics: + ./hack/ci/prom_metric_linter.sh --operator-name="kubevirt" --sub-operator-name="cdi" + help: @echo "Usage: make [Targets ...]" @echo " all " diff --git a/go.mod b/go.mod index 4cda4b8a3..025c1682d 100644 --- a/go.mod +++ b/go.mod @@ -20,6 +20,7 @@ require ( github.com/klauspost/compress v1.14.2 github.com/kubernetes-csi/external-snapshotter/client/v6 v6.0.1 github.com/kubernetes-csi/lib-volume-populator v1.2.0 + github.com/kubevirt/monitoring/pkg/metrics/parser v0.0.0-20230627123556-81a891d4462a github.com/onsi/ginkgo v1.16.5 github.com/onsi/gomega v1.24.1 github.com/openshift/api v0.0.0-20230406152840-ce21e3fe5da2 diff --git a/go.sum b/go.sum index 407de1a37..cb0418060 100644 --- a/go.sum +++ b/go.sum @@ -846,6 +846,8 @@ github.com/kubernetes-csi/external-snapshotter/client/v6 v6.0.1 h1:OqBS3UAo3eGWp github.com/kubernetes-csi/external-snapshotter/client/v6 v6.0.1/go.mod h1:tnHiLn3P10N95fjn7O40QH5ovN0EFGAxqdTpUMrX6bU= github.com/kubernetes-csi/lib-volume-populator v1.2.0 h1:7ooY7P/5xEMNKQS1NwcqipUF1FMD2uGBjp13UGQmGpY= github.com/kubernetes-csi/lib-volume-populator v1.2.0/go.mod h1:euAJwBP1NcKCm4ifQLmPgwJvlakPjGLDbbSvchlUr3I= +github.com/kubevirt/monitoring/pkg/metrics/parser v0.0.0-20230627123556-81a891d4462a h1:cdX+oxWw1lJDS3EchP+7Oz1XbErk4r7ffVJu1b1MKgI= +github.com/kubevirt/monitoring/pkg/metrics/parser v0.0.0-20230627123556-81a891d4462a/go.mod h1:qGj2agzgwQ27nYhP3xhLs+IBzE5+ALNUg8bDfMcwPqo= github.com/kylelemons/godebug v0.0.0-20160406211939-eadb3ce320cb/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/leanovate/gopter v0.2.4/go.mod h1:gNcbPWNEWRe4lm+bycKqxUYoH5uoVje5SkOJ3uoLer8= diff --git a/hack/ci/prom_metric_linter.sh b/hack/ci/prom_metric_linter.sh new file mode 100755 index 000000000..d02824672 --- /dev/null +++ b/hack/ci/prom_metric_linter.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash + +# +# This file is part of the KubeVirt project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Copyright 2023 Red Hat, Inc. +# +# +set -e + +linter_image_tag="v0.0.1" + +PROJECT_ROOT="$(readlink -e "$(dirname "${BASH_SOURCE[0]}")"/../../)" +export METRICS_COLLECTOR_PATH="${METRICS_COLLECTOR_PATH:-${PROJECT_ROOT}/tools/prom-metrics-collector}" + +if [[ ! -d "$METRICS_COLLECTOR_PATH" ]]; then + echo "Invalid METRICS_COLLECTOR_PATH: $METRICS_COLLECTOR_PATH is not a valid directory path" + exit 1 +fi + +# Parse command-line arguments +while [[ $# -gt 0 ]]; do + case "$1" in + --operator-name=*) + operator_name="${1#*=}" + shift + ;; + --sub-operator-name=*) + sub_operator_name="${1#*=}" + shift + ;; + *) + echo "Invalid argument: $1" + exit 1 + ;; + esac +done + +# Get the metrics list +go build -o _out/prom-metrics-collector "$METRICS_COLLECTOR_PATH/..." +json_output=$(_out/prom-metrics-collector 2>/dev/null) + +# Select container runtime +source "${PROJECT_ROOT}"/hack/build/common.sh + +# Run the linter by using the prom-metrics-linter Docker container +errors=$($CDI_CRI run -i "quay.io/kubevirt/prom-metrics-linter:$linter_image_tag" \ + --metric-families="$json_output" \ + --operator-name="$operator_name" \ + --sub-operator-name="$sub_operator_name" 2>/dev/null) + +# Check if there were any errors, if yes print and fail +if [[ $errors != "" ]]; then + echo "$errors" + exit 1 +fi diff --git a/tools/prom-metrics-collector/metrics_collector.go b/tools/prom-metrics-collector/metrics_collector.go new file mode 100644 index 000000000..a08d87f5c --- /dev/null +++ b/tools/prom-metrics-collector/metrics_collector.go @@ -0,0 +1,78 @@ +/* + * This file is part of the KubeVirt project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2023 Red Hat, Inc. + * + */ + +package main + +import ( + parser "github.com/kubevirt/monitoring/pkg/metrics/parser" + "kubevirt.io/containerized-data-importer/pkg/monitoring" + + dto "github.com/prometheus/client_model/go" +) + +// excludedMetrics defines the metrics to ignore, +// open issue:https://github.com/kubevirt/containerized-data-importer/issues/2773 +// Do not add metrics to this list! +var excludedMetrics = map[string]struct{}{ + "clone_progress": {}, + "kubevirt_cdi_operator_up_total": {}, + "kubevirt_cdi_incomplete_storageprofiles_total": {}, +} + +func recordRulesDescToMetricList(mdl []monitoring.RecordRulesDesc) []monitoring.MetricOpts { + res := make([]monitoring.MetricOpts, len(mdl)) + for i, md := range mdl { + res[i] = metricDescriptionToMetric(md) + } + + return res +} + +func metricDescriptionToMetric(rrd monitoring.RecordRulesDesc) monitoring.MetricOpts { + return monitoring.MetricOpts{ + Name: rrd.Opts.Name, + Help: rrd.Opts.Help, + Type: rrd.Opts.Type, + } +} + +// ReadMetrics read and parse the metrics to a MetricFamily +func ReadMetrics() []*dto.MetricFamily { + cdiMetrics := recordRulesDescToMetricList(monitoring.GetRecordRulesDesc("")) + for _, opts := range monitoring.MetricOptsList { + cdiMetrics = append(cdiMetrics, opts) + } + metricsList := make([]parser.Metric, len(cdiMetrics)) + var metricFamily []*dto.MetricFamily + for i, cdiMetric := range cdiMetrics { + metricsList[i] = parser.Metric{ + Name: cdiMetric.Name, + Help: cdiMetric.Help, + Type: cdiMetric.Type, + } + } + for _, cdiMetric := range metricsList { + // Remove ignored metrics from all rules + if _, isExcludedMetric := excludedMetrics[cdiMetric.Name]; !isExcludedMetric { + mf := parser.CreateMetricFamily(cdiMetric) + metricFamily = append(metricFamily, mf) + } + } + return metricFamily +} diff --git a/tools/prom-metrics-collector/metrics_json_generator.go b/tools/prom-metrics-collector/metrics_json_generator.go new file mode 100644 index 000000000..f1f01c63c --- /dev/null +++ b/tools/prom-metrics-collector/metrics_json_generator.go @@ -0,0 +1,37 @@ +/* + * This file is part of the KubeVirt project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2023 Red Hat, Inc. + * + */ + +package main + +import ( + "encoding/json" + "fmt" + "os" +) + +func main() { + metricFamilies := ReadMetrics() + + jsonBytes, err := json.Marshal(metricFamilies) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + fmt.Println(string(jsonBytes)) // Write the JSON string to standard output +} diff --git a/vendor/github.com/kubevirt/monitoring/pkg/metrics/parser/metrics_parser.go b/vendor/github.com/kubevirt/monitoring/pkg/metrics/parser/metrics_parser.go new file mode 100644 index 000000000..fd37bf52f --- /dev/null +++ b/vendor/github.com/kubevirt/monitoring/pkg/metrics/parser/metrics_parser.go @@ -0,0 +1,52 @@ +/* + * This file is part of the KubeVirt project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2023 Red Hat, Inc. + * + */ + +package parser + +import ( + dto "github.com/prometheus/client_model/go" +) + +// Metric represents a Prometheus metric +type Metric struct { + Name string `json:"name,omitempty"` + Help string `json:"help,omitempty"` + Type string `json:"type,omitempty"` +} + +// Set the correct metric type for creating MetricFamily +func CreateMetricFamily(m Metric) *dto.MetricFamily { + metricType := dto.MetricType_UNTYPED + + switch m.Type { + case "Counter": + metricType = dto.MetricType_COUNTER + case "Gauge": + metricType = dto.MetricType_GAUGE + case "Histogram": + metricType = dto.MetricType_HISTOGRAM + case "Summary": + metricType = dto.MetricType_SUMMARY + } + + return &dto.MetricFamily{ + Name: &m.Name, + Help: &m.Help, + Type: &metricType, + } +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 17206fd04..bc63e1a69 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -309,6 +309,9 @@ github.com/kubernetes-csi/external-snapshotter/client/v6/clientset/versioned/typ # github.com/kubernetes-csi/lib-volume-populator v1.2.0 ## explicit; go 1.18 github.com/kubernetes-csi/lib-volume-populator/populator-machinery +# github.com/kubevirt/monitoring/pkg/metrics/parser v0.0.0-20230627123556-81a891d4462a +## explicit; go 1.20 +github.com/kubevirt/monitoring/pkg/metrics/parser # github.com/mailru/easyjson v0.7.7 ## explicit; go 1.12 github.com/mailru/easyjson/buffer