Use labels for mapping metric types to metrics (#219)
* Use labels for mapping metric types to metrics Signed-off-by: Mikkel Oscar Lyderik Larsen <mikkel.larsen@zalando.de> * Log warning when old format is used Signed-off-by: Mikkel Oscar Lyderik Larsen <mikkel.larsen@zalando.de> * Test NewCollector logic for external metrics Signed-off-by: Mikkel Oscar Lyderik Larsen <mikkel.larsen@zalando.de>
This commit is contained in:
Mikkel Oscar Lyderik Larsen
committed by
GitHub
parent
bb107b678c
commit
df0ed1fca4
74
README.md
74
README.md
@ -22,7 +22,7 @@ kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: myapp-hpa
|
||||
annotations:
|
||||
# metric-config.<metricType>.<metricName>.<collectorName>/<configKey>
|
||||
# metric-config.<metricType>.<metricName>.<collectorType>/<configKey>
|
||||
metric-config.pods.requests-per-second.json-path/json-key: "$.http_server.rps"
|
||||
metric-config.pods.requests-per-second.json-path/path: /metrics
|
||||
metric-config.pods.requests-per-second.json-path/port: "9090"
|
||||
@ -104,7 +104,7 @@ kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: myapp-hpa
|
||||
annotations:
|
||||
# metric-config.<metricType>.<metricName>.<collectorName>/<configKey>
|
||||
# metric-config.<metricType>.<metricName>.<collectorType>/<configKey>
|
||||
metric-config.pods.requests-per-second.json-path/json-key: "$.http_server.rps"
|
||||
metric-config.pods.requests-per-second.json-path/path: /metrics
|
||||
metric-config.pods.requests-per-second.json-path/port: "9090"
|
||||
@ -216,11 +216,10 @@ Default is 1 minute.
|
||||
|
||||
This is an example of an HPA configured to get metrics based on a Prometheus
|
||||
query. The query is defined in the annotation
|
||||
`metric-config.external.prometheus-query.prometheus/processed-events-per-second`
|
||||
`metric-config.external.processed-events-per-second.prometheus/query`
|
||||
where `processed-events-per-second` is the query name which will be associated
|
||||
with the result of the query. A matching `query-name` label must be defined in
|
||||
the `matchLabels` of the metric definition. This allows having multiple
|
||||
prometheus queries associated with a single HPA.
|
||||
with the result of the query.
|
||||
This allows having multiple prometheus queries associated with a single HPA.
|
||||
|
||||
```yaml
|
||||
apiVersion: autoscaling/v2beta2
|
||||
@ -231,10 +230,9 @@ metadata:
|
||||
# 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: |
|
||||
metric-config.external.processed-events-per-second.prometheus/prometheus-server: http://prometheus.my-namespace.svc
|
||||
# metric-config.<metricType>.<metricName>.<collectorType>/<configKey>
|
||||
metric-config.external.processed-events-per-second.prometheus/query: |
|
||||
scalar(sum(rate(event-service_events_count{application="event-service",processed="true"}[1m])))
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
@ -247,10 +245,10 @@ spec:
|
||||
- type: External
|
||||
external:
|
||||
metric:
|
||||
name: prometheus-query
|
||||
name: processed-events-per-second
|
||||
selector:
|
||||
matchLabels:
|
||||
query-name: processed-events-per-second
|
||||
type: prometheus
|
||||
target:
|
||||
type: AverageValue
|
||||
averageValue: "10"
|
||||
@ -281,7 +279,7 @@ kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: myapp-hpa
|
||||
annotations:
|
||||
# metric-config.<metricType>.<metricName>.<collectorName>/<configKey>
|
||||
# metric-config.<metricType>.<metricName>.<collectorType>/<configKey>
|
||||
metric-config.object.processed-events-per-second.prometheus/query: |
|
||||
scalar(sum(rate(event-service_events_count{application="event-service",processed="true"}[1m])))
|
||||
metric-config.object.processed-events-per-second.prometheus/per-replica: "true"
|
||||
@ -382,10 +380,9 @@ we only support Flux instead of InfluxQL.
|
||||
|
||||
This is an example of an HPA configured to get metrics based on a Flux query.
|
||||
The query is defined in the annotation
|
||||
`metric-config.external.flux-query.influxdb/queue_depth`
|
||||
where `queue_depth` is the query name which will be associated with the result of the query.
|
||||
A matching `query-name` label must be defined in the `matchLabels` of the metric definition.
|
||||
This allows having multiple flux queries associated with a single HPA.
|
||||
`metric-config.external.<metricName>.influxdb/query` where `<metricName>` is
|
||||
the query name which will be associated with the result of the query. This
|
||||
allows having multiple flux queries associated with a single HPA.
|
||||
|
||||
```yaml
|
||||
apiVersion: autoscaling/v2beta2
|
||||
@ -399,13 +396,13 @@ metadata:
|
||||
# - --influxdb-address
|
||||
# - --influxdb-token
|
||||
# - --influxdb-org
|
||||
metric-config.external.flux-query.influxdb/address: "http://influxdbv2.my-namespace.svc"
|
||||
metric-config.external.flux-query.influxdb/token: "secret-token"
|
||||
metric-config.external.queue-depth.influxdb/address: "http://influxdbv2.my-namespace.svc"
|
||||
metric-config.external.queue-depth.influxdb/token: "secret-token"
|
||||
# This could be either the organization name or the ID.
|
||||
metric-config.external.flux-query.influxdb/org: "deadbeef"
|
||||
# metric-config.<metricType>.<metricName>.<collectorName>/<configKey>
|
||||
metric-config.external.queue-depth.influxdb/org: "deadbeef"
|
||||
# metric-config.<metricType>.<metricName>.<collectorType>/<configKey>
|
||||
# <configKey> == query-name
|
||||
metric-config.external.flux-query.influxdb/queue_depth: |
|
||||
metric-config.external.queue-depth.influxdb/query: |
|
||||
from(bucket: "apps")
|
||||
|> range(start: -30s)
|
||||
|> filter(fn: (r) => r._measurement == "queue_depth")
|
||||
@ -425,10 +422,10 @@ spec:
|
||||
- type: External
|
||||
external:
|
||||
metric:
|
||||
name: flux-query
|
||||
name: queue-depth
|
||||
selector:
|
||||
matchLabels:
|
||||
query-name: queue_depth
|
||||
type: influxdb
|
||||
target:
|
||||
type: Value
|
||||
value: "1"
|
||||
@ -490,9 +487,10 @@ spec:
|
||||
- type: External
|
||||
external:
|
||||
metric:
|
||||
name: sqs-queue-length
|
||||
name: my-sqs
|
||||
selector:
|
||||
matchLabels:
|
||||
type: sqs-queue-length
|
||||
queue-name: foobar
|
||||
region: eu-central-1
|
||||
target:
|
||||
@ -531,9 +529,9 @@ kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: myapp-hpa
|
||||
annotations:
|
||||
# metric-config.<metricType>.<metricName>.<collectorName>/<configKey>
|
||||
metric-config.external.zmon-check.zmon/key: "custom.*"
|
||||
metric-config.external.zmon-check.zmon/tag-application: "my-custom-app-*"
|
||||
# metric-config.<metricType>.<metricName>.<collectorType>/<configKey>
|
||||
metric-config.external.my-zmon-check.zmon/key: "custom.*"
|
||||
metric-config.external.my-zmon-check.zmon/tag-application: "my-custom-app-*"
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
@ -545,9 +543,10 @@ spec:
|
||||
- type: External
|
||||
external:
|
||||
metric:
|
||||
name: zmon-check
|
||||
name: my-zmon-check
|
||||
selector:
|
||||
matchLabels:
|
||||
type: zmon
|
||||
check-id: "1234" # the ZMON check to query for metrics
|
||||
key: "custom.value"
|
||||
tag-application: my-custom-app
|
||||
@ -597,8 +596,8 @@ specify a duration of `5m` then the query will return metric points for the
|
||||
last 5 minutes and apply the specified aggregation with the same duration .e.g
|
||||
`max(5m)`.
|
||||
|
||||
The annotations `metric-config.external.zmon-check.zmon/key` and
|
||||
`metric-config.external.zmon-check.zmon/tag-<name>` can be optionally used if
|
||||
The annotations `metric-config.external.my-zmon-check.zmon/key` and
|
||||
`metric-config.external.my-zmon-check.zmon/tag-<name>` can be optionally used if
|
||||
you need to define a `key` or other `tag` with a "star" query syntax like
|
||||
`values.*`. This *hack* is in place because it's not allowed to use `*` in the
|
||||
metric label definitions. If both annotations and corresponding label is
|
||||
@ -626,10 +625,10 @@ kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: myapp-hpa
|
||||
annotations:
|
||||
# metric-config.<metricType>.<metricName>.<collectorName>/<configKey>
|
||||
metric-config.external.http.json/json-key: "$.some-metric.value"
|
||||
metric-config.external.http.json/endpoint: "http://metric-source.app-namespace:8080/metrics"
|
||||
metric-config.external.http.json/aggregator: "max"
|
||||
# metric-config.<metricType>.<metricName>.<collectorType>/<configKey>
|
||||
metric-config.external.unique-metric-name.json-path/json-key: "$.some-metric.value"
|
||||
metric-config.external.unique-metric-name.json-path/endpoint: "http://metric-source.app-namespace:8080/metrics"
|
||||
metric-config.external.unique-metric-name.json-path/aggregator: "max"
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
@ -641,10 +640,10 @@ spec:
|
||||
- type: External
|
||||
external:
|
||||
metric:
|
||||
name: http
|
||||
name: unique-metric-name
|
||||
selector:
|
||||
matchLabels:
|
||||
identifier: unique-metric-name
|
||||
type: json-path
|
||||
target:
|
||||
averageValue: 1
|
||||
type: AverageValue
|
||||
@ -659,4 +658,3 @@ target. The following configuration values are supported:
|
||||
in the namespace `app-namespace` is called.
|
||||
- `aggregator` is only required if the metric is an array of values and specifies how the values
|
||||
are aggregated. Currently this option can support the values: `sum`, `max`, `min`, `avg`.
|
||||
|
||||
|
@ -6,7 +6,7 @@ metadata:
|
||||
labels:
|
||||
application: custom-metrics-consumer
|
||||
annotations:
|
||||
# metric-config.<metricType>.<metricName>.<collectorName>/<configKey>
|
||||
# metric-config.<metricType>.<metricName>.<collectorType>/<configKey>
|
||||
metric-config.pods.queue-length.json-path/json-key: "$.queue.length"
|
||||
metric-config.pods.queue-length.json-path/path: /metrics
|
||||
metric-config.pods.queue-length.json-path/port: "9090"
|
||||
@ -50,9 +50,10 @@ spec:
|
||||
- type: External
|
||||
external:
|
||||
metric:
|
||||
name: sqs-queue-length
|
||||
name: app-queue-length
|
||||
selector:
|
||||
matchLabels:
|
||||
type: sqs-queue-length
|
||||
queue-name: foobar
|
||||
region: eu-central-1
|
||||
target:
|
||||
|
@ -15,7 +15,7 @@ const (
|
||||
)
|
||||
|
||||
type AnnotationConfigs struct {
|
||||
CollectorName string
|
||||
CollectorType string
|
||||
Configs map[string]string
|
||||
PerReplica bool
|
||||
Interval time.Duration
|
||||
@ -64,14 +64,14 @@ func (m AnnotationConfigMap) Parse(annotations map[string]string) error {
|
||||
config, ok := m[key]
|
||||
if !ok {
|
||||
config = &AnnotationConfigs{
|
||||
CollectorName: metricCollector,
|
||||
CollectorType: metricCollector,
|
||||
Configs: map[string]string{},
|
||||
}
|
||||
m[key] = config
|
||||
}
|
||||
|
||||
// TODO: fail if collector name doesn't match
|
||||
if config.CollectorName != metricCollector {
|
||||
if config.CollectorType != metricCollector {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -4,12 +4,17 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/zalando-incubator/kube-metrics-adapter/pkg/annotations"
|
||||
autoscalingv2 "k8s.io/api/autoscaling/v2beta2"
|
||||
"k8s.io/metrics/pkg/apis/custom_metrics"
|
||||
"k8s.io/metrics/pkg/apis/external_metrics"
|
||||
)
|
||||
|
||||
const (
|
||||
typeLabelKey = "type"
|
||||
)
|
||||
|
||||
type ObjectReference struct {
|
||||
autoscalingv2.CrossVersionObjectReference
|
||||
Namespace string
|
||||
@ -19,6 +24,7 @@ type CollectorFactory struct {
|
||||
podsPlugins pluginMap
|
||||
objectPlugins objectPluginMap
|
||||
externalPlugins map[string]CollectorPlugin
|
||||
logger *log.Entry
|
||||
}
|
||||
|
||||
type objectPluginMap struct {
|
||||
@ -39,6 +45,7 @@ func NewCollectorFactory() *CollectorFactory {
|
||||
Named: map[string]*pluginMap{},
|
||||
},
|
||||
externalPlugins: map[string]CollectorPlugin{},
|
||||
logger: log.WithFields(log.Fields{"collector": "true"}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,7 +119,7 @@ func (c *CollectorFactory) NewCollector(hpa *autoscalingv2.HorizontalPodAutoscal
|
||||
switch config.Type {
|
||||
case autoscalingv2.PodsMetricSourceType:
|
||||
// first try to find a plugin by format
|
||||
if plugin, ok := c.podsPlugins.Named[config.CollectorName]; ok {
|
||||
if plugin, ok := c.podsPlugins.Named[config.CollectorType]; ok {
|
||||
return plugin.NewCollector(hpa, config, interval)
|
||||
}
|
||||
|
||||
@ -123,7 +130,7 @@ func (c *CollectorFactory) NewCollector(hpa *autoscalingv2.HorizontalPodAutoscal
|
||||
case autoscalingv2.ObjectMetricSourceType:
|
||||
// first try to find a plugin by kind
|
||||
if kinds, ok := c.objectPlugins.Named[config.ObjectReference.Kind]; ok {
|
||||
if plugin, ok := kinds.Named[config.CollectorName]; ok {
|
||||
if plugin, ok := kinds.Named[config.CollectorType]; ok {
|
||||
return plugin.NewCollector(hpa, config, interval)
|
||||
}
|
||||
|
||||
@ -134,7 +141,7 @@ func (c *CollectorFactory) NewCollector(hpa *autoscalingv2.HorizontalPodAutoscal
|
||||
}
|
||||
|
||||
// else try to find a default plugin for this kind
|
||||
if plugin, ok := c.objectPlugins.Any.Named[config.CollectorName]; ok {
|
||||
if plugin, ok := c.objectPlugins.Any.Named[config.CollectorType]; ok {
|
||||
return plugin.NewCollector(hpa, config, interval)
|
||||
}
|
||||
|
||||
@ -142,7 +149,21 @@ func (c *CollectorFactory) NewCollector(hpa *autoscalingv2.HorizontalPodAutoscal
|
||||
return c.objectPlugins.Any.Any.NewCollector(hpa, config, interval)
|
||||
}
|
||||
case autoscalingv2.ExternalMetricSourceType:
|
||||
if plugin, ok := c.externalPlugins[config.Metric.Name]; ok {
|
||||
// First type to get metric type from the `type` label,
|
||||
// otherwise fall back to the legacy metric name based mapping.
|
||||
var pluginKey string
|
||||
if config.Metric.Selector != nil && config.Metric.Selector.MatchLabels != nil {
|
||||
if typ, ok := config.Metric.Selector.MatchLabels[typeLabelKey]; ok {
|
||||
pluginKey = typ
|
||||
}
|
||||
}
|
||||
|
||||
if pluginKey == "" {
|
||||
pluginKey = config.Metric.Name
|
||||
c.logger.Warnf("HPA %s/%s is using deprecated metric type identifier '%s'", hpa.Namespace, hpa.Name, config.Metric.Name)
|
||||
}
|
||||
|
||||
if plugin, ok := c.externalPlugins[pluginKey]; ok {
|
||||
return plugin.NewCollector(hpa, config, interval)
|
||||
}
|
||||
}
|
||||
@ -168,7 +189,7 @@ type Collector interface {
|
||||
|
||||
type MetricConfig struct {
|
||||
MetricTypeName
|
||||
CollectorName string
|
||||
CollectorType string
|
||||
Config map[string]string
|
||||
ObjectReference custom_metrics.ObjectReference
|
||||
PerReplica bool
|
||||
@ -228,7 +249,7 @@ func ParseHPAMetrics(hpa *autoscalingv2.HorizontalPodAutoscaler) ([]*MetricConfi
|
||||
|
||||
annotationConfigs, present := parser.GetAnnotationConfig(typeName.Metric.Name, typeName.Type)
|
||||
if present {
|
||||
config.CollectorName = annotationConfigs.CollectorName
|
||||
config.CollectorType = annotationConfigs.CollectorType
|
||||
config.Interval = annotationConfigs.Interval
|
||||
config.PerReplica = annotationConfigs.PerReplica
|
||||
// configs specified in annotations takes precedence
|
||||
|
129
pkg/collector/collector_test.go
Normal file
129
pkg/collector/collector_test.go
Normal file
@ -0,0 +1,129 @@
|
||||
package collector
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
autoscalingv2 "k8s.io/api/autoscaling/v2beta2"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type mockCollectorPlugin struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (c *mockCollectorPlugin) NewCollector(hpa *autoscalingv2.HorizontalPodAutoscaler, config *MetricConfig, interval time.Duration) (Collector, error) {
|
||||
return &mockCollector{Name: c.Name}, nil
|
||||
}
|
||||
|
||||
type mockCollector struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (c *mockCollector) GetMetrics() ([]CollectedMetric, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *mockCollector) Interval() time.Duration {
|
||||
return 0
|
||||
}
|
||||
|
||||
func TestNewCollector(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
msg string
|
||||
hpa *autoscalingv2.HorizontalPodAutoscaler
|
||||
expectedCollector string
|
||||
}{
|
||||
{
|
||||
msg: "should get create collector type from legacy metric name",
|
||||
hpa: &autoscalingv2.HorizontalPodAutoscaler{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{},
|
||||
},
|
||||
Spec: autoscalingv2.HorizontalPodAutoscalerSpec{
|
||||
Metrics: []autoscalingv2.MetricSpec{
|
||||
{
|
||||
Type: autoscalingv2.ExternalMetricSourceType,
|
||||
External: &autoscalingv2.ExternalMetricSource{
|
||||
Metric: autoscalingv2.MetricIdentifier{
|
||||
Name: "external-1",
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{"x": "y"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedCollector: "external-1",
|
||||
},
|
||||
{
|
||||
msg: "should get create collector type from type label (ignore legacy metric name)",
|
||||
hpa: &autoscalingv2.HorizontalPodAutoscaler{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{},
|
||||
},
|
||||
Spec: autoscalingv2.HorizontalPodAutoscalerSpec{
|
||||
Metrics: []autoscalingv2.MetricSpec{
|
||||
{
|
||||
Type: autoscalingv2.ExternalMetricSourceType,
|
||||
External: &autoscalingv2.ExternalMetricSource{
|
||||
Metric: autoscalingv2.MetricIdentifier{
|
||||
Name: "external-1",
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{"type": "external-2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedCollector: "external-2",
|
||||
},
|
||||
{
|
||||
msg: "should not find collector when no collector matches",
|
||||
hpa: &autoscalingv2.HorizontalPodAutoscaler{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{},
|
||||
},
|
||||
Spec: autoscalingv2.HorizontalPodAutoscalerSpec{
|
||||
Metrics: []autoscalingv2.MetricSpec{
|
||||
{
|
||||
Type: autoscalingv2.ExternalMetricSourceType,
|
||||
External: &autoscalingv2.ExternalMetricSource{
|
||||
Metric: autoscalingv2.MetricIdentifier{
|
||||
Name: "external-3",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedCollector: "",
|
||||
},
|
||||
} {
|
||||
t.Run(tc.msg, func(t *testing.T) {
|
||||
collectorFactory := NewCollectorFactory()
|
||||
for _, collector := range []string{"1", "2"} {
|
||||
collectorFactory.RegisterExternalCollector([]string{"external-" + collector}, &mockCollectorPlugin{Name: "external-" + collector})
|
||||
}
|
||||
configs, err := ParseHPAMetrics(tc.hpa)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, configs, 1)
|
||||
|
||||
collector, err := collectorFactory.NewCollector(tc.hpa, configs[0], 0)
|
||||
if tc.expectedCollector == "" {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
|
||||
c, ok := collector.(*mockCollector)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, tc.expectedCollector, c.Name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -14,7 +14,8 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
HTTPMetricName = "http"
|
||||
HTTPJSONPathType = "json-path"
|
||||
HTTPMetricNameLegacy = "http"
|
||||
HTTPEndpointAnnotationKey = "endpoint"
|
||||
HTTPJsonPathAnnotationKey = "json-key"
|
||||
identifierLabel = "identifier"
|
||||
|
@ -15,7 +15,8 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
InfluxDBMetricName = "flux-query"
|
||||
InfluxDBMetricType = "influxdb"
|
||||
InfluxDBMetricNameLegacy = "flux-query"
|
||||
influxDBAddressKey = "address"
|
||||
influxDBTokenKey = "token"
|
||||
influxDBOrgKey = "org"
|
||||
|
@ -24,7 +24,7 @@ func TestInfluxDBCollector_New(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
CollectorName: "influxdb",
|
||||
CollectorType: "influxdb",
|
||||
Config: map[string]string{
|
||||
"range1m": `from(bucket: "?") |> range(start: -1m)`,
|
||||
"range2m": `from(bucket: "?") |> range(start: -2m)`,
|
||||
@ -62,7 +62,7 @@ func TestInfluxDBCollector_New(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
CollectorName: "influxdb",
|
||||
CollectorType: "influxdb",
|
||||
Config: map[string]string{
|
||||
"range1m": `from(bucket: "?") |> range(start: -1m)`,
|
||||
"range2m": `from(bucket: "?") |> range(start: -2m)`,
|
||||
@ -140,7 +140,7 @@ func TestInfluxDBCollector_New(t *testing.T) {
|
||||
t.Run("error - "+tc.name, func(t *testing.T) {
|
||||
m := &MetricConfig{
|
||||
MetricTypeName: tc.mTypeName,
|
||||
CollectorName: "influxdb",
|
||||
CollectorType: "influxdb",
|
||||
Config: tc.config,
|
||||
}
|
||||
_, err := NewInfluxDBCollector("http://localhost:9999", "secret", "deadbeef", m, time.Second)
|
||||
|
@ -61,7 +61,7 @@ func NewPodCollector(client kubernetes.Interface, hpa *autoscalingv2.HorizontalP
|
||||
}
|
||||
|
||||
var getter httpmetrics.PodMetricsGetter
|
||||
switch config.CollectorName {
|
||||
switch config.CollectorType {
|
||||
case "json-path":
|
||||
var err error
|
||||
getter, err = httpmetrics.NewPodMetricsJSONPathGetter(config.Config)
|
||||
@ -69,7 +69,7 @@ func NewPodCollector(client kubernetes.Interface, hpa *autoscalingv2.HorizontalP
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("format '%s' not supported", config.CollectorName)
|
||||
return nil, fmt.Errorf("format '%s' not supported", config.CollectorType)
|
||||
}
|
||||
|
||||
c.Getter = getter
|
||||
|
@ -97,7 +97,7 @@ func makeTestHTTPServer(t *testing.T, values [][]int64) (string, string, *testMe
|
||||
|
||||
func makeTestConfig(port string) *MetricConfig {
|
||||
return &MetricConfig{
|
||||
CollectorName: "json-path",
|
||||
CollectorType: "json-path",
|
||||
Config: map[string]string{"json-key": "$.values", "port": port, "path": "/metrics", "aggregator": "sum"},
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,8 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
PrometheusMetricName = "prometheus-query"
|
||||
PrometheusMetricType = "prometheus"
|
||||
PrometheusMetricNameLegacy = "prometheus-query"
|
||||
prometheusQueryNameLabelKey = "query-name"
|
||||
prometheusServerAnnotationKey = "prometheus-server"
|
||||
)
|
||||
|
@ -14,9 +14,10 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// ZMONCheckMetric defines the metric name for metrics based on ZMON
|
||||
// ZMONMetricType defines the metric type for metrics based on ZMON
|
||||
// checks.
|
||||
ZMONCheckMetric = "zmon-check"
|
||||
ZMONMetricType = "zmon"
|
||||
ZMONCheckMetricLegacy = "zmon-check"
|
||||
zmonCheckIDLabelKey = "check-id"
|
||||
zmonKeyLabelKey = "key"
|
||||
zmonDurationLabelKey = "duration"
|
||||
@ -42,12 +43,7 @@ func NewZMONCollectorPlugin(zmon zmon.ZMON) (*ZMONCollectorPlugin, error) {
|
||||
|
||||
// NewCollector initializes a new ZMON collector from the specified HPA.
|
||||
func (c *ZMONCollectorPlugin) NewCollector(hpa *autoscalingv2.HorizontalPodAutoscaler, config *MetricConfig, interval time.Duration) (Collector, error) {
|
||||
switch config.Metric.Name {
|
||||
case ZMONCheckMetric:
|
||||
return NewZMONCollector(c.zmon, config, interval)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("metric '%s' not supported", config.Metric.Name)
|
||||
return NewZMONCollector(c.zmon, config, interval)
|
||||
}
|
||||
|
||||
// ZMONCollector defines a collector that is able to collect metrics from ZMON.
|
||||
|
@ -26,7 +26,7 @@ func TestZMONCollectorNewCollector(t *testing.T) {
|
||||
|
||||
config := &MetricConfig{
|
||||
MetricTypeName: MetricTypeName{
|
||||
Metric: newMetricIdentifier(ZMONCheckMetric),
|
||||
Metric: newMetricIdentifier("foo-check", ZMONMetricType),
|
||||
},
|
||||
Config: map[string]string{
|
||||
zmonCheckIDLabelKey: "1234",
|
||||
@ -50,28 +50,26 @@ func TestZMONCollectorNewCollector(t *testing.T) {
|
||||
require.Equal(t, []string{"max"}, zmonCollector.aggregators)
|
||||
require.Equal(t, map[string]string{"alias": "cluster_alias"}, 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)
|
||||
require.Error(t, err)
|
||||
|
||||
// should fail if the check id is not specified.
|
||||
delete(config.Config, zmonCheckIDLabelKey)
|
||||
config.Metric.Name = ZMONCheckMetric
|
||||
config.Metric.Name = "foo-check"
|
||||
_, err = collectPlugin.NewCollector(nil, config, 1*time.Second)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func newMetricIdentifier(metricName string) autoscalingv2.MetricIdentifier {
|
||||
selector := metav1.LabelSelector{}
|
||||
func newMetricIdentifier(metricName, metricType string) autoscalingv2.MetricIdentifier {
|
||||
selector := metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"type": metricType,
|
||||
},
|
||||
}
|
||||
return autoscalingv2.MetricIdentifier{Name: metricName, Selector: &selector}
|
||||
}
|
||||
|
||||
func TestZMONCollectorGetMetrics(tt *testing.T) {
|
||||
|
||||
config := &MetricConfig{
|
||||
MetricTypeName: MetricTypeName{
|
||||
Metric: newMetricIdentifier(ZMONCheckMetric),
|
||||
Metric: newMetricIdentifier("foo-check", ZMONMetricType),
|
||||
Type: "foo",
|
||||
},
|
||||
Config: map[string]string{
|
||||
|
@ -174,7 +174,7 @@ func (o AdapterServerOptions) RunCustomMetricsAdapterServer(stopCh <-chan struct
|
||||
return fmt.Errorf("failed to register prometheus object collector plugin: %v", err)
|
||||
}
|
||||
|
||||
collectorFactory.RegisterExternalCollector([]string{collector.PrometheusMetricName}, promPlugin)
|
||||
collectorFactory.RegisterExternalCollector([]string{collector.PrometheusMetricType, collector.PrometheusMetricNameLegacy}, promPlugin)
|
||||
|
||||
// skipper collector can only be enabled if prometheus is.
|
||||
if o.SkipperIngressMetrics {
|
||||
@ -195,11 +195,11 @@ func (o AdapterServerOptions) RunCustomMetricsAdapterServer(stopCh <-chan struct
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to initialize InfluxDB collector plugin: %v", err)
|
||||
}
|
||||
collectorFactory.RegisterExternalCollector([]string{collector.InfluxDBMetricName}, influxdbPlugin)
|
||||
collectorFactory.RegisterExternalCollector([]string{collector.InfluxDBMetricType, collector.InfluxDBMetricNameLegacy}, influxdbPlugin)
|
||||
}
|
||||
|
||||
plugin, _ := collector.NewHTTPCollectorPlugin()
|
||||
collectorFactory.RegisterExternalCollector([]string{collector.HTTPMetricName}, plugin)
|
||||
collectorFactory.RegisterExternalCollector([]string{collector.HTTPJSONPathType, collector.HTTPMetricNameLegacy}, plugin)
|
||||
// register generic pod collector
|
||||
err = collectorFactory.RegisterPodsCollector("", collector.NewPodCollectorPlugin(client))
|
||||
if err != nil {
|
||||
@ -224,7 +224,7 @@ func (o AdapterServerOptions) RunCustomMetricsAdapterServer(stopCh <-chan struct
|
||||
return fmt.Errorf("failed to initialize ZMON collector plugin: %v", err)
|
||||
}
|
||||
|
||||
collectorFactory.RegisterExternalCollector([]string{collector.ZMONCheckMetric}, zmonPlugin)
|
||||
collectorFactory.RegisterExternalCollector([]string{collector.ZMONMetricType, collector.ZMONCheckMetricLegacy}, zmonPlugin)
|
||||
}
|
||||
|
||||
awsSessions := make(map[string]*session.Session, len(o.AWSRegions))
|
||||
|
Reference in New Issue
Block a user