Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add hpa stats for current utilization and average value #961

Merged
merged 1 commit into from
Nov 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions docs/horizontalpodautoscaler-metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

| Metric name | Metric type | Labels/tags | Status |
| -------------------------------- | ----------- | ------------------------------------------------------------- | ------ |
| kube_hpa_labels | Gauge | `hpa`=&lt;hpa-name&gt; <br> `namespace`=&lt;hpa-namespace&gt; | STABLE |
| kube_hpa_metadata_generation | Gauge | `hpa`=&lt;hpa-name&gt; <br> `namespace`=&lt;hpa-namespace&gt; | STABLE |
| kube_hpa_spec_max_replicas | Gauge | `hpa`=&lt;hpa-name&gt; <br> `namespace`=&lt;hpa-namespace&gt; | STABLE |
| kube_hpa_spec_min_replicas | Gauge | `hpa`=&lt;hpa-name&gt; <br> `namespace`=&lt;hpa-namespace&gt; | STABLE |
| kube_hpa_status_condition | Gauge | `hpa`=&lt;hpa-name&gt; <br> `namespace`=&lt;hpa-namespace&gt; <br> `condition`=&lt;hpa-condition&gt; <br> `status`=&lt;true\|false\|unknown&gt; | STABLE |
| kube_hpa_status_current_replicas | Gauge | `hpa`=&lt;hpa-name&gt; <br> `namespace`=&lt;hpa-namespace&gt; | STABLE |
| kube_hpa_status_currentmetrics_average_utilization | Gauge | `hpa`=&lt;hpa-name&gt; <br> `namespace`=&lt;hpa-namespace&gt; | EXPERIMENTAL |
| kube_hpa_status_currentmetrics_average_value | Gauge | `hpa`=&lt;hpa-name&gt; <br> `namespace`=&lt;hpa-namespace&gt; | EXPERIMENTAL |
| kube_hpa_status_desired_replicas | Gauge | `hpa`=&lt;hpa-name&gt; <br> `namespace`=&lt;hpa-namespace&gt; | STABLE |
| kube_hpa_status_condition | Gauge | `hpa`=&lt;hpa-name&gt; <br> `namespace`=&lt;hpa-namespace&gt; <br> `condition`=&lt;hpa-condition&gt; <br> `status`=&lt;true\|false\|unknown&gt; | STABLE |
| kube_hpa_labels | Gauge | `hpa`=&lt;hpa-name&gt; <br> `namespace`=&lt;hpa-namespace&gt; | STABLE |
51 changes: 51 additions & 0 deletions internal/store/hpa.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"k8s.io/kube-state-metrics/pkg/metric"

autoscaling "k8s.io/api/autoscaling/v2beta1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/watch"
Expand Down Expand Up @@ -143,6 +144,56 @@ var (
}
}),
},
{
Name: "kube_hpa_status_currentmetrics_average_value",
Type: metric.Gauge,
Help: "Average metric value observed by the autoscaler.",
tariq1890 marked this conversation as resolved.
Show resolved Hide resolved
GenerateFunc: wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family {
ms := make([]*metric.Metric, len(a.Status.CurrentMetrics))
for i, c := range a.Status.CurrentMetrics {
var value *resource.Quantity
switch c.Type {
case autoscaling.ResourceMetricSourceType:
value = &c.Resource.CurrentAverageValue
case autoscaling.PodsMetricSourceType:
value = &c.Pods.CurrentAverageValue
case autoscaling.ObjectMetricSourceType:
value = c.Object.AverageValue
case autoscaling.ExternalMetricSourceType:
value = c.External.CurrentAverageValue
default:
// Skip unsupported metric type
continue
}
if intVal, canFastConvert := value.AsInt64(); canFastConvert {
ms[i] = &metric.Metric{
Value: float64(intVal),
}
}
}
return &metric.Family{
Metrics: ms,
}
}),
},
{
Name: "kube_hpa_status_currentmetrics_average_utilization",
Type: metric.Gauge,
Help: "Average metric utilization observed by the autoscaler.",
GenerateFunc: wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family {
ms := make([]*metric.Metric, len(a.Status.CurrentMetrics))
for i, c := range a.Status.CurrentMetrics {
if c.Type == autoscaling.ResourceMetricSourceType {
ms[i] = &metric.Metric{
Value: float64(*c.Resource.CurrentAverageUtilization),
}
}
}
return &metric.Family{
Metrics: ms,
}
}),
},
}
)

Expand Down
46 changes: 33 additions & 13 deletions internal/store/hpa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (

autoscaling "k8s.io/api/autoscaling/v2beta1"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"k8s.io/kube-state-metrics/pkg/metric"
Expand All @@ -44,10 +45,14 @@ func TestHPAStore(t *testing.T) {
# 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
# HELP kube_hpa_status_condition The condition of this autoscaler.
# TYPE kube_hpa_status_condition gauge
# HELP kube_hpa_labels Kubernetes labels converted to Prometheus labels.
# TYPE kube_hpa_labels gauge
# HELP kube_hpa_status_condition The condition of this autoscaler.
# TYPE kube_hpa_status_condition gauge
# HELP kube_hpa_labels Kubernetes labels converted to Prometheus labels.
# TYPE kube_hpa_labels gauge
# HELP kube_hpa_status_currentmetrics_average_value Average metric value observed by the autoscaler.
# TYPE kube_hpa_status_currentmetrics_average_value gauge
# HELP kube_hpa_status_currentmetrics_average_utilization Average metric utilization observed by the autoscaler.
# TYPE kube_hpa_status_currentmetrics_average_utilization gauge
`
cases := []generateMetricsTestCase{
{
Expand Down Expand Up @@ -77,20 +82,33 @@ func TestHPAStore(t *testing.T) {
{
Type: autoscaling.AbleToScale,
Status: v1.ConditionTrue,
Reason: "reason",
},
},
CurrentMetrics: []autoscaling.MetricStatus{
{
Type: "Resource",
Resource: &autoscaling.ResourceMetricStatus{
Name: "cpu",
CurrentAverageUtilization: new(int32),
CurrentAverageValue: resource.MustParse("10"),
},
},
},
},
},
Want: metadata + `
kube_hpa_labels{hpa="hpa1",label_app="foobar",namespace="ns1"} 1
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_condition{condition="AbleToScale",hpa="hpa1",namespace="ns1",status="false"} 0
kube_hpa_status_condition{condition="AbleToScale",hpa="hpa1",namespace="ns1",status="true"} 1
kube_hpa_status_condition{condition="AbleToScale",hpa="hpa1",namespace="ns1",status="unknown"} 0
kube_hpa_status_current_replicas{hpa="hpa1",namespace="ns1"} 2
kube_hpa_status_desired_replicas{hpa="hpa1",namespace="ns1"} 2
kube_hpa_labels{hpa="hpa1",label_app="foobar",namespace="ns1"} 1
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_condition{condition="AbleToScale",hpa="hpa1",namespace="ns1",status="false"} 0
kube_hpa_status_condition{condition="AbleToScale",hpa="hpa1",namespace="ns1",status="true"} 1
kube_hpa_status_condition{condition="AbleToScale",hpa="hpa1",namespace="ns1",status="unknown"} 0
kube_hpa_status_current_replicas{hpa="hpa1",namespace="ns1"} 2
kube_hpa_status_desired_replicas{hpa="hpa1",namespace="ns1"} 2
kube_hpa_status_currentmetrics_average_value{hpa="hpa1",namespace="ns1"} 10
kube_hpa_status_currentmetrics_average_utilization{hpa="hpa1",namespace="ns1"} 0
`,
MetricNames: []string{
"kube_hpa_metadata_generation",
Expand All @@ -100,6 +118,8 @@ func TestHPAStore(t *testing.T) {
"kube_hpa_status_desired_replicas",
"kube_hpa_status_condition",
"kube_hpa_labels",
"kube_hpa_status_currentmetrics_average_value",
"kube_hpa_status_currentmetrics_average_utilization",
},
},
}
Expand Down