diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 00000000..8b5993f9 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,38 @@ +run: + deadline: 5m + +linters: + disable-all: true + enable: + - bodyclose + - dogsled + - dupl + - errcheck + - exportloopref + - gocritic + - gocyclo + - gofmt + - goimports + - gosec + - goprintffuncname + - gosimple + - govet + - ineffassign + - misspell + - nakedret + - nolintlint + - revive + - staticcheck + - typecheck + - unconvert + - unused + - whitespace + +linters-settings: + goimports: + local-prefixes: sigs.k8s.io/prometheus-adapter + revive: + rules: + - name: exported + arguments: + - disableStutteringCheck diff --git a/Makefile b/Makefile index a4a3149d..a058859d 100644 --- a/Makefile +++ b/Makefile @@ -2,12 +2,14 @@ REGISTRY?=gcr.io/k8s-staging-prometheus-adapter IMAGE=prometheus-adapter ARCH?=$(shell go env GOARCH) ALL_ARCH=amd64 arm arm64 ppc64le s390x +GOPATH:=$(shell go env GOPATH) VERSION=$(shell cat VERSION) TAG_PREFIX=v TAG?=$(TAG_PREFIX)$(VERSION) GO_VERSION?=1.18.5 +GOLANGCI_VERSION?=1.50.1 .PHONY: all all: prometheus-adapter @@ -57,21 +59,29 @@ test: # --------------- .PHONY: verify -verify: verify-gofmt verify-deps verify-generated test +verify: verify-lint verify-deps verify-generated .PHONY: update -update: update-generated +update: update-lint update-generated -# Format -# ------ +# Format and lint +# --------------- -.PHONY: verify-gofmt -verify-gofmt: - ./hack/gofmt-all.sh -v +HAS_GOLANGCI_VERSION:=$(shell $(GOPATH)/bin/golangci-lint version --format=short) +.PHONY: golangci +golangci: +ifneq ($(HAS_GOLANGCI_VERSION), $(GOLANGCI_VERSION)) + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOPATH)/bin v$(GOLANGCI_VERSION) +endif + +.PHONY: verify-lint +verify-lint: golangci + $(GOPATH)/bin/golangci-lint run --modules-download-mode=readonly || (echo 'Run "make update-lint"' && exit 1) + +.PHONY: update-lint +update-lint: golangci + $(GOPATH)/bin/golangci-lint run --fix --modules-download-mode=readonly -.PHONY: gofmt -gofmt: - ./hack/gofmt-all.sh # Dependencies # ------------ @@ -88,7 +98,7 @@ verify-deps: generated_files=pkg/api/generated/openapi/zz_generated.openapi.go .PHONY: verify-generated -verify-generated: +verify-generated: update-generated @git diff --exit-code -- $(generated_files) .PHONY: update-generated diff --git a/cmd/adapter/adapter.go b/cmd/adapter/adapter.go index bc85a56c..9c868a53 100644 --- a/cmd/adapter/adapter.go +++ b/cmd/adapter/adapter.go @@ -21,7 +21,6 @@ import ( "crypto/x509" "flag" "fmt" - "io/ioutil" "net/http" "net/url" "os" @@ -93,7 +92,7 @@ func (cmd *PrometheusAdapter) makePromClient() (prom.Client, error) { } if cmd.PrometheusVerb != http.MethodGet && cmd.PrometheusVerb != http.MethodPost { - return nil, fmt.Errorf("unsupported Prometheus HTTP verb %q. use \"GET\" or \"POST\" instead.", cmd.PrometheusVerb) + return nil, fmt.Errorf("unsupported Prometheus HTTP verb %q; supported verbs: \"GET\" and \"POST\"", cmd.PrometheusVerb) } var httpClient *http.Client @@ -115,7 +114,7 @@ func (cmd *PrometheusAdapter) makePromClient() (prom.Client, error) { } if cmd.PrometheusTokenFile != "" { - data, err := ioutil.ReadFile(cmd.PrometheusTokenFile) + data, err := os.ReadFile(cmd.PrometheusTokenFile) if err != nil { return nil, fmt.Errorf("failed to read prometheus-token-file: %v", err) } @@ -392,7 +391,7 @@ func makeKubeconfigHTTPClient(inClusterAuth bool, kubeConfigPath string) (*http. } func makePrometheusCAClient(caFilePath string, tlsCertFilePath string, tlsKeyFilePath string) (*http.Client, error) { - data, err := ioutil.ReadFile(caFilePath) + data, err := os.ReadFile(caFilePath) if err != nil { return nil, fmt.Errorf("failed to read prometheus-ca-file: %v", err) } @@ -409,6 +408,7 @@ func makePrometheusCAClient(caFilePath string, tlsCertFilePath string, tlsKeyFil } return &http.Client{ Transport: &http.Transport{ + //nolint:gosec TLSClientConfig: &tls.Config{ RootCAs: pool, Certificates: []tls.Certificate{tlsClientCerts}, @@ -419,6 +419,7 @@ func makePrometheusCAClient(caFilePath string, tlsCertFilePath string, tlsKeyFil return &http.Client{ Transport: &http.Transport{ + //nolint:gosec TLSClientConfig: &tls.Config{ RootCAs: pool, }, diff --git a/cmd/adapter/adapter_test.go b/cmd/adapter/adapter_test.go index cd636a9d..3cc5f0d4 100644 --- a/cmd/adapter/adapter_test.go +++ b/cmd/adapter/adapter_test.go @@ -27,7 +27,6 @@ import ( const certsDir = "testdata" func TestMakeKubeconfigHTTPClient(t *testing.T) { - tests := []struct { kubeconfigPath string inClusterAuth bool @@ -71,16 +70,13 @@ func TestMakeKubeconfigHTTPClient(t *testing.T) { t.Error("HTTP client Transport is nil, expected http.RoundTripper") } } - } else { - if err == nil { - t.Errorf("Error is nil, expected %v", err) - } + } else if err == nil { + t.Errorf("Error is nil, expected %v", err) } } } func TestMakePrometheusCAClient(t *testing.T) { - tests := []struct { caFilePath string tlsCertFilePath string @@ -140,16 +136,13 @@ func TestMakePrometheusCAClient(t *testing.T) { t.Errorf("TLS certificates is %+v, expected nil", prometheusCAClient.Transport.(*http.Transport).TLSClientConfig.Certificates) } } - } else { - if err == nil { - t.Errorf("Error is nil, expected %v", err) - } + } else if err == nil { + t.Errorf("Error is nil, expected %v", err) } } } func TestParseHeaderArgs(t *testing.T) { - tests := []struct { args []string headers http.Header diff --git a/cmd/config-gen/utils/default.go b/cmd/config-gen/utils/default.go index 39372598..3022c569 100644 --- a/cmd/config-gen/utils/default.go +++ b/cmd/config-gen/utils/default.go @@ -7,7 +7,7 @@ import ( pmodel "github.com/prometheus/common/model" prom "sigs.k8s.io/prometheus-adapter/pkg/client" - . "sigs.k8s.io/prometheus-adapter/pkg/config" + "sigs.k8s.io/prometheus-adapter/pkg/config" ) // DefaultConfig returns a configuration equivalent to the former @@ -15,55 +15,55 @@ import ( // will be of the form `<<.Resource>>`, cadvisor series will be // of the form `container_`, and have the label `pod`. Any series ending // in total will be treated as a rate metric. -func DefaultConfig(rateInterval time.Duration, labelPrefix string) *MetricsDiscoveryConfig { - return &MetricsDiscoveryConfig{ - Rules: []DiscoveryRule{ +func DefaultConfig(rateInterval time.Duration, labelPrefix string) *config.MetricsDiscoveryConfig { + return &config.MetricsDiscoveryConfig{ + Rules: []config.DiscoveryRule{ // container seconds rate metrics { SeriesQuery: string(prom.MatchSeries("", prom.NameMatches("^container_.*"), prom.LabelNeq("container", "POD"), prom.LabelNeq("namespace", ""), prom.LabelNeq("pod", ""))), - Resources: ResourceMapping{ - Overrides: map[string]GroupResource{ + Resources: config.ResourceMapping{ + Overrides: map[string]config.GroupResource{ "namespace": {Resource: "namespace"}, "pod": {Resource: "pod"}, }, }, - Name: NameMapping{Matches: "^container_(.*)_seconds_total$"}, + Name: config.NameMapping{Matches: "^container_(.*)_seconds_total$"}, MetricsQuery: fmt.Sprintf(`sum(rate(<<.Series>>{<<.LabelMatchers>>,container!="POD"}[%s])) by (<<.GroupBy>>)`, pmodel.Duration(rateInterval).String()), }, // container rate metrics { SeriesQuery: string(prom.MatchSeries("", prom.NameMatches("^container_.*"), prom.LabelNeq("container", "POD"), prom.LabelNeq("namespace", ""), prom.LabelNeq("pod", ""))), - SeriesFilters: []RegexFilter{{IsNot: "^container_.*_seconds_total$"}}, - Resources: ResourceMapping{ - Overrides: map[string]GroupResource{ + SeriesFilters: []config.RegexFilter{{IsNot: "^container_.*_seconds_total$"}}, + Resources: config.ResourceMapping{ + Overrides: map[string]config.GroupResource{ "namespace": {Resource: "namespace"}, "pod": {Resource: "pod"}, }, }, - Name: NameMapping{Matches: "^container_(.*)_total$"}, + Name: config.NameMapping{Matches: "^container_(.*)_total$"}, MetricsQuery: fmt.Sprintf(`sum(rate(<<.Series>>{<<.LabelMatchers>>,container!="POD"}[%s])) by (<<.GroupBy>>)`, pmodel.Duration(rateInterval).String()), }, // container non-cumulative metrics { SeriesQuery: string(prom.MatchSeries("", prom.NameMatches("^container_.*"), prom.LabelNeq("container", "POD"), prom.LabelNeq("namespace", ""), prom.LabelNeq("pod", ""))), - SeriesFilters: []RegexFilter{{IsNot: "^container_.*_total$"}}, - Resources: ResourceMapping{ - Overrides: map[string]GroupResource{ + SeriesFilters: []config.RegexFilter{{IsNot: "^container_.*_total$"}}, + Resources: config.ResourceMapping{ + Overrides: map[string]config.GroupResource{ "namespace": {Resource: "namespace"}, "pod": {Resource: "pod"}, }, }, - Name: NameMapping{Matches: "^container_(.*)$"}, + Name: config.NameMapping{Matches: "^container_(.*)$"}, MetricsQuery: `sum(<<.Series>>{<<.LabelMatchers>>,container!="POD"}) by (<<.GroupBy>>)`, }, // normal non-cumulative metrics { SeriesQuery: string(prom.MatchSeries("", prom.LabelNeq(fmt.Sprintf("%snamespace", labelPrefix), ""), prom.NameNotMatches("^container_.*"))), - SeriesFilters: []RegexFilter{{IsNot: ".*_total$"}}, - Resources: ResourceMapping{ + SeriesFilters: []config.RegexFilter{{IsNot: ".*_total$"}}, + Resources: config.ResourceMapping{ Template: fmt.Sprintf("%s<<.Resource>>", labelPrefix), }, MetricsQuery: "sum(<<.Series>>{<<.LabelMatchers>>}) by (<<.GroupBy>>)", @@ -72,9 +72,9 @@ func DefaultConfig(rateInterval time.Duration, labelPrefix string) *MetricsDisco // normal rate metrics { SeriesQuery: string(prom.MatchSeries("", prom.LabelNeq(fmt.Sprintf("%snamespace", labelPrefix), ""), prom.NameNotMatches("^container_.*"))), - SeriesFilters: []RegexFilter{{IsNot: ".*_seconds_total"}}, - Name: NameMapping{Matches: "^(.*)_total$"}, - Resources: ResourceMapping{ + SeriesFilters: []config.RegexFilter{{IsNot: ".*_seconds_total"}}, + Name: config.NameMapping{Matches: "^(.*)_total$"}, + Resources: config.ResourceMapping{ Template: fmt.Sprintf("%s<<.Resource>>", labelPrefix), }, MetricsQuery: fmt.Sprintf("sum(rate(<<.Series>>{<<.LabelMatchers>>}[%s])) by (<<.GroupBy>>)", pmodel.Duration(rateInterval).String()), @@ -83,20 +83,20 @@ func DefaultConfig(rateInterval time.Duration, labelPrefix string) *MetricsDisco // seconds rate metrics { SeriesQuery: string(prom.MatchSeries("", prom.LabelNeq(fmt.Sprintf("%snamespace", labelPrefix), ""), prom.NameNotMatches("^container_.*"))), - Name: NameMapping{Matches: "^(.*)_seconds_total$"}, - Resources: ResourceMapping{ + Name: config.NameMapping{Matches: "^(.*)_seconds_total$"}, + Resources: config.ResourceMapping{ Template: fmt.Sprintf("%s<<.Resource>>", labelPrefix), }, MetricsQuery: fmt.Sprintf("sum(rate(<<.Series>>{<<.LabelMatchers>>}[%s])) by (<<.GroupBy>>)", pmodel.Duration(rateInterval).String()), }, }, - ResourceRules: &ResourceRules{ - CPU: ResourceRule{ + ResourceRules: &config.ResourceRules{ + CPU: config.ResourceRule{ ContainerQuery: fmt.Sprintf("sum(rate(container_cpu_usage_seconds_total{<<.LabelMatchers>>}[%s])) by (<<.GroupBy>>)", pmodel.Duration(rateInterval).String()), NodeQuery: fmt.Sprintf("sum(rate(container_cpu_usage_seconds_total{<<.LabelMatchers>>, id='/'}[%s])) by (<<.GroupBy>>)", pmodel.Duration(rateInterval).String()), - Resources: ResourceMapping{ - Overrides: map[string]GroupResource{ + Resources: config.ResourceMapping{ + Overrides: map[string]config.GroupResource{ "namespace": {Resource: "namespace"}, "pod": {Resource: "pod"}, "instance": {Resource: "node"}, @@ -104,11 +104,11 @@ func DefaultConfig(rateInterval time.Duration, labelPrefix string) *MetricsDisco }, ContainerLabel: fmt.Sprintf("%scontainer", labelPrefix), }, - Memory: ResourceRule{ + Memory: config.ResourceRule{ ContainerQuery: "sum(container_memory_working_set_bytes{<<.LabelMatchers>>}) by (<<.GroupBy>>)", NodeQuery: "sum(container_memory_working_set_bytes{<<.LabelMatchers>>,id='/'}) by (<<.GroupBy>>)", - Resources: ResourceMapping{ - Overrides: map[string]GroupResource{ + Resources: config.ResourceMapping{ + Overrides: map[string]config.GroupResource{ "namespace": {Resource: "namespace"}, "pod": {Resource: "pod"}, "instance": {Resource: "node"}, diff --git a/hack/gofmt-all.sh b/hack/gofmt-all.sh deleted file mode 100755 index 1dbfc344..00000000 --- a/hack/gofmt-all.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -# Copyright 2017 The Kubernetes Authors. -# -# 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. - -set -o errexit -set -o nounset -set -o pipefail - -verify=0 -if [[ ${1:-} = "--verify" || ${1:-} = "-v" ]]; then - verify=1 -fi - -find_files() { - find . -not \( \( \ - -wholename './_output' \ - -o -wholename './vendor' \ - \) -prune \) -name '*.go' -} - -if [[ $verify -eq 1 ]]; then - diff=$(find_files | xargs gofmt -s -d 2>&1) - if [[ -n "${diff}" ]]; then - echo "gofmt -s -w $(echo "${diff}" | awk '/^diff / { print $2 }' | tr '\n' ' ')" - exit 1 - fi -else - find_files | xargs gofmt -s -w -fi diff --git a/pkg/client/api.go b/pkg/client/api.go index 62bf6372..c5ca6032 100644 --- a/pkg/client/api.go +++ b/pkg/client/api.go @@ -21,7 +21,6 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "net/http" "net/url" "path" @@ -61,11 +60,10 @@ func (c *httpAPIClient) Do(ctx context.Context, verb, endpoint string, query url reqBody = strings.NewReader(query.Encode()) } - req, err := http.NewRequest(verb, u.String(), reqBody) + req, err := http.NewRequestWithContext(ctx, verb, u.String(), reqBody) if err != nil { return APIResponse{}, fmt.Errorf("error constructing HTTP request to Prometheus: %v", err) } - req.WithContext(ctx) for key, values := range c.headers { for _, value := range values { req.Header.Add(key, value) @@ -102,7 +100,7 @@ func (c *httpAPIClient) Do(ctx context.Context, verb, endpoint string, query url var body io.Reader = resp.Body if klog.V(8).Enabled() { - data, err := ioutil.ReadAll(body) + data, err := io.ReadAll(body) if err != nil { return APIResponse{}, fmt.Errorf("unable to log response body: %v", err) } @@ -237,7 +235,7 @@ func (h *queryClient) QueryRange(ctx context.Context, r Range, query Selector) ( // when present func timeoutFromContext(ctx context.Context) (time.Duration, bool) { if deadline, hasDeadline := ctx.Deadline(); hasDeadline { - return time.Now().Sub(deadline), true + return time.Since(deadline), true } return time.Duration(0), false diff --git a/pkg/client/helpers.go b/pkg/client/helpers.go index 34544f9f..b12d2296 100644 --- a/pkg/client/helpers.go +++ b/pkg/client/helpers.go @@ -13,6 +13,7 @@ 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. */ + package client import ( diff --git a/pkg/client/interfaces.go b/pkg/client/interfaces.go index cf3cbe04..b8d7fcde 100644 --- a/pkg/client/interfaces.go +++ b/pkg/client/interfaces.go @@ -13,6 +13,7 @@ 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. */ + package client import ( diff --git a/pkg/client/metrics/metrics.go b/pkg/client/metrics/metrics.go index bbebf43a..b54067f2 100644 --- a/pkg/client/metrics/metrics.go +++ b/pkg/client/metrics/metrics.go @@ -13,6 +13,7 @@ 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. */ + package metrics import ( diff --git a/pkg/client/types.go b/pkg/client/types.go index 19dfdf35..02a72469 100644 --- a/pkg/client/types.go +++ b/pkg/client/types.go @@ -25,10 +25,10 @@ type ErrorType string const ( ErrBadData ErrorType = "bad_data" - ErrTimeout = "timeout" - ErrCanceled = "canceled" - ErrExec = "execution" - ErrBadResponse = "bad_response" + ErrTimeout ErrorType = "timeout" + ErrCanceled ErrorType = "canceled" + ErrExec ErrorType = "execution" + ErrBadResponse ErrorType = "bad_response" ) // Error is an error returned by the API. @@ -46,7 +46,7 @@ type ResponseStatus string const ( ResponseSucceeded ResponseStatus = "succeeded" - ResponseError = "error" + ResponseError ResponseStatus = "error" ) // APIResponse represents the raw response returned by the API. diff --git a/pkg/config/loader.go b/pkg/config/loader.go index 5d0a7166..2c716887 100644 --- a/pkg/config/loader.go +++ b/pkg/config/loader.go @@ -2,7 +2,7 @@ package config import ( "fmt" - "io/ioutil" + "io" "os" yaml "gopkg.in/yaml.v2" @@ -15,7 +15,7 @@ func FromFile(filename string) (*MetricsDiscoveryConfig, error) { return nil, fmt.Errorf("unable to load metrics discovery config file: %v", err) } defer file.Close() - contents, err := ioutil.ReadAll(file) + contents, err := io.ReadAll(file) if err != nil { return nil, fmt.Errorf("unable to load metrics discovery config file: %v", err) } diff --git a/pkg/custom-provider/provider.go b/pkg/custom-provider/provider.go index 4dbe68e6..989042d5 100644 --- a/pkg/custom-provider/provider.go +++ b/pkg/custom-provider/provider.go @@ -99,7 +99,7 @@ func (p *prometheusProvider) metricFor(value pmodel.SampleValue, name types.Name Name: info.Metric, }, // TODO(directxman12): use the right timestamp - Timestamp: metav1.Time{time.Now()}, + Timestamp: metav1.Time{Time: time.Now()}, Value: *q, } @@ -256,7 +256,7 @@ func (l *cachingMetricsLister) updateMetrics() error { } selectors[sel] = struct{}{} go func() { - series, err := l.promClient.Series(context.TODO(), pmodel.Interval{startTime, 0}, sel) + series, err := l.promClient.Series(context.TODO(), pmodel.Interval{Start: startTime, End: 0}, sel) if err != nil { errs <- fmt.Errorf("unable to fetch metrics for query %q: %v", sel, err) return diff --git a/pkg/custom-provider/provider_test.go b/pkg/custom-provider/provider_test.go index da274baf..9d144004 100644 --- a/pkg/custom-provider/provider_test.go +++ b/pkg/custom-provider/provider_test.go @@ -87,7 +87,7 @@ var _ = Describe("Custom Metrics Provider", func() { By("ensuring that no metrics are present before we start listing") Expect(prov.ListAllMetrics()).To(BeEmpty()) - By("setting the acceptible interval to now until the next update, with a bit of wiggle room") + By("setting the acceptable interval to now until the next update, with a bit of wiggle room") startTime := pmodel.Now().Add(-1*fakeProviderUpdateInterval - fakeProviderUpdateInterval/10) fakeProm.AcceptableInterval = pmodel.Interval{Start: startTime, End: 0} @@ -98,16 +98,16 @@ var _ = Describe("Custom Metrics Provider", func() { By("listing all metrics, and checking that they contain the expected results") Expect(prov.ListAllMetrics()).To(ConsistOf( - provider.CustomMetricInfo{schema.GroupResource{Resource: "services"}, true, "ingress_hits"}, - provider.CustomMetricInfo{schema.GroupResource{Group: "extensions", Resource: "ingresses"}, true, "ingress_hits"}, - provider.CustomMetricInfo{schema.GroupResource{Resource: "pods"}, true, "ingress_hits"}, - provider.CustomMetricInfo{schema.GroupResource{Resource: "namespaces"}, false, "ingress_hits"}, - provider.CustomMetricInfo{schema.GroupResource{Resource: "services"}, true, "service_proxy_packets"}, - provider.CustomMetricInfo{schema.GroupResource{Resource: "namespaces"}, false, "service_proxy_packets"}, - provider.CustomMetricInfo{schema.GroupResource{Group: "extensions", Resource: "deployments"}, true, "work_queue_wait"}, - provider.CustomMetricInfo{schema.GroupResource{Resource: "namespaces"}, false, "work_queue_wait"}, - provider.CustomMetricInfo{schema.GroupResource{Resource: "namespaces"}, false, "some_usage"}, - provider.CustomMetricInfo{schema.GroupResource{Resource: "pods"}, true, "some_usage"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "services"}, Namespaced: true, Metric: "ingress_hits"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Group: "extensions", Resource: "ingresses"}, Namespaced: true, Metric: "ingress_hits"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "pods"}, Namespaced: true, Metric: "ingress_hits"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "namespaces"}, Namespaced: false, Metric: "ingress_hits"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "services"}, Namespaced: true, Metric: "service_proxy_packets"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "namespaces"}, Namespaced: false, Metric: "service_proxy_packets"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Group: "extensions", Resource: "deployments"}, Namespaced: true, Metric: "work_queue_wait"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "namespaces"}, Namespaced: false, Metric: "work_queue_wait"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "namespaces"}, Namespaced: false, Metric: "some_usage"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "pods"}, Namespaced: true, Metric: "some_usage"}, )) }) }) diff --git a/pkg/custom-provider/series_registry_test.go b/pkg/custom-provider/series_registry_test.go index b4bbe7cc..09e440a7 100644 --- a/pkg/custom-provider/series_registry_test.go +++ b/pkg/custom-provider/series_registry_test.go @@ -84,7 +84,7 @@ var seriesRegistryTestSeries = [][]prom.Series{ }, }, { - // guage metrics + // gauge metrics { Name: "node_gigawatts", Labels: pmodel.LabelSet{"kube_node": "somenode"}, @@ -159,7 +159,7 @@ var _ = Describe("Series Registry", func() { // container metrics { title: "container metrics gauge / multiple resource names", - info: provider.CustomMetricInfo{schema.GroupResource{Resource: "pods"}, true, "some_usage"}, + info: provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "pods"}, Namespaced: true, Metric: "some_usage"}, namespace: "somens", resourceNames: []string{"somepod1", "somepod2"}, metricSelector: labels.Everything(), @@ -168,7 +168,7 @@ var _ = Describe("Series Registry", func() { }, { title: "container metrics counter", - info: provider.CustomMetricInfo{schema.GroupResource{Resource: "pods"}, true, "some_count"}, + info: provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "pods"}, Namespaced: true, Metric: "some_count"}, namespace: "somens", resourceNames: []string{"somepod1", "somepod2"}, metricSelector: labels.Everything(), @@ -177,7 +177,7 @@ var _ = Describe("Series Registry", func() { }, { title: "container metrics seconds counter", - info: provider.CustomMetricInfo{schema.GroupResource{Resource: "pods"}, true, "some_time"}, + info: provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "pods"}, Namespaced: true, Metric: "some_time"}, namespace: "somens", resourceNames: []string{"somepod1", "somepod2"}, metricSelector: labels.Everything(), @@ -187,7 +187,7 @@ var _ = Describe("Series Registry", func() { // namespaced metrics { title: "namespaced metrics counter / multidimensional (service)", - info: provider.CustomMetricInfo{schema.GroupResource{Resource: "service"}, true, "ingress_hits"}, + info: provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "service"}, Namespaced: true, Metric: "ingress_hits"}, namespace: "somens", resourceNames: []string{"somesvc"}, metricSelector: labels.Everything(), @@ -196,7 +196,7 @@ var _ = Describe("Series Registry", func() { }, { title: "namespaced metrics counter / multidimensional (service) / selection using labels", - info: provider.CustomMetricInfo{schema.GroupResource{Resource: "service"}, true, "ingress_hits"}, + info: provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "service"}, Namespaced: true, Metric: "ingress_hits"}, namespace: "somens", resourceNames: []string{"somesvc"}, metricSelector: labels.NewSelector().Add( @@ -206,7 +206,7 @@ var _ = Describe("Series Registry", func() { }, { title: "namespaced metrics counter / multidimensional (ingress)", - info: provider.CustomMetricInfo{schema.GroupResource{Group: "extensions", Resource: "ingress"}, true, "ingress_hits"}, + info: provider.CustomMetricInfo{GroupResource: schema.GroupResource{Group: "extensions", Resource: "ingress"}, Namespaced: true, Metric: "ingress_hits"}, namespace: "somens", resourceNames: []string{"someingress"}, metricSelector: labels.Everything(), @@ -215,7 +215,7 @@ var _ = Describe("Series Registry", func() { }, { title: "namespaced metrics counter / multidimensional (pod)", - info: provider.CustomMetricInfo{schema.GroupResource{Resource: "pod"}, true, "ingress_hits"}, + info: provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "pod"}, Namespaced: true, Metric: "ingress_hits"}, namespace: "somens", resourceNames: []string{"somepod"}, metricSelector: labels.Everything(), @@ -224,7 +224,7 @@ var _ = Describe("Series Registry", func() { }, { title: "namespaced metrics gauge", - info: provider.CustomMetricInfo{schema.GroupResource{Resource: "service"}, true, "service_proxy_packets"}, + info: provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "service"}, Namespaced: true, Metric: "service_proxy_packets"}, namespace: "somens", resourceNames: []string{"somesvc"}, metricSelector: labels.Everything(), @@ -233,7 +233,7 @@ var _ = Describe("Series Registry", func() { }, { title: "namespaced metrics seconds counter", - info: provider.CustomMetricInfo{schema.GroupResource{Group: "extensions", Resource: "deployment"}, true, "work_queue_wait"}, + info: provider.CustomMetricInfo{GroupResource: schema.GroupResource{Group: "extensions", Resource: "deployment"}, Namespaced: true, Metric: "work_queue_wait"}, namespace: "somens", resourceNames: []string{"somedep"}, metricSelector: labels.Everything(), @@ -243,7 +243,7 @@ var _ = Describe("Series Registry", func() { // non-namespaced series { title: "root scoped metrics gauge", - info: provider.CustomMetricInfo{schema.GroupResource{Resource: "node"}, false, "node_gigawatts"}, + info: provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "node"}, Namespaced: false, Metric: "node_gigawatts"}, resourceNames: []string{"somenode"}, metricSelector: labels.Everything(), @@ -251,7 +251,7 @@ var _ = Describe("Series Registry", func() { }, { title: "root scoped metrics counter", - info: provider.CustomMetricInfo{schema.GroupResource{Resource: "persistentvolume"}, false, "volume_claims"}, + info: provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "persistentvolume"}, Namespaced: false, Metric: "volume_claims"}, resourceNames: []string{"somepv"}, metricSelector: labels.Everything(), @@ -259,7 +259,7 @@ var _ = Describe("Series Registry", func() { }, { title: "root scoped metrics seconds counter", - info: provider.CustomMetricInfo{schema.GroupResource{Resource: "node"}, false, "node_fan"}, + info: provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "node"}, Namespaced: false, Metric: "node_fan"}, resourceNames: []string{"somenode"}, metricSelector: labels.Everything(), @@ -281,23 +281,23 @@ var _ = Describe("Series Registry", func() { It("should list all metrics", func() { Expect(registry.ListAllMetrics()).To(ConsistOf( - provider.CustomMetricInfo{schema.GroupResource{Resource: "pods"}, true, "some_count"}, - provider.CustomMetricInfo{schema.GroupResource{Resource: "namespaces"}, false, "some_count"}, - provider.CustomMetricInfo{schema.GroupResource{Resource: "pods"}, true, "some_time"}, - provider.CustomMetricInfo{schema.GroupResource{Resource: "namespaces"}, false, "some_time"}, - provider.CustomMetricInfo{schema.GroupResource{Resource: "pods"}, true, "some_usage"}, - provider.CustomMetricInfo{schema.GroupResource{Resource: "namespaces"}, false, "some_usage"}, - provider.CustomMetricInfo{schema.GroupResource{Resource: "services"}, true, "ingress_hits"}, - provider.CustomMetricInfo{schema.GroupResource{Group: "extensions", Resource: "ingresses"}, true, "ingress_hits"}, - provider.CustomMetricInfo{schema.GroupResource{Resource: "pods"}, true, "ingress_hits"}, - provider.CustomMetricInfo{schema.GroupResource{Resource: "namespaces"}, false, "ingress_hits"}, - provider.CustomMetricInfo{schema.GroupResource{Resource: "services"}, true, "service_proxy_packets"}, - provider.CustomMetricInfo{schema.GroupResource{Resource: "namespaces"}, false, "service_proxy_packets"}, - provider.CustomMetricInfo{schema.GroupResource{Group: "extensions", Resource: "deployments"}, true, "work_queue_wait"}, - provider.CustomMetricInfo{schema.GroupResource{Resource: "namespaces"}, false, "work_queue_wait"}, - provider.CustomMetricInfo{schema.GroupResource{Resource: "nodes"}, false, "node_gigawatts"}, - provider.CustomMetricInfo{schema.GroupResource{Resource: "persistentvolumes"}, false, "volume_claims"}, - provider.CustomMetricInfo{schema.GroupResource{Resource: "nodes"}, false, "node_fan"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "pods"}, Namespaced: true, Metric: "some_count"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "namespaces"}, Namespaced: false, Metric: "some_count"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "pods"}, Namespaced: true, Metric: "some_time"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "namespaces"}, Namespaced: false, Metric: "some_time"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "pods"}, Namespaced: true, Metric: "some_usage"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "namespaces"}, Namespaced: false, Metric: "some_usage"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "services"}, Namespaced: true, Metric: "ingress_hits"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Group: "extensions", Resource: "ingresses"}, Namespaced: true, Metric: "ingress_hits"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "pods"}, Namespaced: true, Metric: "ingress_hits"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "namespaces"}, Namespaced: false, Metric: "ingress_hits"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "services"}, Namespaced: true, Metric: "service_proxy_packets"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "namespaces"}, Namespaced: false, Metric: "service_proxy_packets"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Group: "extensions", Resource: "deployments"}, Namespaced: true, Metric: "work_queue_wait"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "namespaces"}, Namespaced: false, Metric: "work_queue_wait"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "nodes"}, Namespaced: false, Metric: "node_gigawatts"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "persistentvolumes"}, Namespaced: false, Metric: "volume_claims"}, + provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "nodes"}, Namespaced: false, Metric: "node_fan"}, )) }) }) diff --git a/pkg/external-provider/basic_metric_lister.go b/pkg/external-provider/basic_metric_lister.go index 4afef158..ea8adeb6 100644 --- a/pkg/external-provider/basic_metric_lister.go +++ b/pkg/external-provider/basic_metric_lister.go @@ -100,7 +100,7 @@ func (l *basicMetricLister) ListAllMetrics() (MetricUpdateResult, error) { } selectors[sel] = struct{}{} go func() { - series, err := l.promClient.Series(context.TODO(), pmodel.Interval{startTime, 0}, sel) + series, err := l.promClient.Series(context.TODO(), pmodel.Interval{Start: startTime, End: 0}, sel) if err != nil { errs <- fmt.Errorf("unable to fetch metrics for query %q: %v", sel, err) return diff --git a/pkg/external-provider/external_series_registry.go b/pkg/external-provider/external_series_registry.go index bdc6ea9d..e58475a8 100644 --- a/pkg/external-provider/external_series_registry.go +++ b/pkg/external-provider/external_series_registry.go @@ -103,7 +103,6 @@ func (r *externalSeriesRegistry) filterAndStoreMetrics(result MetricUpdateResult r.metrics = apiMetricsCache r.metricsInfo = rawMetricsCache - } func (r *externalSeriesRegistry) ListAllMetrics() []provider.ExternalMetricInfo { diff --git a/pkg/external-provider/metric_converter.go b/pkg/external-provider/metric_converter.go index 34911765..9e7863df 100644 --- a/pkg/external-provider/metric_converter.go +++ b/pkg/external-provider/metric_converter.go @@ -61,7 +61,7 @@ func (c *metricConverter) convertSample(info provider.ExternalMetricInfo, sample singleMetric := external_metrics.ExternalMetricValue{ MetricName: info.Metric, Timestamp: metav1.Time{ - sample.Timestamp.Time(), + Time: sample.Timestamp.Time(), }, Value: *resource.NewMilliQuantity(int64(sample.Value*1000.0), resource.DecimalSI), MetricLabels: labels, @@ -133,7 +133,7 @@ func (c *metricConverter) convertScalar(info provider.ExternalMetricInfo, queryR { MetricName: info.Metric, Timestamp: metav1.Time{ - toConvert.Timestamp.Time(), + Time: toConvert.Timestamp.Time(), }, Value: *resource.NewMilliQuantity(int64(toConvert.Value*1000.0), resource.DecimalSI), }, diff --git a/pkg/external-provider/periodic_metric_lister.go b/pkg/external-provider/periodic_metric_lister.go index 5a719490..b7320e26 100644 --- a/pkg/external-provider/periodic_metric_lister.go +++ b/pkg/external-provider/periodic_metric_lister.go @@ -69,9 +69,9 @@ func (l *periodicMetricLister) updateMetrics() error { return err } - //Cache the result. + // Cache the result. l.mostRecentResult = result - //Let our listeners know we've got new data ready for them. + // Let our listeners know we've got new data ready for them. l.notifyListeners() return nil } @@ -85,5 +85,7 @@ func (l *periodicMetricLister) notifyListeners() { } func (l *periodicMetricLister) UpdateNow() { - l.updateMetrics() + if err := l.updateMetrics(); err != nil { + utilruntime.HandleError(err) + } } diff --git a/pkg/naming/lbl_res.go b/pkg/naming/lbl_res.go index 17e93fd2..59bee000 100644 --- a/pkg/naming/lbl_res.go +++ b/pkg/naming/lbl_res.go @@ -22,7 +22,6 @@ import ( "regexp" "text/template" - apimeta "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime/schema" pmodel "github.com/prometheus/common/model" @@ -34,7 +33,6 @@ type labelGroupResExtractor struct { resourceInd int groupInd *int - mapper apimeta.RESTMapper } // newLabelGroupResExtractor creates a new labelGroupResExtractor for labels whose form @@ -42,7 +40,10 @@ type labelGroupResExtractor struct { // so anything in the template which limits resource or group name length will cause issues. func newLabelGroupResExtractor(labelTemplate *template.Template) (*labelGroupResExtractor, error) { labelRegexBuff := new(bytes.Buffer) - if err := labelTemplate.Execute(labelRegexBuff, schema.GroupResource{"(?P.+?)", "(?P.+?)"}); err != nil { + if err := labelTemplate.Execute(labelRegexBuff, schema.GroupResource{ + Group: "(?P.+?)", + Resource: "(?P.+?)"}, + ); err != nil { return nil, fmt.Errorf("unable to convert label template to matcher: %v", err) } if labelRegexBuff.Len() == 0 { diff --git a/pkg/naming/metric_namer.go b/pkg/naming/metric_namer.go index f2d7213d..dc241290 100644 --- a/pkg/naming/metric_namer.go +++ b/pkg/naming/metric_namer.go @@ -194,13 +194,14 @@ func NamersFromConfig(cfg []config.DiscoveryRule, mapper apimeta.RESTMapper) ([] if nameAs == "" { // check if we have an obvious default subexpNames := nameMatches.SubexpNames() - if len(subexpNames) == 1 { + switch len(subexpNames) { + case 1: // no capture groups, use the whole thing nameAs = "$0" - } else if len(subexpNames) == 2 { + case 2: // one capture group, use that nameAs = "$1" - } else { + default: return nil, fmt.Errorf("must specify an 'as' value for name matcher %q associated with series query %q", rule.Name.Matches, rule.SeriesQuery) } } diff --git a/pkg/naming/metrics_query.go b/pkg/naming/metrics_query.go index 7aa89c0d..13b0bf03 100644 --- a/pkg/naming/metrics_query.go +++ b/pkg/naming/metrics_query.go @@ -283,9 +283,8 @@ func (q *metricsQuery) processQueryParts(queryParts []queryPart) ([]string, map[ } func (q *metricsQuery) selectMatcher(operator selection.Operator, values []string) (func(string, string) string, error) { - - numValues := len(values) - if numValues == 0 { + switch len(values) { + case 0: switch operator { case selection.Exists: return prom.LabelNeq, nil @@ -294,7 +293,7 @@ func (q *metricsQuery) selectMatcher(operator selection.Operator, values []strin case selection.Equals, selection.DoubleEquals, selection.NotEquals, selection.In, selection.NotIn: return nil, ErrMalformedQuery } - } else if numValues == 1 { + case 1: switch operator { case selection.Equals, selection.DoubleEquals: return prom.LabelEq, nil @@ -305,7 +304,7 @@ func (q *metricsQuery) selectMatcher(operator selection.Operator, values []strin case selection.DoesNotExist, selection.NotIn: return prom.LabelNotMatches, nil } - } else { + default: // Since labels can only have one value, providing multiple // values results in a regex match, even if that's not what the user // asked for. @@ -321,8 +320,8 @@ func (q *metricsQuery) selectMatcher(operator selection.Operator, values []strin } func (q *metricsQuery) selectTargetValue(operator selection.Operator, values []string) (string, error) { - numValues := len(values) - if numValues == 0 { + switch len(values) { + case 0: switch operator { case selection.Exists, selection.DoesNotExist: // Return an empty string when values are equal to 0 @@ -334,7 +333,7 @@ func (q *metricsQuery) selectTargetValue(operator selection.Operator, values []s case selection.Equals, selection.DoubleEquals, selection.NotEquals, selection.In, selection.NotIn: return "", ErrMalformedQuery } - } else if numValues == 1 { + case 1: switch operator { case selection.Equals, selection.DoubleEquals, selection.NotEquals, selection.In, selection.NotIn: // Pass the value through as-is. @@ -347,7 +346,7 @@ func (q *metricsQuery) selectTargetValue(operator selection.Operator, values []s case selection.Exists, selection.DoesNotExist: return "", ErrQueryUnsupportedValues } - } else { + default: switch operator { case selection.Equals, selection.DoubleEquals, selection.NotEquals, selection.In, selection.NotIn: // Pass the value through as-is. diff --git a/pkg/resourceprovider/provider.go b/pkg/resourceprovider/provider.go index ff274092..a56f4d43 100644 --- a/pkg/resourceprovider/provider.go +++ b/pkg/resourceprovider/provider.go @@ -72,7 +72,6 @@ func newResourceQuery(cfg config.ResourceRule, mapper apimeta.RESTMapper) (resou nodeQuery: nodeQuery, containerLabel: cfg.ContainerLabel, }, nil - } // resourceQuery represents query information for querying resource metrics for some resource,