pkg/collectors: Refactor hpa collector
This commit is contained in:
parent
3778527880
commit
ce5c90fbf1
|
|
@ -178,6 +178,13 @@ func TestFullScrapeCycle(t *testing.T) {
|
||||||
# HELP kube_endpoint_labels Kubernetes labels converted to Prometheus labels.
|
# HELP kube_endpoint_labels Kubernetes labels converted to Prometheus labels.
|
||||||
# HELP kube_endpoint_address_available Number of addresses available in endpoint.
|
# HELP kube_endpoint_address_available Number of addresses available in endpoint.
|
||||||
# HELP kube_endpoint_address_not_ready Number of addresses not ready in endpoint
|
# HELP kube_endpoint_address_not_ready Number of addresses not ready in endpoint
|
||||||
|
# HELP kube_hpa_metadata_generation The generation observed by the HorizontalPodAutoscaler controller.
|
||||||
|
# HELP kube_hpa_spec_max_replicas Upper limit for the number of pods that can be set by the autoscaler; cannot be smaller than MinReplicas.
|
||||||
|
# HELP kube_hpa_spec_min_replicas Lower limit for the number of pods that can be set by the autoscaler, default 1.
|
||||||
|
# HELP kube_hpa_status_current_replicas Current number of replicas of pods managed by this autoscaler.
|
||||||
|
# HELP kube_hpa_status_desired_replicas Desired number of replicas of pods managed by this autoscaler.
|
||||||
|
# HELP kube_hpa_labels Kubernetes labels converted to Prometheus labels.
|
||||||
|
# HELP kube_hpa_status_condition The condition of this autoscaler.
|
||||||
# HELP kube_job_labels Kubernetes labels converted to Prometheus labels.
|
# HELP kube_job_labels Kubernetes labels converted to Prometheus labels.
|
||||||
# HELP kube_job_info Information about job.
|
# HELP kube_job_info Information about job.
|
||||||
# HELP kube_job_created Unix creation timestamp
|
# HELP kube_job_created Unix creation timestamp
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import (
|
||||||
"k8s.io/kube-state-metrics/pkg/options"
|
"k8s.io/kube-state-metrics/pkg/options"
|
||||||
|
|
||||||
apps "k8s.io/api/apps/v1beta1"
|
apps "k8s.io/api/apps/v1beta1"
|
||||||
// autoscaling "k8s.io/api/autoscaling/v2beta1"
|
autoscaling "k8s.io/api/autoscaling/v2beta1"
|
||||||
batchv1 "k8s.io/api/batch/v1"
|
batchv1 "k8s.io/api/batch/v1"
|
||||||
batchv1beta1 "k8s.io/api/batch/v1beta1"
|
batchv1beta1 "k8s.io/api/batch/v1beta1"
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
|
|
@ -116,26 +116,26 @@ func (b *Builder) Build() []*Collector {
|
||||||
}
|
}
|
||||||
|
|
||||||
var availableCollectors = map[string]func(f *Builder) *Collector{
|
var availableCollectors = map[string]func(f *Builder) *Collector{
|
||||||
"configmaps": func(b *Builder) *Collector { return b.buildConfigMapCollector() },
|
"configmaps": func(b *Builder) *Collector { return b.buildConfigMapCollector() },
|
||||||
"cronjobs": func(b *Builder) *Collector { return b.buildCronJobCollector() },
|
"cronjobs": func(b *Builder) *Collector { return b.buildCronJobCollector() },
|
||||||
"daemonsets": func(b *Builder) *Collector { return b.buildDaemonSetCollector() },
|
"daemonsets": func(b *Builder) *Collector { return b.buildDaemonSetCollector() },
|
||||||
"deployments": func(b *Builder) *Collector { return b.buildDeploymentCollector() },
|
"deployments": func(b *Builder) *Collector { return b.buildDeploymentCollector() },
|
||||||
"endpoints": func(b *Builder) *Collector { return b.buildEndpointsCollector() },
|
"endpoints": func(b *Builder) *Collector { return b.buildEndpointsCollector() },
|
||||||
"jobs": func(b *Builder) *Collector { return b.buildJobCollector() },
|
"horizontalpodautoscalers": func(b *Builder) *Collector { return b.buildHPACollector() },
|
||||||
"limitranges": func(b *Builder) *Collector { return b.buildLimitRangeCollector() },
|
"jobs": func(b *Builder) *Collector { return b.buildJobCollector() },
|
||||||
"namespaces": func(b *Builder) *Collector { return b.buildNamespaceCollector() },
|
"limitranges": func(b *Builder) *Collector { return b.buildLimitRangeCollector() },
|
||||||
"nodes": func(b *Builder) *Collector { return b.buildNodeCollector() },
|
"namespaces": func(b *Builder) *Collector { return b.buildNamespaceCollector() },
|
||||||
"persistentvolumeclaims": func(b *Builder) *Collector { return b.buildPersistentVolumeClaimCollector() },
|
"nodes": func(b *Builder) *Collector { return b.buildNodeCollector() },
|
||||||
"persistentvolumes": func(b *Builder) *Collector { return b.buildPersistentVolumeCollector() },
|
"persistentvolumeclaims": func(b *Builder) *Collector { return b.buildPersistentVolumeClaimCollector() },
|
||||||
"poddisruptionbudgets": func(b *Builder) *Collector { return b.buildPodDisruptionBudgetCollector() },
|
"persistentvolumes": func(b *Builder) *Collector { return b.buildPersistentVolumeCollector() },
|
||||||
"pods": func(b *Builder) *Collector { return b.buildPodCollector() },
|
"poddisruptionbudgets": func(b *Builder) *Collector { return b.buildPodDisruptionBudgetCollector() },
|
||||||
"replicasets": func(b *Builder) *Collector { return b.buildReplicaSetCollector() },
|
"pods": func(b *Builder) *Collector { return b.buildPodCollector() },
|
||||||
"replicationcontrollers": func(b *Builder) *Collector { return b.buildReplicationControllerCollector() },
|
"replicasets": func(b *Builder) *Collector { return b.buildReplicaSetCollector() },
|
||||||
"resourcequotas": func(b *Builder) *Collector { return b.buildResourceQuotaCollector() },
|
"replicationcontrollers": func(b *Builder) *Collector { return b.buildReplicationControllerCollector() },
|
||||||
"secrets": func(b *Builder) *Collector { return b.buildSecretCollector() },
|
"resourcequotas": func(b *Builder) *Collector { return b.buildResourceQuotaCollector() },
|
||||||
"services": func(b *Builder) *Collector { return b.buildServiceCollector() },
|
"secrets": func(b *Builder) *Collector { return b.buildSecretCollector() },
|
||||||
"statefulsets": func(b *Builder) *Collector { return b.buildStatefulSetCollector() },
|
"services": func(b *Builder) *Collector { return b.buildServiceCollector() },
|
||||||
// "horizontalpodautoscalers": func(b *Builder) *Collector { return b.buildHPACollector() },
|
"statefulsets": func(b *Builder) *Collector { return b.buildStatefulSetCollector() },
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Builder) buildConfigMapCollector() *Collector {
|
func (b *Builder) buildConfigMapCollector() *Collector {
|
||||||
|
|
@ -213,6 +213,21 @@ func (b *Builder) buildEndpointsCollector() *Collector {
|
||||||
return NewCollector(store)
|
return NewCollector(store)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Builder) buildHPACollector() *Collector {
|
||||||
|
filteredMetricFamilies := filterMetricFamilies(b.whiteBlackList, hpaMetricFamilies)
|
||||||
|
composedMetricGenFuncs := composeMetricGenFuncs(filteredMetricFamilies)
|
||||||
|
|
||||||
|
helpTexts := extractHelpText(filteredMetricFamilies)
|
||||||
|
|
||||||
|
store := metricsstore.NewMetricsStore(
|
||||||
|
helpTexts,
|
||||||
|
composedMetricGenFuncs,
|
||||||
|
)
|
||||||
|
reflectorPerNamespace(b.ctx, b.kubeClient, &autoscaling.HorizontalPodAutoscaler{}, store, b.namespaces, createHPAListWatch)
|
||||||
|
|
||||||
|
return NewCollector(store)
|
||||||
|
}
|
||||||
|
|
||||||
func (b *Builder) buildJobCollector() *Collector {
|
func (b *Builder) buildJobCollector() *Collector {
|
||||||
filteredMetricFamilies := filterMetricFamilies(b.whiteBlackList, jobMetricFamilies)
|
filteredMetricFamilies := filterMetricFamilies(b.whiteBlackList, jobMetricFamilies)
|
||||||
composedMetricGenFuncs := composeMetricGenFuncs(filteredMetricFamilies)
|
composedMetricGenFuncs := composeMetricGenFuncs(filteredMetricFamilies)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,147 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package collectors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/kube-state-metrics/pkg/metrics"
|
||||||
|
|
||||||
|
autoscaling "k8s.io/api/autoscaling/v2beta1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/watch"
|
||||||
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
|
"k8s.io/client-go/tools/cache"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
descHorizontalPodAutoscalerLabelsName = "kube_hpa_labels"
|
||||||
|
descHorizontalPodAutoscalerLabelsHelp = "Kubernetes labels converted to Prometheus labels."
|
||||||
|
descHorizontalPodAutoscalerLabelsDefaultLabels = []string{"namespace", "hpa"}
|
||||||
|
|
||||||
|
hpaMetricFamilies = []metrics.FamilyGenerator{
|
||||||
|
metrics.FamilyGenerator{
|
||||||
|
Name: "kube_hpa_metadata_generation",
|
||||||
|
Help: "The generation observed by the HorizontalPodAutoscaler controller.",
|
||||||
|
GenerateFunc: wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) metrics.Family {
|
||||||
|
return metrics.Family{&metrics.Metric{
|
||||||
|
Name: "kube_hpa_metadata_generation",
|
||||||
|
Value: float64(a.ObjectMeta.Generation),
|
||||||
|
}}
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
metrics.FamilyGenerator{
|
||||||
|
Name: "kube_hpa_spec_max_replicas",
|
||||||
|
Help: "Upper limit for the number of pods that can be set by the autoscaler; cannot be smaller than MinReplicas.",
|
||||||
|
GenerateFunc: wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) metrics.Family {
|
||||||
|
return metrics.Family{&metrics.Metric{
|
||||||
|
Name: "kube_hpa_spec_max_replicas",
|
||||||
|
Value: float64(a.Spec.MaxReplicas),
|
||||||
|
}}
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
metrics.FamilyGenerator{
|
||||||
|
Name: "kube_hpa_spec_min_replicas",
|
||||||
|
Help: "Lower limit for the number of pods that can be set by the autoscaler, default 1.",
|
||||||
|
GenerateFunc: wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) metrics.Family {
|
||||||
|
return metrics.Family{&metrics.Metric{
|
||||||
|
Name: "kube_hpa_spec_min_replicas",
|
||||||
|
Value: float64(*a.Spec.MinReplicas),
|
||||||
|
}}
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
metrics.FamilyGenerator{
|
||||||
|
Name: "kube_hpa_status_current_replicas",
|
||||||
|
Help: "Current number of replicas of pods managed by this autoscaler.",
|
||||||
|
GenerateFunc: wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) metrics.Family {
|
||||||
|
return metrics.Family{&metrics.Metric{
|
||||||
|
Name: "kube_hpa_status_current_replicas",
|
||||||
|
Value: float64(a.Status.CurrentReplicas),
|
||||||
|
}}
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
metrics.FamilyGenerator{
|
||||||
|
Name: "kube_hpa_status_desired_replicas",
|
||||||
|
Help: "Desired number of replicas of pods managed by this autoscaler.",
|
||||||
|
GenerateFunc: wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) metrics.Family {
|
||||||
|
return metrics.Family{&metrics.Metric{
|
||||||
|
Name: "kube_hpa_status_desired_replicas",
|
||||||
|
Value: float64(a.Status.DesiredReplicas),
|
||||||
|
}}
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
metrics.FamilyGenerator{
|
||||||
|
Name: descHorizontalPodAutoscalerLabelsName,
|
||||||
|
Help: descHorizontalPodAutoscalerLabelsHelp,
|
||||||
|
GenerateFunc: wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) metrics.Family {
|
||||||
|
labelKeys, labelValues := kubeLabelsToPrometheusLabels(a.Labels)
|
||||||
|
return metrics.Family{&metrics.Metric{
|
||||||
|
Name: descHorizontalPodAutoscalerLabelsName,
|
||||||
|
LabelKeys: labelKeys,
|
||||||
|
LabelValues: labelValues,
|
||||||
|
Value: 1,
|
||||||
|
}}
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
metrics.FamilyGenerator{
|
||||||
|
Name: "kube_hpa_status_condition",
|
||||||
|
Help: "The condition of this autoscaler.",
|
||||||
|
GenerateFunc: wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) metrics.Family {
|
||||||
|
f := metrics.Family{}
|
||||||
|
|
||||||
|
for _, c := range a.Status.Conditions {
|
||||||
|
metrics := addConditionMetrics(c.Status)
|
||||||
|
|
||||||
|
for _, m := range metrics {
|
||||||
|
metric := m
|
||||||
|
metric.Name = "kube_hpa_status_condition"
|
||||||
|
metric.LabelKeys = []string{"condition", "status"}
|
||||||
|
metric.LabelValues = append(metric.LabelValues, string(c.Type))
|
||||||
|
f = append(f, metric)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return f
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func wrapHPAFunc(f func(*autoscaling.HorizontalPodAutoscaler) metrics.Family) func(interface{}) metrics.Family {
|
||||||
|
return func(obj interface{}) metrics.Family {
|
||||||
|
hpa := obj.(*autoscaling.HorizontalPodAutoscaler)
|
||||||
|
|
||||||
|
metricFamily := f(hpa)
|
||||||
|
|
||||||
|
for _, m := range metricFamily {
|
||||||
|
m.LabelKeys = append(descHorizontalPodAutoscalerLabelsDefaultLabels, m.LabelKeys...)
|
||||||
|
m.LabelValues = append([]string{hpa.Namespace, hpa.Name}, m.LabelValues...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return metricFamily
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createHPAListWatch(kubeClient clientset.Interface, ns string) cache.ListWatch {
|
||||||
|
return cache.ListWatch{
|
||||||
|
ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
|
||||||
|
return kubeClient.AutoscalingV2beta1().HorizontalPodAutoscalers(ns).List(opts)
|
||||||
|
},
|
||||||
|
WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
|
||||||
|
return kubeClient.AutoscalingV2beta1().HorizontalPodAutoscalers(ns).Watch(opts)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package collectors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
autoscaling "k8s.io/api/autoscaling/v2beta1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
hpa1MinReplicas int32 = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHPACollector(t *testing.T) {
|
||||||
|
// Fixed metadata on type and help text. We prepend this to every expected
|
||||||
|
// output so we only have to modify a single place when doing adjustments.
|
||||||
|
const metadata = `
|
||||||
|
# HELP kube_hpa_metadata_generation The generation observed by the HorizontalPodAutoscaler controller.
|
||||||
|
# TYPE kube_hpa_metadata_generation gauge
|
||||||
|
# HELP kube_hpa_spec_max_replicas Upper limit for the number of pods that can be set by the autoscaler; cannot be smaller than MinReplicas.
|
||||||
|
# TYPE kube_hpa_spec_max_replicas gauge
|
||||||
|
# HELP kube_hpa_spec_min_replicas Lower limit for the number of pods that can be set by the autoscaler, default 1.
|
||||||
|
# TYPE kube_hpa_spec_min_replicas gauge
|
||||||
|
# HELP kube_hpa_status_current_replicas Current number of replicas of pods managed by this autoscaler.
|
||||||
|
# TYPE kube_hpa_status_current_replicas gauge
|
||||||
|
# HELP kube_hpa_status_desired_replicas Desired number of replicas of pods managed by this autoscaler.
|
||||||
|
# TYPE kube_hpa_status_desired_replicas gauge
|
||||||
|
`
|
||||||
|
cases := []generateMetricsTestCase{
|
||||||
|
{
|
||||||
|
// Verify populating base metrics.
|
||||||
|
Obj: &autoscaling.HorizontalPodAutoscaler{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Generation: 2,
|
||||||
|
Name: "hpa1",
|
||||||
|
Namespace: "ns1",
|
||||||
|
},
|
||||||
|
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
||||||
|
MaxReplicas: 4,
|
||||||
|
MinReplicas: &hpa1MinReplicas,
|
||||||
|
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
|
||||||
|
APIVersion: "extensions/v1beta1",
|
||||||
|
Kind: "Deployment",
|
||||||
|
Name: "deployment1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Status: autoscaling.HorizontalPodAutoscalerStatus{
|
||||||
|
CurrentReplicas: 2,
|
||||||
|
DesiredReplicas: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Want: `
|
||||||
|
kube_hpa_metadata_generation{hpa="hpa1",namespace="ns1"} 2
|
||||||
|
kube_hpa_spec_max_replicas{hpa="hpa1",namespace="ns1"} 4
|
||||||
|
kube_hpa_spec_min_replicas{hpa="hpa1",namespace="ns1"} 2
|
||||||
|
kube_hpa_status_current_replicas{hpa="hpa1",namespace="ns1"} 2
|
||||||
|
kube_hpa_status_desired_replicas{hpa="hpa1",namespace="ns1"} 2
|
||||||
|
`,
|
||||||
|
MetricNames: []string{
|
||||||
|
"kube_hpa_metadata_generation",
|
||||||
|
"kube_hpa_spec_max_replicas",
|
||||||
|
"kube_hpa_spec_min_replicas",
|
||||||
|
"kube_hpa_status_current_replicas",
|
||||||
|
"kube_hpa_status_desired_replicas",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for i, c := range cases {
|
||||||
|
c.Func = composeMetricGenFuncs(hpaMetricFamilies)
|
||||||
|
if err := c.run(); err != nil {
|
||||||
|
t.Errorf("unexpected collecting result in %vth run:\n%s", i, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue