mirror of
https://github.com/zalando-incubator/kube-metrics-adapter.git
synced 2025-05-12 08:21:54 +00:00
Compare commits
12 Commits
v0.0.1
...
new-ingres
Author | SHA1 | Date | |
---|---|---|---|
5e6d304ecd | |||
0de5042d3d | |||
07c0e179b3 | |||
29ee953a16 | |||
f78ef26857 | |||
a3c14e9dcb | |||
b6b13fb31a | |||
0a06691d39 | |||
2d1d51e829 | |||
41761e62df | |||
ed4c93abbb | |||
b2194ca136 |
@ -2,14 +2,14 @@ language: go
|
||||
dist: xenial
|
||||
|
||||
go:
|
||||
- "1.11.x"
|
||||
- "1.13.x"
|
||||
|
||||
env:
|
||||
- GO111MODULE=on GOLANGCI_RELEASE="v1.16.0"
|
||||
|
||||
before_install:
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get github.com/lawrencewoodman/roveralls
|
||||
- GO111MODULE=off go get github.com/mattn/goveralls
|
||||
- GO111MODULE=off go get github.com/lawrencewoodman/roveralls
|
||||
- curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin ${GOLANGCI_RELEASE}
|
||||
|
||||
script:
|
||||
|
@ -172,6 +172,10 @@ kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: myapp-hpa
|
||||
annotations:
|
||||
# This annotation is optional.
|
||||
# If specified, then this prometheus server is used,
|
||||
# instead of the prometheus server specified as the CLI argument `--prometheus-server`.
|
||||
metric-config.external.prometheus-query.prometheus/prometheus-server: http://prometheus.my-namespace.svc
|
||||
# metric-config.<metricType>.<metricName>.<collectorName>/<configKey>
|
||||
# <configKey> == query-name
|
||||
metric-config.external.prometheus-query.prometheus/processed-events-per-second: |
|
||||
|
@ -7,6 +7,8 @@ pipeline:
|
||||
- /go/pkg/mod # pkg cache for Go modules
|
||||
- ~/.cache/go-build # Go build cache
|
||||
type: script
|
||||
env:
|
||||
GOFLAGS: "-mod=readonly"
|
||||
commands:
|
||||
- desc: test
|
||||
cmd: |
|
||||
@ -18,9 +20,11 @@ pipeline:
|
||||
cmd: |
|
||||
if [[ $CDP_TARGET_BRANCH == master && ! $CDP_PULL_REQUEST_NUMBER ]]; then
|
||||
IMAGE=registry-write.opensource.zalan.do/teapot/kube-metrics-adapter
|
||||
VERSION=$(git describe --tags --always --dirty)
|
||||
VERSION=$(git describe --tags --always)
|
||||
else
|
||||
IMAGE=registry-write.opensource.zalan.do/teapot/kube-metrics-adapter-test
|
||||
VERSION=$CDP_BUILD_VERSION
|
||||
fi
|
||||
IMAGE=$IMAGE VERSION=$VERSION make build.docker
|
||||
git diff --stat --exit-code
|
||||
IMAGE=$IMAGE VERSION=$VERSION make build.push
|
||||
|
86
go.mod
86
go.mod
@ -1,91 +1,33 @@
|
||||
module github.com/zalando-incubator/kube-metrics-adapter
|
||||
|
||||
require (
|
||||
bitbucket.org/ww/goautoneg v0.0.0-20120707110453-75cd24fc2f2c // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect
|
||||
github.com/BurntSushi/toml v0.3.0 // indirect
|
||||
github.com/NYTimes/gziphandler v1.0.1 // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.0 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/Sirupsen/logrus v1.0.6 // indirect
|
||||
github.com/aws/aws-sdk-go v1.16.6
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 // indirect
|
||||
github.com/boltdb/bolt v1.3.1 // indirect
|
||||
github.com/coreos/bbolt v1.3.0 // indirect
|
||||
github.com/coreos/etcd v3.3.9+incompatible // indirect
|
||||
github.com/coreos/go-semver v0.2.0 // indirect
|
||||
github.com/coreos/go-systemd v0.0.0-20180705093442-88bfeed483d3 // indirect
|
||||
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea // indirect
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
|
||||
github.com/docker/docker v1.13.1 // indirect
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.0 // indirect
|
||||
github.com/emicklei/go-restful v2.8.0+incompatible // indirect
|
||||
github.com/emicklei/go-restful-swagger12 v0.0.0-20170926063155-7524189396c6 // indirect
|
||||
github.com/evanphx/json-patch v4.1.1-0.20190203004735-bbf30d639737+incompatible // indirect
|
||||
github.com/fsnotify/fsnotify v1.4.7 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.0.0-20180322222829-3a0015ad55fa // indirect
|
||||
github.com/go-openapi/jsonreference v0.0.0-20180322222742-3fb327e6747d // indirect
|
||||
github.com/go-openapi/spec v0.0.0-20180801175345-384415f06ee2 // indirect
|
||||
github.com/go-openapi/swag v0.0.0-20180715190254-becd2f08beaf // indirect
|
||||
github.com/gogo/protobuf v1.1.1 // indirect
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
|
||||
github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7 // indirect
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c // indirect
|
||||
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf // indirect
|
||||
github.com/googleapis/gnostic v0.2.0 // indirect
|
||||
github.com/gorilla/websocket v1.3.0 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.4.1 // indirect
|
||||
github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47 // indirect
|
||||
github.com/hpcloud/tail v1.0.0 // indirect
|
||||
github.com/imdario/mergo v0.3.6 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jonboulle/clockwork v0.1.0 // indirect
|
||||
github.com/json-iterator/go v1.1.5 // indirect
|
||||
github.com/kubernetes-incubator/custom-metrics-apiserver v0.0.0-20190116221620-b7016fc85e1c
|
||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||
github.com/kubernetes-incubator/custom-metrics-apiserver v0.0.0-20190918110929-3d9be26a50eb
|
||||
github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852
|
||||
github.com/onsi/ginkgo v1.6.0 // indirect
|
||||
github.com/onsi/gomega v1.4.1 // indirect
|
||||
github.com/pborman/uuid v0.0.0-20180122190007-c65b2f87fee3 // indirect
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||
github.com/prometheus/client_golang v0.9.0-pre1.0.20180824101016-4eb539fa85a2
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 // indirect
|
||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e
|
||||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273 // indirect
|
||||
github.com/sirupsen/logrus v1.3.0
|
||||
github.com/prometheus/client_golang v0.9.2
|
||||
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275
|
||||
github.com/sirupsen/logrus v1.4.2
|
||||
github.com/soheilhy/cmux v0.1.4 // indirect
|
||||
github.com/spf13/cobra v0.0.3
|
||||
github.com/spf13/pflag v1.0.2 // indirect
|
||||
github.com/stretchr/testify v1.2.2
|
||||
github.com/stretchr/testify v1.3.0
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6 // indirect
|
||||
github.com/ugorji/go v1.1.1 // indirect
|
||||
github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18 // indirect
|
||||
github.com/zalando-incubator/cluster-lifecycle-manager v0.0.0-20180921141935-824b77fb1f84
|
||||
golang.org/x/crypto v0.0.0-20181015023909-0c41d7ab0a0e // indirect
|
||||
golang.org/x/net v0.0.0-20180824152047-4bcd98cce591 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f // indirect
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2 // indirect
|
||||
google.golang.org/appengine v1.2.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 // indirect
|
||||
google.golang.org/grpc v1.14.0 // indirect
|
||||
gopkg.in/airbrake/gobrake.v2 v2.0.9 // indirect
|
||||
gopkg.in/fsnotify.v1 v1.4.7 // indirect
|
||||
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0-20170531160350-a96e63847dc3 // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.1 // indirect
|
||||
k8s.io/api v0.0.0-20190226173710-145d52631d00
|
||||
k8s.io/apimachinery v0.0.0-20190221084156-01f179d85dbc
|
||||
k8s.io/apiserver v0.0.0-20190226174732-cf2f1d68202d
|
||||
k8s.io/client-go v2.0.0-alpha.0.0.20190226174127-78295b709ec6+incompatible
|
||||
k8s.io/kube-openapi v0.0.0-20180731170545-e3762e86a74c // indirect
|
||||
k8s.io/api v0.0.0-20190918155943-95b840bb6a1f
|
||||
k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655
|
||||
k8s.io/apiserver v0.0.0-20190918160949-bfa5e2e684ad // indirect
|
||||
k8s.io/client-go v0.0.0-20190918160344-1fbdaa4c8d90
|
||||
k8s.io/component-base v0.0.0-20190918160511-547f6c5d7090
|
||||
k8s.io/klog v0.4.0
|
||||
k8s.io/metrics v0.0.0-20190226180357-f3f09b9076d1
|
||||
)
|
||||
|
||||
go 1.13
|
||||
|
2
main.go
2
main.go
@ -23,7 +23,7 @@ import (
|
||||
|
||||
"github.com/zalando-incubator/kube-metrics-adapter/pkg/server"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apiserver/pkg/util/logs"
|
||||
"k8s.io/component-base/logs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -56,11 +56,11 @@ func NewAWSSQSCollector(sessions map[string]*session.Session, config *MetricConf
|
||||
return nil, fmt.Errorf("selector for queue is not specified")
|
||||
}
|
||||
|
||||
name, ok := config.Metric.Selector.MatchLabels[sqsQueueNameLabelKey]
|
||||
name, ok := config.Config[sqsQueueNameLabelKey]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("sqs queue name not specified on metric")
|
||||
}
|
||||
region, ok := config.Metric.Selector.MatchLabels[sqsQueueRegionLabelKey]
|
||||
region, ok := config.Config[sqsQueueRegionLabelKey]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("sqs queue region is not specified on metric")
|
||||
}
|
||||
|
@ -208,7 +208,9 @@ func ParseHPAMetrics(hpa *autoscalingv2.HorizontalPodAutoscaler) ([]*MetricConfi
|
||||
Config: map[string]string{},
|
||||
}
|
||||
|
||||
if metric.Type == autoscalingv2.ExternalMetricSourceType {
|
||||
if metric.Type == autoscalingv2.ExternalMetricSourceType &&
|
||||
metric.External.Metric.Selector != nil &&
|
||||
metric.External.Metric.Selector.MatchLabels != nil {
|
||||
config.Config = metric.External.Metric.Selector.MatchLabels
|
||||
}
|
||||
|
||||
@ -217,7 +219,11 @@ func ParseHPAMetrics(hpa *autoscalingv2.HorizontalPodAutoscaler) ([]*MetricConfi
|
||||
config.CollectorName = annotationConfigs.CollectorName
|
||||
config.Interval = annotationConfigs.Interval
|
||||
config.PerReplica = annotationConfigs.PerReplica
|
||||
config.Config = annotationConfigs.Configs
|
||||
// configs specified in annotations takes precedence
|
||||
// over labels
|
||||
for k, v := range annotationConfigs.Configs {
|
||||
config.Config[k] = v
|
||||
}
|
||||
}
|
||||
metricConfigs = append(metricConfigs, config)
|
||||
}
|
||||
|
@ -18,8 +18,9 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
PrometheusMetricName = "prometheus-query"
|
||||
prometheusQueryNameLabelKey = "query-name"
|
||||
PrometheusMetricName = "prometheus-query"
|
||||
prometheusQueryNameLabelKey = "query-name"
|
||||
prometheusServerAnnotationKey = "prometheus-server"
|
||||
)
|
||||
|
||||
type NoResultError struct {
|
||||
@ -38,7 +39,7 @@ type PrometheusCollectorPlugin struct {
|
||||
func NewPrometheusCollectorPlugin(client kubernetes.Interface, prometheusServer string) (*PrometheusCollectorPlugin, error) {
|
||||
cfg := api.Config{
|
||||
Address: prometheusServer,
|
||||
RoundTripper: &http.Transport{},
|
||||
RoundTripper: http.DefaultTransport,
|
||||
}
|
||||
|
||||
promClient, err := api.NewClient(cfg)
|
||||
@ -90,7 +91,11 @@ func NewPrometheusCollector(client kubernetes.Interface, promAPI promv1.API, hpa
|
||||
return nil, fmt.Errorf("no prometheus query defined")
|
||||
}
|
||||
case autoscalingv2.ExternalMetricSourceType:
|
||||
queryName, ok := config.Metric.Selector.MatchLabels[prometheusQueryNameLabelKey]
|
||||
if config.Metric.Selector == nil {
|
||||
return nil, fmt.Errorf("selector for prometheus query is not specified")
|
||||
}
|
||||
|
||||
queryName, ok := config.Config[prometheusQueryNameLabelKey]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("query name not specified on metric")
|
||||
}
|
||||
@ -101,6 +106,20 @@ func NewPrometheusCollector(client kubernetes.Interface, promAPI promv1.API, hpa
|
||||
} else {
|
||||
return nil, fmt.Errorf("no prometheus query defined for metric")
|
||||
}
|
||||
|
||||
// Use custom Prometheus URL if defined in HPA annotation.
|
||||
if promServer, ok := config.Config[prometheusServerAnnotationKey]; ok {
|
||||
cfg := api.Config{
|
||||
Address: promServer,
|
||||
RoundTripper: http.DefaultTransport,
|
||||
}
|
||||
|
||||
promClient, err := api.NewClient(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.promAPI = promv1.NewAPI(promClient)
|
||||
}
|
||||
}
|
||||
|
||||
return c, nil
|
||||
|
@ -2,7 +2,9 @@ package collector
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -19,6 +21,10 @@ const (
|
||||
rpsMetricBackendSeparator = ","
|
||||
)
|
||||
|
||||
var (
|
||||
errBackendNameMissing = errors.New("backend name must be specified for requests-per-second when traffic switching is used")
|
||||
)
|
||||
|
||||
// SkipperCollectorPlugin is a collector plugin for initializing metrics
|
||||
// collectors for getting skipper ingress metrics.
|
||||
type SkipperCollectorPlugin struct {
|
||||
@ -81,52 +87,78 @@ func NewSkipperCollector(client kubernetes.Interface, plugin CollectorPlugin, hp
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getAnnotationWeight(backendWeights string, backend string) (float64, bool) {
|
||||
func getAnnotationWeight(backendWeights string, backend string) float64 {
|
||||
var weightsMap map[string]int
|
||||
err := json.Unmarshal([]byte(backendWeights), &weightsMap)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
return 0
|
||||
}
|
||||
if weight, ok := weightsMap[backend]; ok {
|
||||
return float64(weight) / 100, true
|
||||
return float64(weight) / 100
|
||||
}
|
||||
return 0, false
|
||||
return 0
|
||||
}
|
||||
|
||||
func getWeights(ingressAnnotations map[string]string, backendAnnotations []string, backend string) float64 {
|
||||
var maxWeight float64 = -1
|
||||
weightSet := false
|
||||
func getWeights(ingressAnnotations map[string]string, backendAnnotations []string, backend string) (float64, error) {
|
||||
maxWeight := 0.0
|
||||
annotationsPresent := false
|
||||
|
||||
for _, anno := range backendAnnotations {
|
||||
if weightsMap, ok := ingressAnnotations[anno]; ok {
|
||||
weight, isPresent := getAnnotationWeight(weightsMap, backend)
|
||||
if isPresent {
|
||||
weightSet = true
|
||||
if weight > maxWeight {
|
||||
maxWeight = weight
|
||||
}
|
||||
}
|
||||
annotationsPresent = true
|
||||
maxWeight = math.Max(maxWeight, getAnnotationWeight(weightsMap, backend))
|
||||
}
|
||||
}
|
||||
if weightSet {
|
||||
return maxWeight
|
||||
|
||||
// Fallback for ingresses that don't use traffic switching
|
||||
if !annotationsPresent {
|
||||
return 1.0, nil
|
||||
}
|
||||
return 1.0
|
||||
|
||||
// Require backend name here
|
||||
if backend != "" {
|
||||
return maxWeight, nil
|
||||
}
|
||||
|
||||
return 0.0, errBackendNameMissing
|
||||
}
|
||||
|
||||
// getCollector returns a collector for getting the metrics.
|
||||
func (c *SkipperCollector) getCollector() (Collector, error) {
|
||||
ingress, err := c.client.ExtensionsV1beta1().Ingresses(c.objectReference.Namespace).Get(c.objectReference.Name, metav1.GetOptions{})
|
||||
var annotations map[string]string
|
||||
var hosts []string
|
||||
|
||||
switch c.objectReference.APIVersion {
|
||||
case "extensions/v1beta1":
|
||||
ingress, err := c.client.ExtensionsV1beta1().Ingresses(c.objectReference.Namespace).Get(c.objectReference.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
annotations = ingress.Annotations
|
||||
for _, rule := range ingress.Spec.Rules {
|
||||
hosts = append(hosts, rule.Host)
|
||||
}
|
||||
case "networking.k8s.io/v1beta1":
|
||||
ingress, err := c.client.NetworkingV1beta1().Ingresses(c.objectReference.Namespace).Get(c.objectReference.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
annotations = ingress.Annotations
|
||||
for _, rule := range ingress.Spec.Rules {
|
||||
hosts = append(hosts, rule.Host)
|
||||
}
|
||||
}
|
||||
|
||||
backendWeight, err := getWeights(annotations, c.backendAnnotations, c.backend)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
backendWeight := getWeights(ingress.Annotations, c.backendAnnotations, c.backend)
|
||||
config := c.config
|
||||
|
||||
var collector Collector
|
||||
collectors := make([]Collector, 0, len(ingress.Spec.Rules))
|
||||
for _, rule := range ingress.Spec.Rules {
|
||||
host := strings.Replace(rule.Host, ".", "_", -1)
|
||||
collectors := make([]Collector, 0, len(hosts))
|
||||
for _, host := range hosts {
|
||||
host := strings.Replace(host, ".", "_", -1)
|
||||
config.Config = map[string]string{
|
||||
"query": fmt.Sprintf(rpsQuery, host),
|
||||
}
|
||||
|
@ -106,6 +106,7 @@ func TestSkipperCollector(t *testing.T) {
|
||||
backend string
|
||||
ingressName string
|
||||
collectedMetric int
|
||||
expectError bool
|
||||
namespace string
|
||||
backendWeights map[string]map[string]int
|
||||
replicas int32
|
||||
@ -177,7 +178,7 @@ func TestSkipperCollector(t *testing.T) {
|
||||
msg: "test backend is not set",
|
||||
metrics: []int{100, 1500, 700},
|
||||
ingressName: "dummy-ingress",
|
||||
collectedMetric: 1500,
|
||||
collectedMetric: 0,
|
||||
namespace: "default",
|
||||
backend: "backend3",
|
||||
backendWeights: map[string]map[string]int{testBackendWeightsAnnotation: {"backend2": 100, "backend1": 0}},
|
||||
@ -185,6 +186,42 @@ func TestSkipperCollector(t *testing.T) {
|
||||
readyReplicas: 1,
|
||||
backendAnnotations: []string{testBackendWeightsAnnotation},
|
||||
},
|
||||
{
|
||||
msg: "test no annotations set",
|
||||
metrics: []int{100, 1500, 700},
|
||||
ingressName: "dummy-ingress",
|
||||
collectedMetric: 1500,
|
||||
namespace: "default",
|
||||
backend: "backend3",
|
||||
backendWeights: map[string]map[string]int{},
|
||||
replicas: 1,
|
||||
readyReplicas: 1,
|
||||
backendAnnotations: []string{testBackendWeightsAnnotation},
|
||||
},
|
||||
{
|
||||
msg: "test annotations are set but backend is missing",
|
||||
metrics: []int{100, 1500, 700},
|
||||
ingressName: "dummy-ingress",
|
||||
expectError: true,
|
||||
namespace: "default",
|
||||
backend: "",
|
||||
backendWeights: map[string]map[string]int{testBackendWeightsAnnotation: {"backend2": 100, "backend1": 0}},
|
||||
replicas: 1,
|
||||
readyReplicas: 1,
|
||||
backendAnnotations: []string{testBackendWeightsAnnotation},
|
||||
},
|
||||
{
|
||||
msg: "test annotations are missing and backend is unset",
|
||||
metrics: []int{100, 1500, 700},
|
||||
ingressName: "dummy-ingress",
|
||||
collectedMetric: 1500,
|
||||
namespace: "default",
|
||||
backend: "",
|
||||
backendWeights: nil,
|
||||
replicas: 1,
|
||||
readyReplicas: 1,
|
||||
backendAnnotations: []string{testBackendWeightsAnnotation},
|
||||
},
|
||||
{
|
||||
msg: "test partial backend annotations",
|
||||
metrics: []int{100, 1500, 700},
|
||||
@ -201,7 +238,7 @@ func TestSkipperCollector(t *testing.T) {
|
||||
backendAnnotations: []string{testBackendWeightsAnnotation, testStacksetWeightsAnnotation},
|
||||
},
|
||||
} {
|
||||
t.Run(tc.msg, func(tt *testing.T) {
|
||||
t.Run(tc.msg, func(t *testing.T) {
|
||||
client := fake.NewSimpleClientset()
|
||||
err := makeIngress(client, tc.namespace, tc.ingressName, tc.backend, tc.backendWeights)
|
||||
require.NoError(t, err)
|
||||
@ -211,11 +248,15 @@ func TestSkipperCollector(t *testing.T) {
|
||||
_, err = newDeployment(client, tc.namespace, tc.backend, tc.replicas, tc.readyReplicas)
|
||||
require.NoError(t, err)
|
||||
collector, err := NewSkipperCollector(client, plugin, hpa, config, time.Minute, tc.backendAnnotations, tc.backend)
|
||||
require.NoError(tt, err, "failed to create skipper collector: %v", err)
|
||||
require.NoError(t, err, "failed to create skipper collector: %v", err)
|
||||
collected, err := collector.GetMetrics()
|
||||
require.NoError(tt, err, "failed to collect metrics: %v", err)
|
||||
require.Len(t, collected, 1, "the number of metrics returned is not 1")
|
||||
require.EqualValues(t, tc.collectedMetric, collected[0].Custom.Value.Value(), "the returned metric is not expected value")
|
||||
if tc.expectError {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err, "failed to collect metrics: %v", err)
|
||||
require.Len(t, collected, 1, "the number of metrics returned is not 1")
|
||||
require.EqualValues(t, tc.collectedMetric, collected[0].Custom.Value.Value(), "the returned metric is not expected value")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -44,11 +44,7 @@ func NewZMONCollectorPlugin(zmon zmon.ZMON) (*ZMONCollectorPlugin, error) {
|
||||
func (c *ZMONCollectorPlugin) NewCollector(hpa *autoscalingv2.HorizontalPodAutoscaler, config *MetricConfig, interval time.Duration) (Collector, error) {
|
||||
switch config.Metric.Name {
|
||||
case ZMONCheckMetric:
|
||||
annotations := map[string]string{}
|
||||
if hpa != nil {
|
||||
annotations = hpa.Annotations
|
||||
}
|
||||
return NewZMONCollector(c.zmon, config, annotations, interval)
|
||||
return NewZMONCollector(c.zmon, config, interval)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("metric '%s' not supported", config.Metric.Name)
|
||||
@ -68,7 +64,11 @@ type ZMONCollector struct {
|
||||
}
|
||||
|
||||
// NewZMONCollector initializes a new ZMONCollector.
|
||||
func NewZMONCollector(zmon zmon.ZMON, config *MetricConfig, annotations map[string]string, interval time.Duration) (*ZMONCollector, error) {
|
||||
func NewZMONCollector(zmon zmon.ZMON, config *MetricConfig, interval time.Duration) (*ZMONCollector, error) {
|
||||
if config.Metric.Selector == nil {
|
||||
return nil, fmt.Errorf("selector for zmon-check is not specified")
|
||||
}
|
||||
|
||||
checkIDStr, ok := config.Config[zmonCheckIDLabelKey]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("ZMON check ID not specified on metric")
|
||||
@ -86,11 +86,6 @@ func NewZMONCollector(zmon zmon.ZMON, config *MetricConfig, annotations map[stri
|
||||
key = k
|
||||
}
|
||||
|
||||
// annotations takes precedence over label
|
||||
if k, ok := annotations[zmonKeyAnnotationKey]; ok {
|
||||
key = k
|
||||
}
|
||||
|
||||
duration := defaultQueryDuration
|
||||
|
||||
// parse optional duration value
|
||||
@ -110,16 +105,6 @@ func NewZMONCollector(zmon zmon.ZMON, config *MetricConfig, annotations map[stri
|
||||
}
|
||||
}
|
||||
|
||||
// parse tags from annotations
|
||||
// tags defined in annotations takes precedence over tags defined in
|
||||
// the labels.
|
||||
for k, v := range annotations {
|
||||
if strings.HasPrefix(k, zmonTagPrefixAnnotationKey) {
|
||||
key := strings.TrimPrefix(k, zmonTagPrefixAnnotationKey)
|
||||
tags[key] = v
|
||||
}
|
||||
}
|
||||
|
||||
// default aggregator is last
|
||||
aggregators := []string{"last"}
|
||||
if k, ok := config.Config[zmonAggregatorsLabelKey]; ok {
|
||||
|
@ -50,20 +50,6 @@ func TestZMONCollectorNewCollector(t *testing.T) {
|
||||
require.Equal(t, []string{"max"}, zmonCollector.aggregators)
|
||||
require.Equal(t, map[string]string{"alias": "cluster_alias"}, zmonCollector.tags)
|
||||
|
||||
// check that annotations overwrites labels
|
||||
hpa.ObjectMeta = metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
zmonKeyAnnotationKey: "annotation_key",
|
||||
zmonTagPrefixAnnotationKey + "alias": "cluster_alias_annotation",
|
||||
},
|
||||
}
|
||||
collector, err = collectPlugin.NewCollector(hpa, config, 1*time.Second)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, collector)
|
||||
zmonCollector = collector.(*ZMONCollector)
|
||||
require.Equal(t, "annotation_key", zmonCollector.key)
|
||||
require.Equal(t, map[string]string{"alias": "cluster_alias_annotation"}, zmonCollector.tags)
|
||||
|
||||
// should fail if the metric name isn't ZMON
|
||||
config.Metric = newMetricIdentifier("non-zmon-check")
|
||||
_, err = collectPlugin.NewCollector(nil, config, 1*time.Second)
|
||||
@ -131,7 +117,7 @@ func TestZMONCollectorGetMetrics(tt *testing.T) {
|
||||
dataPoints: ti.dataPoints,
|
||||
}
|
||||
|
||||
zmonCollector, err := NewZMONCollector(z, config, nil, 1*time.Second)
|
||||
zmonCollector, err := NewZMONCollector(z, config, 1*time.Second)
|
||||
require.NoError(t, err)
|
||||
|
||||
metrics, _ := zmonCollector.GetMetrics()
|
||||
|
@ -262,7 +262,7 @@ func (p *HPAProvider) collectMetrics(ctx context.Context) {
|
||||
}
|
||||
|
||||
// GetMetricByName gets a single metric by name.
|
||||
func (p *HPAProvider) GetMetricByName(name types.NamespacedName, info provider.CustomMetricInfo) (*custom_metrics.MetricValue, error) {
|
||||
func (p *HPAProvider) GetMetricByName(name types.NamespacedName, info provider.CustomMetricInfo, metricSelector labels.Selector) (*custom_metrics.MetricValue, error) {
|
||||
metric := p.metricStore.GetMetricsByName(name, info)
|
||||
if metric == nil {
|
||||
return nil, provider.NewMetricNotFoundForError(info.GroupResource, info.Metric, name.Name)
|
||||
@ -272,7 +272,7 @@ func (p *HPAProvider) GetMetricByName(name types.NamespacedName, info provider.C
|
||||
|
||||
// GetMetricBySelector returns metrics for namespaced resources by
|
||||
// label selector.
|
||||
func (p *HPAProvider) GetMetricBySelector(namespace string, selector labels.Selector, info provider.CustomMetricInfo) (*custom_metrics.MetricValueList, error) {
|
||||
func (p *HPAProvider) GetMetricBySelector(namespace string, selector labels.Selector, info provider.CustomMetricInfo, metricSelector labels.Selector) (*custom_metrics.MetricValueList, error) {
|
||||
return p.metricStore.GetMetricsBySelector(namespace, selector, info), nil
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,6 @@ import (
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/golang/glog"
|
||||
"github.com/kubernetes-incubator/custom-metrics-apiserver/pkg/cmd/server"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/spf13/cobra"
|
||||
@ -38,6 +37,7 @@ import (
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -111,7 +111,7 @@ func NewCommandStartAdapterServer(stopCh <-chan struct{}) *cobra.Command {
|
||||
func (o AdapterServerOptions) RunCustomMetricsAdapterServer(stopCh <-chan struct{}) error {
|
||||
go func() {
|
||||
http.Handle("/metrics", promhttp.Handler())
|
||||
glog.Fatal(http.ListenAndServe(o.MetricsAddress, nil))
|
||||
klog.Fatal(http.ListenAndServe(o.MetricsAddress, nil))
|
||||
}()
|
||||
|
||||
config, err := o.Config()
|
||||
|
Reference in New Issue
Block a user