Use Golangci-lint

This commit is contained in:
Olivier Lemasle 2022-11-09 21:52:24 +01:00
parent fdfecc8d7f
commit 0ea1c1b8d3
23 changed files with 177 additions and 174 deletions

38
.golangci.yml Normal file
View file

@ -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

View file

@ -2,12 +2,14 @@ REGISTRY?=gcr.io/k8s-staging-prometheus-adapter
IMAGE=prometheus-adapter IMAGE=prometheus-adapter
ARCH?=$(shell go env GOARCH) ARCH?=$(shell go env GOARCH)
ALL_ARCH=amd64 arm arm64 ppc64le s390x ALL_ARCH=amd64 arm arm64 ppc64le s390x
GOPATH:=$(shell go env GOPATH)
VERSION=$(shell cat VERSION) VERSION=$(shell cat VERSION)
TAG_PREFIX=v TAG_PREFIX=v
TAG?=$(TAG_PREFIX)$(VERSION) TAG?=$(TAG_PREFIX)$(VERSION)
GO_VERSION?=1.18.5 GO_VERSION?=1.18.5
GOLANGCI_VERSION?=1.50.1
.PHONY: all .PHONY: all
all: prometheus-adapter all: prometheus-adapter
@ -57,21 +59,29 @@ test:
# --------------- # ---------------
.PHONY: verify .PHONY: verify
verify: verify-gofmt verify-deps verify-generated test verify: verify-lint verify-deps verify-generated
.PHONY: update .PHONY: update
update: update-generated update: update-lint update-generated
# Format # Format and lint
# ------ # ---------------
.PHONY: verify-gofmt HAS_GOLANGCI_VERSION:=$(shell $(GOPATH)/bin/golangci-lint version --format=short)
verify-gofmt: .PHONY: golangci
./hack/gofmt-all.sh -v 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 # Dependencies
# ------------ # ------------
@ -88,7 +98,7 @@ verify-deps:
generated_files=pkg/api/generated/openapi/zz_generated.openapi.go generated_files=pkg/api/generated/openapi/zz_generated.openapi.go
.PHONY: verify-generated .PHONY: verify-generated
verify-generated: verify-generated: update-generated
@git diff --exit-code -- $(generated_files) @git diff --exit-code -- $(generated_files)
.PHONY: update-generated .PHONY: update-generated

View file

@ -21,7 +21,6 @@ import (
"crypto/x509" "crypto/x509"
"flag" "flag"
"fmt" "fmt"
"io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
@ -93,7 +92,7 @@ func (cmd *PrometheusAdapter) makePromClient() (prom.Client, error) {
} }
if cmd.PrometheusVerb != http.MethodGet && cmd.PrometheusVerb != http.MethodPost { 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 var httpClient *http.Client
@ -115,7 +114,7 @@ func (cmd *PrometheusAdapter) makePromClient() (prom.Client, error) {
} }
if cmd.PrometheusTokenFile != "" { if cmd.PrometheusTokenFile != "" {
data, err := ioutil.ReadFile(cmd.PrometheusTokenFile) data, err := os.ReadFile(cmd.PrometheusTokenFile)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to read prometheus-token-file: %v", err) 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) { func makePrometheusCAClient(caFilePath string, tlsCertFilePath string, tlsKeyFilePath string) (*http.Client, error) {
data, err := ioutil.ReadFile(caFilePath) data, err := os.ReadFile(caFilePath)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to read prometheus-ca-file: %v", err) 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{ return &http.Client{
Transport: &http.Transport{ Transport: &http.Transport{
//nolint:gosec
TLSClientConfig: &tls.Config{ TLSClientConfig: &tls.Config{
RootCAs: pool, RootCAs: pool,
Certificates: []tls.Certificate{tlsClientCerts}, Certificates: []tls.Certificate{tlsClientCerts},
@ -419,6 +419,7 @@ func makePrometheusCAClient(caFilePath string, tlsCertFilePath string, tlsKeyFil
return &http.Client{ return &http.Client{
Transport: &http.Transport{ Transport: &http.Transport{
//nolint:gosec
TLSClientConfig: &tls.Config{ TLSClientConfig: &tls.Config{
RootCAs: pool, RootCAs: pool,
}, },

View file

@ -27,7 +27,6 @@ import (
const certsDir = "testdata" const certsDir = "testdata"
func TestMakeKubeconfigHTTPClient(t *testing.T) { func TestMakeKubeconfigHTTPClient(t *testing.T) {
tests := []struct { tests := []struct {
kubeconfigPath string kubeconfigPath string
inClusterAuth bool inClusterAuth bool
@ -71,16 +70,13 @@ func TestMakeKubeconfigHTTPClient(t *testing.T) {
t.Error("HTTP client Transport is nil, expected http.RoundTripper") t.Error("HTTP client Transport is nil, expected http.RoundTripper")
} }
} }
} else { } else if err == nil {
if err == nil {
t.Errorf("Error is nil, expected %v", err) t.Errorf("Error is nil, expected %v", err)
} }
} }
} }
}
func TestMakePrometheusCAClient(t *testing.T) { func TestMakePrometheusCAClient(t *testing.T) {
tests := []struct { tests := []struct {
caFilePath string caFilePath string
tlsCertFilePath 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) t.Errorf("TLS certificates is %+v, expected nil", prometheusCAClient.Transport.(*http.Transport).TLSClientConfig.Certificates)
} }
} }
} else { } else if err == nil {
if err == nil {
t.Errorf("Error is nil, expected %v", err) t.Errorf("Error is nil, expected %v", err)
} }
} }
} }
}
func TestParseHeaderArgs(t *testing.T) { func TestParseHeaderArgs(t *testing.T) {
tests := []struct { tests := []struct {
args []string args []string
headers http.Header headers http.Header

View file

@ -7,7 +7,7 @@ import (
pmodel "github.com/prometheus/common/model" pmodel "github.com/prometheus/common/model"
prom "sigs.k8s.io/prometheus-adapter/pkg/client" 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 // DefaultConfig returns a configuration equivalent to the former
@ -15,55 +15,55 @@ import (
// will be of the form `<prefix><<.Resource>>`, cadvisor series will be // will be of the form `<prefix><<.Resource>>`, cadvisor series will be
// of the form `container_`, and have the label `pod`. Any series ending // of the form `container_`, and have the label `pod`. Any series ending
// in total will be treated as a rate metric. // in total will be treated as a rate metric.
func DefaultConfig(rateInterval time.Duration, labelPrefix string) *MetricsDiscoveryConfig { func DefaultConfig(rateInterval time.Duration, labelPrefix string) *config.MetricsDiscoveryConfig {
return &MetricsDiscoveryConfig{ return &config.MetricsDiscoveryConfig{
Rules: []DiscoveryRule{ Rules: []config.DiscoveryRule{
// container seconds rate metrics // container seconds rate metrics
{ {
SeriesQuery: string(prom.MatchSeries("", prom.NameMatches("^container_.*"), prom.LabelNeq("container", "POD"), prom.LabelNeq("namespace", ""), prom.LabelNeq("pod", ""))), SeriesQuery: string(prom.MatchSeries("", prom.NameMatches("^container_.*"), prom.LabelNeq("container", "POD"), prom.LabelNeq("namespace", ""), prom.LabelNeq("pod", ""))),
Resources: ResourceMapping{ Resources: config.ResourceMapping{
Overrides: map[string]GroupResource{ Overrides: map[string]config.GroupResource{
"namespace": {Resource: "namespace"}, "namespace": {Resource: "namespace"},
"pod": {Resource: "pod"}, "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()), MetricsQuery: fmt.Sprintf(`sum(rate(<<.Series>>{<<.LabelMatchers>>,container!="POD"}[%s])) by (<<.GroupBy>>)`, pmodel.Duration(rateInterval).String()),
}, },
// container rate metrics // container rate metrics
{ {
SeriesQuery: string(prom.MatchSeries("", prom.NameMatches("^container_.*"), prom.LabelNeq("container", "POD"), prom.LabelNeq("namespace", ""), prom.LabelNeq("pod", ""))), SeriesQuery: string(prom.MatchSeries("", prom.NameMatches("^container_.*"), prom.LabelNeq("container", "POD"), prom.LabelNeq("namespace", ""), prom.LabelNeq("pod", ""))),
SeriesFilters: []RegexFilter{{IsNot: "^container_.*_seconds_total$"}}, SeriesFilters: []config.RegexFilter{{IsNot: "^container_.*_seconds_total$"}},
Resources: ResourceMapping{ Resources: config.ResourceMapping{
Overrides: map[string]GroupResource{ Overrides: map[string]config.GroupResource{
"namespace": {Resource: "namespace"}, "namespace": {Resource: "namespace"},
"pod": {Resource: "pod"}, "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()), MetricsQuery: fmt.Sprintf(`sum(rate(<<.Series>>{<<.LabelMatchers>>,container!="POD"}[%s])) by (<<.GroupBy>>)`, pmodel.Duration(rateInterval).String()),
}, },
// container non-cumulative metrics // container non-cumulative metrics
{ {
SeriesQuery: string(prom.MatchSeries("", prom.NameMatches("^container_.*"), prom.LabelNeq("container", "POD"), prom.LabelNeq("namespace", ""), prom.LabelNeq("pod", ""))), SeriesQuery: string(prom.MatchSeries("", prom.NameMatches("^container_.*"), prom.LabelNeq("container", "POD"), prom.LabelNeq("namespace", ""), prom.LabelNeq("pod", ""))),
SeriesFilters: []RegexFilter{{IsNot: "^container_.*_total$"}}, SeriesFilters: []config.RegexFilter{{IsNot: "^container_.*_total$"}},
Resources: ResourceMapping{ Resources: config.ResourceMapping{
Overrides: map[string]GroupResource{ Overrides: map[string]config.GroupResource{
"namespace": {Resource: "namespace"}, "namespace": {Resource: "namespace"},
"pod": {Resource: "pod"}, "pod": {Resource: "pod"},
}, },
}, },
Name: NameMapping{Matches: "^container_(.*)$"}, Name: config.NameMapping{Matches: "^container_(.*)$"},
MetricsQuery: `sum(<<.Series>>{<<.LabelMatchers>>,container!="POD"}) by (<<.GroupBy>>)`, MetricsQuery: `sum(<<.Series>>{<<.LabelMatchers>>,container!="POD"}) by (<<.GroupBy>>)`,
}, },
// normal non-cumulative metrics // normal non-cumulative metrics
{ {
SeriesQuery: string(prom.MatchSeries("", prom.LabelNeq(fmt.Sprintf("%snamespace", labelPrefix), ""), prom.NameNotMatches("^container_.*"))), SeriesQuery: string(prom.MatchSeries("", prom.LabelNeq(fmt.Sprintf("%snamespace", labelPrefix), ""), prom.NameNotMatches("^container_.*"))),
SeriesFilters: []RegexFilter{{IsNot: ".*_total$"}}, SeriesFilters: []config.RegexFilter{{IsNot: ".*_total$"}},
Resources: ResourceMapping{ Resources: config.ResourceMapping{
Template: fmt.Sprintf("%s<<.Resource>>", labelPrefix), Template: fmt.Sprintf("%s<<.Resource>>", labelPrefix),
}, },
MetricsQuery: "sum(<<.Series>>{<<.LabelMatchers>>}) by (<<.GroupBy>>)", MetricsQuery: "sum(<<.Series>>{<<.LabelMatchers>>}) by (<<.GroupBy>>)",
@ -72,9 +72,9 @@ func DefaultConfig(rateInterval time.Duration, labelPrefix string) *MetricsDisco
// normal rate metrics // normal rate metrics
{ {
SeriesQuery: string(prom.MatchSeries("", prom.LabelNeq(fmt.Sprintf("%snamespace", labelPrefix), ""), prom.NameNotMatches("^container_.*"))), SeriesQuery: string(prom.MatchSeries("", prom.LabelNeq(fmt.Sprintf("%snamespace", labelPrefix), ""), prom.NameNotMatches("^container_.*"))),
SeriesFilters: []RegexFilter{{IsNot: ".*_seconds_total"}}, SeriesFilters: []config.RegexFilter{{IsNot: ".*_seconds_total"}},
Name: NameMapping{Matches: "^(.*)_total$"}, Name: config.NameMapping{Matches: "^(.*)_total$"},
Resources: ResourceMapping{ Resources: config.ResourceMapping{
Template: fmt.Sprintf("%s<<.Resource>>", labelPrefix), Template: fmt.Sprintf("%s<<.Resource>>", labelPrefix),
}, },
MetricsQuery: fmt.Sprintf("sum(rate(<<.Series>>{<<.LabelMatchers>>}[%s])) by (<<.GroupBy>>)", pmodel.Duration(rateInterval).String()), 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 // seconds rate metrics
{ {
SeriesQuery: string(prom.MatchSeries("", prom.LabelNeq(fmt.Sprintf("%snamespace", labelPrefix), ""), prom.NameNotMatches("^container_.*"))), SeriesQuery: string(prom.MatchSeries("", prom.LabelNeq(fmt.Sprintf("%snamespace", labelPrefix), ""), prom.NameNotMatches("^container_.*"))),
Name: NameMapping{Matches: "^(.*)_seconds_total$"}, Name: config.NameMapping{Matches: "^(.*)_seconds_total$"},
Resources: ResourceMapping{ Resources: config.ResourceMapping{
Template: fmt.Sprintf("%s<<.Resource>>", labelPrefix), Template: fmt.Sprintf("%s<<.Resource>>", labelPrefix),
}, },
MetricsQuery: fmt.Sprintf("sum(rate(<<.Series>>{<<.LabelMatchers>>}[%s])) by (<<.GroupBy>>)", pmodel.Duration(rateInterval).String()), MetricsQuery: fmt.Sprintf("sum(rate(<<.Series>>{<<.LabelMatchers>>}[%s])) by (<<.GroupBy>>)", pmodel.Duration(rateInterval).String()),
}, },
}, },
ResourceRules: &ResourceRules{ ResourceRules: &config.ResourceRules{
CPU: ResourceRule{ CPU: config.ResourceRule{
ContainerQuery: fmt.Sprintf("sum(rate(container_cpu_usage_seconds_total{<<.LabelMatchers>>}[%s])) by (<<.GroupBy>>)", pmodel.Duration(rateInterval).String()), 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()), NodeQuery: fmt.Sprintf("sum(rate(container_cpu_usage_seconds_total{<<.LabelMatchers>>, id='/'}[%s])) by (<<.GroupBy>>)", pmodel.Duration(rateInterval).String()),
Resources: ResourceMapping{ Resources: config.ResourceMapping{
Overrides: map[string]GroupResource{ Overrides: map[string]config.GroupResource{
"namespace": {Resource: "namespace"}, "namespace": {Resource: "namespace"},
"pod": {Resource: "pod"}, "pod": {Resource: "pod"},
"instance": {Resource: "node"}, "instance": {Resource: "node"},
@ -104,11 +104,11 @@ func DefaultConfig(rateInterval time.Duration, labelPrefix string) *MetricsDisco
}, },
ContainerLabel: fmt.Sprintf("%scontainer", labelPrefix), ContainerLabel: fmt.Sprintf("%scontainer", labelPrefix),
}, },
Memory: ResourceRule{ Memory: config.ResourceRule{
ContainerQuery: "sum(container_memory_working_set_bytes{<<.LabelMatchers>>}) by (<<.GroupBy>>)", ContainerQuery: "sum(container_memory_working_set_bytes{<<.LabelMatchers>>}) by (<<.GroupBy>>)",
NodeQuery: "sum(container_memory_working_set_bytes{<<.LabelMatchers>>,id='/'}) by (<<.GroupBy>>)", NodeQuery: "sum(container_memory_working_set_bytes{<<.LabelMatchers>>,id='/'}) by (<<.GroupBy>>)",
Resources: ResourceMapping{ Resources: config.ResourceMapping{
Overrides: map[string]GroupResource{ Overrides: map[string]config.GroupResource{
"namespace": {Resource: "namespace"}, "namespace": {Resource: "namespace"},
"pod": {Resource: "pod"}, "pod": {Resource: "pod"},
"instance": {Resource: "node"}, "instance": {Resource: "node"},

View file

@ -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

View file

@ -21,7 +21,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
"path" "path"
@ -61,11 +60,10 @@ func (c *httpAPIClient) Do(ctx context.Context, verb, endpoint string, query url
reqBody = strings.NewReader(query.Encode()) 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 { if err != nil {
return APIResponse{}, fmt.Errorf("error constructing HTTP request to Prometheus: %v", err) return APIResponse{}, fmt.Errorf("error constructing HTTP request to Prometheus: %v", err)
} }
req.WithContext(ctx)
for key, values := range c.headers { for key, values := range c.headers {
for _, value := range values { for _, value := range values {
req.Header.Add(key, value) 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 var body io.Reader = resp.Body
if klog.V(8).Enabled() { if klog.V(8).Enabled() {
data, err := ioutil.ReadAll(body) data, err := io.ReadAll(body)
if err != nil { if err != nil {
return APIResponse{}, fmt.Errorf("unable to log response body: %v", err) 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 // when present
func timeoutFromContext(ctx context.Context) (time.Duration, bool) { func timeoutFromContext(ctx context.Context) (time.Duration, bool) {
if deadline, hasDeadline := ctx.Deadline(); hasDeadline { if deadline, hasDeadline := ctx.Deadline(); hasDeadline {
return time.Now().Sub(deadline), true return time.Since(deadline), true
} }
return time.Duration(0), false return time.Duration(0), false

View file

@ -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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package client package client
import ( import (

View file

@ -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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package client package client
import ( import (

View file

@ -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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package metrics package metrics
import ( import (

View file

@ -25,10 +25,10 @@ type ErrorType string
const ( const (
ErrBadData ErrorType = "bad_data" ErrBadData ErrorType = "bad_data"
ErrTimeout = "timeout" ErrTimeout ErrorType = "timeout"
ErrCanceled = "canceled" ErrCanceled ErrorType = "canceled"
ErrExec = "execution" ErrExec ErrorType = "execution"
ErrBadResponse = "bad_response" ErrBadResponse ErrorType = "bad_response"
) )
// Error is an error returned by the API. // Error is an error returned by the API.
@ -46,7 +46,7 @@ type ResponseStatus string
const ( const (
ResponseSucceeded ResponseStatus = "succeeded" ResponseSucceeded ResponseStatus = "succeeded"
ResponseError = "error" ResponseError ResponseStatus = "error"
) )
// APIResponse represents the raw response returned by the API. // APIResponse represents the raw response returned by the API.

View file

@ -2,7 +2,7 @@ package config
import ( import (
"fmt" "fmt"
"io/ioutil" "io"
"os" "os"
yaml "gopkg.in/yaml.v2" 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) return nil, fmt.Errorf("unable to load metrics discovery config file: %v", err)
} }
defer file.Close() defer file.Close()
contents, err := ioutil.ReadAll(file) contents, err := io.ReadAll(file)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to load metrics discovery config file: %v", err) return nil, fmt.Errorf("unable to load metrics discovery config file: %v", err)
} }

View file

@ -99,7 +99,7 @@ func (p *prometheusProvider) metricFor(value pmodel.SampleValue, name types.Name
Name: info.Metric, Name: info.Metric,
}, },
// TODO(directxman12): use the right timestamp // TODO(directxman12): use the right timestamp
Timestamp: metav1.Time{time.Now()}, Timestamp: metav1.Time{Time: time.Now()},
Value: *q, Value: *q,
} }
@ -256,7 +256,7 @@ func (l *cachingMetricsLister) updateMetrics() error {
} }
selectors[sel] = struct{}{} selectors[sel] = struct{}{}
go func() { 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 { if err != nil {
errs <- fmt.Errorf("unable to fetch metrics for query %q: %v", sel, err) errs <- fmt.Errorf("unable to fetch metrics for query %q: %v", sel, err)
return return

View file

@ -87,7 +87,7 @@ var _ = Describe("Custom Metrics Provider", func() {
By("ensuring that no metrics are present before we start listing") By("ensuring that no metrics are present before we start listing")
Expect(prov.ListAllMetrics()).To(BeEmpty()) 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) startTime := pmodel.Now().Add(-1*fakeProviderUpdateInterval - fakeProviderUpdateInterval/10)
fakeProm.AcceptableInterval = pmodel.Interval{Start: startTime, End: 0} 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") By("listing all metrics, and checking that they contain the expected results")
Expect(prov.ListAllMetrics()).To(ConsistOf( Expect(prov.ListAllMetrics()).To(ConsistOf(
provider.CustomMetricInfo{schema.GroupResource{Resource: "services"}, true, "ingress_hits"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "services"}, Namespaced: true, Metric: "ingress_hits"},
provider.CustomMetricInfo{schema.GroupResource{Group: "extensions", Resource: "ingresses"}, true, "ingress_hits"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Group: "extensions", Resource: "ingresses"}, Namespaced: true, Metric: "ingress_hits"},
provider.CustomMetricInfo{schema.GroupResource{Resource: "pods"}, true, "ingress_hits"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "pods"}, Namespaced: true, Metric: "ingress_hits"},
provider.CustomMetricInfo{schema.GroupResource{Resource: "namespaces"}, false, "ingress_hits"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "namespaces"}, Namespaced: false, Metric: "ingress_hits"},
provider.CustomMetricInfo{schema.GroupResource{Resource: "services"}, true, "service_proxy_packets"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "services"}, Namespaced: true, Metric: "service_proxy_packets"},
provider.CustomMetricInfo{schema.GroupResource{Resource: "namespaces"}, false, "service_proxy_packets"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "namespaces"}, Namespaced: false, Metric: "service_proxy_packets"},
provider.CustomMetricInfo{schema.GroupResource{Group: "extensions", Resource: "deployments"}, true, "work_queue_wait"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Group: "extensions", Resource: "deployments"}, Namespaced: true, Metric: "work_queue_wait"},
provider.CustomMetricInfo{schema.GroupResource{Resource: "namespaces"}, false, "work_queue_wait"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "namespaces"}, Namespaced: false, Metric: "work_queue_wait"},
provider.CustomMetricInfo{schema.GroupResource{Resource: "namespaces"}, false, "some_usage"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "namespaces"}, Namespaced: false, Metric: "some_usage"},
provider.CustomMetricInfo{schema.GroupResource{Resource: "pods"}, true, "some_usage"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "pods"}, Namespaced: true, Metric: "some_usage"},
)) ))
}) })
}) })

View file

@ -84,7 +84,7 @@ var seriesRegistryTestSeries = [][]prom.Series{
}, },
}, },
{ {
// guage metrics // gauge metrics
{ {
Name: "node_gigawatts", Name: "node_gigawatts",
Labels: pmodel.LabelSet{"kube_node": "somenode"}, Labels: pmodel.LabelSet{"kube_node": "somenode"},
@ -159,7 +159,7 @@ var _ = Describe("Series Registry", func() {
// container metrics // container metrics
{ {
title: "container metrics gauge / multiple resource names", 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", namespace: "somens",
resourceNames: []string{"somepod1", "somepod2"}, resourceNames: []string{"somepod1", "somepod2"},
metricSelector: labels.Everything(), metricSelector: labels.Everything(),
@ -168,7 +168,7 @@ var _ = Describe("Series Registry", func() {
}, },
{ {
title: "container metrics counter", 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", namespace: "somens",
resourceNames: []string{"somepod1", "somepod2"}, resourceNames: []string{"somepod1", "somepod2"},
metricSelector: labels.Everything(), metricSelector: labels.Everything(),
@ -177,7 +177,7 @@ var _ = Describe("Series Registry", func() {
}, },
{ {
title: "container metrics seconds counter", 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", namespace: "somens",
resourceNames: []string{"somepod1", "somepod2"}, resourceNames: []string{"somepod1", "somepod2"},
metricSelector: labels.Everything(), metricSelector: labels.Everything(),
@ -187,7 +187,7 @@ var _ = Describe("Series Registry", func() {
// namespaced metrics // namespaced metrics
{ {
title: "namespaced metrics counter / multidimensional (service)", 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", namespace: "somens",
resourceNames: []string{"somesvc"}, resourceNames: []string{"somesvc"},
metricSelector: labels.Everything(), metricSelector: labels.Everything(),
@ -196,7 +196,7 @@ var _ = Describe("Series Registry", func() {
}, },
{ {
title: "namespaced metrics counter / multidimensional (service) / selection using labels", 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", namespace: "somens",
resourceNames: []string{"somesvc"}, resourceNames: []string{"somesvc"},
metricSelector: labels.NewSelector().Add( metricSelector: labels.NewSelector().Add(
@ -206,7 +206,7 @@ var _ = Describe("Series Registry", func() {
}, },
{ {
title: "namespaced metrics counter / multidimensional (ingress)", 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", namespace: "somens",
resourceNames: []string{"someingress"}, resourceNames: []string{"someingress"},
metricSelector: labels.Everything(), metricSelector: labels.Everything(),
@ -215,7 +215,7 @@ var _ = Describe("Series Registry", func() {
}, },
{ {
title: "namespaced metrics counter / multidimensional (pod)", 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", namespace: "somens",
resourceNames: []string{"somepod"}, resourceNames: []string{"somepod"},
metricSelector: labels.Everything(), metricSelector: labels.Everything(),
@ -224,7 +224,7 @@ var _ = Describe("Series Registry", func() {
}, },
{ {
title: "namespaced metrics gauge", 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", namespace: "somens",
resourceNames: []string{"somesvc"}, resourceNames: []string{"somesvc"},
metricSelector: labels.Everything(), metricSelector: labels.Everything(),
@ -233,7 +233,7 @@ var _ = Describe("Series Registry", func() {
}, },
{ {
title: "namespaced metrics seconds counter", 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", namespace: "somens",
resourceNames: []string{"somedep"}, resourceNames: []string{"somedep"},
metricSelector: labels.Everything(), metricSelector: labels.Everything(),
@ -243,7 +243,7 @@ var _ = Describe("Series Registry", func() {
// non-namespaced series // non-namespaced series
{ {
title: "root scoped metrics gauge", 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"}, resourceNames: []string{"somenode"},
metricSelector: labels.Everything(), metricSelector: labels.Everything(),
@ -251,7 +251,7 @@ var _ = Describe("Series Registry", func() {
}, },
{ {
title: "root scoped metrics counter", 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"}, resourceNames: []string{"somepv"},
metricSelector: labels.Everything(), metricSelector: labels.Everything(),
@ -259,7 +259,7 @@ var _ = Describe("Series Registry", func() {
}, },
{ {
title: "root scoped metrics seconds counter", 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"}, resourceNames: []string{"somenode"},
metricSelector: labels.Everything(), metricSelector: labels.Everything(),
@ -281,23 +281,23 @@ var _ = Describe("Series Registry", func() {
It("should list all metrics", func() { It("should list all metrics", func() {
Expect(registry.ListAllMetrics()).To(ConsistOf( Expect(registry.ListAllMetrics()).To(ConsistOf(
provider.CustomMetricInfo{schema.GroupResource{Resource: "pods"}, true, "some_count"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "pods"}, Namespaced: true, Metric: "some_count"},
provider.CustomMetricInfo{schema.GroupResource{Resource: "namespaces"}, false, "some_count"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "namespaces"}, Namespaced: false, Metric: "some_count"},
provider.CustomMetricInfo{schema.GroupResource{Resource: "pods"}, true, "some_time"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "pods"}, Namespaced: true, Metric: "some_time"},
provider.CustomMetricInfo{schema.GroupResource{Resource: "namespaces"}, false, "some_time"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "namespaces"}, Namespaced: false, Metric: "some_time"},
provider.CustomMetricInfo{schema.GroupResource{Resource: "pods"}, true, "some_usage"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "pods"}, Namespaced: true, Metric: "some_usage"},
provider.CustomMetricInfo{schema.GroupResource{Resource: "namespaces"}, false, "some_usage"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "namespaces"}, Namespaced: false, Metric: "some_usage"},
provider.CustomMetricInfo{schema.GroupResource{Resource: "services"}, true, "ingress_hits"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "services"}, Namespaced: true, Metric: "ingress_hits"},
provider.CustomMetricInfo{schema.GroupResource{Group: "extensions", Resource: "ingresses"}, true, "ingress_hits"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Group: "extensions", Resource: "ingresses"}, Namespaced: true, Metric: "ingress_hits"},
provider.CustomMetricInfo{schema.GroupResource{Resource: "pods"}, true, "ingress_hits"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "pods"}, Namespaced: true, Metric: "ingress_hits"},
provider.CustomMetricInfo{schema.GroupResource{Resource: "namespaces"}, false, "ingress_hits"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "namespaces"}, Namespaced: false, Metric: "ingress_hits"},
provider.CustomMetricInfo{schema.GroupResource{Resource: "services"}, true, "service_proxy_packets"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "services"}, Namespaced: true, Metric: "service_proxy_packets"},
provider.CustomMetricInfo{schema.GroupResource{Resource: "namespaces"}, false, "service_proxy_packets"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "namespaces"}, Namespaced: false, Metric: "service_proxy_packets"},
provider.CustomMetricInfo{schema.GroupResource{Group: "extensions", Resource: "deployments"}, true, "work_queue_wait"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Group: "extensions", Resource: "deployments"}, Namespaced: true, Metric: "work_queue_wait"},
provider.CustomMetricInfo{schema.GroupResource{Resource: "namespaces"}, false, "work_queue_wait"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "namespaces"}, Namespaced: false, Metric: "work_queue_wait"},
provider.CustomMetricInfo{schema.GroupResource{Resource: "nodes"}, false, "node_gigawatts"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "nodes"}, Namespaced: false, Metric: "node_gigawatts"},
provider.CustomMetricInfo{schema.GroupResource{Resource: "persistentvolumes"}, false, "volume_claims"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "persistentvolumes"}, Namespaced: false, Metric: "volume_claims"},
provider.CustomMetricInfo{schema.GroupResource{Resource: "nodes"}, false, "node_fan"}, provider.CustomMetricInfo{GroupResource: schema.GroupResource{Resource: "nodes"}, Namespaced: false, Metric: "node_fan"},
)) ))
}) })
}) })

View file

@ -100,7 +100,7 @@ func (l *basicMetricLister) ListAllMetrics() (MetricUpdateResult, error) {
} }
selectors[sel] = struct{}{} selectors[sel] = struct{}{}
go func() { 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 { if err != nil {
errs <- fmt.Errorf("unable to fetch metrics for query %q: %v", sel, err) errs <- fmt.Errorf("unable to fetch metrics for query %q: %v", sel, err)
return return

View file

@ -103,7 +103,6 @@ func (r *externalSeriesRegistry) filterAndStoreMetrics(result MetricUpdateResult
r.metrics = apiMetricsCache r.metrics = apiMetricsCache
r.metricsInfo = rawMetricsCache r.metricsInfo = rawMetricsCache
} }
func (r *externalSeriesRegistry) ListAllMetrics() []provider.ExternalMetricInfo { func (r *externalSeriesRegistry) ListAllMetrics() []provider.ExternalMetricInfo {

View file

@ -61,7 +61,7 @@ func (c *metricConverter) convertSample(info provider.ExternalMetricInfo, sample
singleMetric := external_metrics.ExternalMetricValue{ singleMetric := external_metrics.ExternalMetricValue{
MetricName: info.Metric, MetricName: info.Metric,
Timestamp: metav1.Time{ Timestamp: metav1.Time{
sample.Timestamp.Time(), Time: sample.Timestamp.Time(),
}, },
Value: *resource.NewMilliQuantity(int64(sample.Value*1000.0), resource.DecimalSI), Value: *resource.NewMilliQuantity(int64(sample.Value*1000.0), resource.DecimalSI),
MetricLabels: labels, MetricLabels: labels,
@ -133,7 +133,7 @@ func (c *metricConverter) convertScalar(info provider.ExternalMetricInfo, queryR
{ {
MetricName: info.Metric, MetricName: info.Metric,
Timestamp: metav1.Time{ Timestamp: metav1.Time{
toConvert.Timestamp.Time(), Time: toConvert.Timestamp.Time(),
}, },
Value: *resource.NewMilliQuantity(int64(toConvert.Value*1000.0), resource.DecimalSI), Value: *resource.NewMilliQuantity(int64(toConvert.Value*1000.0), resource.DecimalSI),
}, },

View file

@ -85,5 +85,7 @@ func (l *periodicMetricLister) notifyListeners() {
} }
func (l *periodicMetricLister) UpdateNow() { func (l *periodicMetricLister) UpdateNow() {
l.updateMetrics() if err := l.updateMetrics(); err != nil {
utilruntime.HandleError(err)
}
} }

View file

@ -22,7 +22,6 @@ import (
"regexp" "regexp"
"text/template" "text/template"
apimeta "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
pmodel "github.com/prometheus/common/model" pmodel "github.com/prometheus/common/model"
@ -34,7 +33,6 @@ type labelGroupResExtractor struct {
resourceInd int resourceInd int
groupInd *int groupInd *int
mapper apimeta.RESTMapper
} }
// newLabelGroupResExtractor creates a new labelGroupResExtractor for labels whose form // 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. // so anything in the template which limits resource or group name length will cause issues.
func newLabelGroupResExtractor(labelTemplate *template.Template) (*labelGroupResExtractor, error) { func newLabelGroupResExtractor(labelTemplate *template.Template) (*labelGroupResExtractor, error) {
labelRegexBuff := new(bytes.Buffer) labelRegexBuff := new(bytes.Buffer)
if err := labelTemplate.Execute(labelRegexBuff, schema.GroupResource{"(?P<group>.+?)", "(?P<resource>.+?)"}); err != nil { if err := labelTemplate.Execute(labelRegexBuff, schema.GroupResource{
Group: "(?P<group>.+?)",
Resource: "(?P<resource>.+?)"},
); err != nil {
return nil, fmt.Errorf("unable to convert label template to matcher: %v", err) return nil, fmt.Errorf("unable to convert label template to matcher: %v", err)
} }
if labelRegexBuff.Len() == 0 { if labelRegexBuff.Len() == 0 {

View file

@ -194,13 +194,14 @@ func NamersFromConfig(cfg []config.DiscoveryRule, mapper apimeta.RESTMapper) ([]
if nameAs == "" { if nameAs == "" {
// check if we have an obvious default // check if we have an obvious default
subexpNames := nameMatches.SubexpNames() subexpNames := nameMatches.SubexpNames()
if len(subexpNames) == 1 { switch len(subexpNames) {
case 1:
// no capture groups, use the whole thing // no capture groups, use the whole thing
nameAs = "$0" nameAs = "$0"
} else if len(subexpNames) == 2 { case 2:
// one capture group, use that // one capture group, use that
nameAs = "$1" 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) return nil, fmt.Errorf("must specify an 'as' value for name matcher %q associated with series query %q", rule.Name.Matches, rule.SeriesQuery)
} }
} }

View file

@ -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) { func (q *metricsQuery) selectMatcher(operator selection.Operator, values []string) (func(string, string) string, error) {
switch len(values) {
numValues := len(values) case 0:
if numValues == 0 {
switch operator { switch operator {
case selection.Exists: case selection.Exists:
return prom.LabelNeq, nil 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: case selection.Equals, selection.DoubleEquals, selection.NotEquals, selection.In, selection.NotIn:
return nil, ErrMalformedQuery return nil, ErrMalformedQuery
} }
} else if numValues == 1 { case 1:
switch operator { switch operator {
case selection.Equals, selection.DoubleEquals: case selection.Equals, selection.DoubleEquals:
return prom.LabelEq, nil return prom.LabelEq, nil
@ -305,7 +304,7 @@ func (q *metricsQuery) selectMatcher(operator selection.Operator, values []strin
case selection.DoesNotExist, selection.NotIn: case selection.DoesNotExist, selection.NotIn:
return prom.LabelNotMatches, nil return prom.LabelNotMatches, nil
} }
} else { default:
// Since labels can only have one value, providing multiple // Since labels can only have one value, providing multiple
// values results in a regex match, even if that's not what the user // values results in a regex match, even if that's not what the user
// asked for. // 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) { func (q *metricsQuery) selectTargetValue(operator selection.Operator, values []string) (string, error) {
numValues := len(values) switch len(values) {
if numValues == 0 { case 0:
switch operator { switch operator {
case selection.Exists, selection.DoesNotExist: case selection.Exists, selection.DoesNotExist:
// Return an empty string when values are equal to 0 // 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: case selection.Equals, selection.DoubleEquals, selection.NotEquals, selection.In, selection.NotIn:
return "", ErrMalformedQuery return "", ErrMalformedQuery
} }
} else if numValues == 1 { case 1:
switch operator { switch operator {
case selection.Equals, selection.DoubleEquals, selection.NotEquals, selection.In, selection.NotIn: case selection.Equals, selection.DoubleEquals, selection.NotEquals, selection.In, selection.NotIn:
// Pass the value through as-is. // Pass the value through as-is.
@ -347,7 +346,7 @@ func (q *metricsQuery) selectTargetValue(operator selection.Operator, values []s
case selection.Exists, selection.DoesNotExist: case selection.Exists, selection.DoesNotExist:
return "", ErrQueryUnsupportedValues return "", ErrQueryUnsupportedValues
} }
} else { default:
switch operator { switch operator {
case selection.Equals, selection.DoubleEquals, selection.NotEquals, selection.In, selection.NotIn: case selection.Equals, selection.DoubleEquals, selection.NotEquals, selection.In, selection.NotIn:
// Pass the value through as-is. // Pass the value through as-is.

View file

@ -72,7 +72,6 @@ func newResourceQuery(cfg config.ResourceRule, mapper apimeta.RESTMapper) (resou
nodeQuery: nodeQuery, nodeQuery: nodeQuery,
containerLabel: cfg.ContainerLabel, containerLabel: cfg.ContainerLabel,
}, nil }, nil
} }
// resourceQuery represents query information for querying resource metrics for some resource, // resourceQuery represents query information for querying resource metrics for some resource,