Add PodDisruptionBudget metrics
This commit is contained in:
parent
f6ae40167e
commit
40f293dbde
|
|
@ -50,6 +50,7 @@ Per group of metrics there is one file for each metrics. See each file for speci
|
|||
* [PersistentVolume Metrics](persistentvolume-metrics.md)
|
||||
* [PersistentVolumeClaim Metrics](persistentvolumeclaim-metrics.md)
|
||||
* [Pod Metrics](pod-metrics.md)
|
||||
* [Pod Disruption Budget Metrics](poddisruptionbudget-metrics.md)
|
||||
* [ReplicaSet Metrics](replicaset-metrics.md)
|
||||
* [ReplicationController Metrics](replicationcontroller-metrics.md)
|
||||
* [ResourceQuota Metrics](resourcequota-metrics.md)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
# PodDisruptionBudget Metrics
|
||||
|
||||
| Metric name| Metric type | Labels/tags | Status |
|
||||
| ---------- | ----------- | ----------- | ----------- |
|
||||
| kube_poddisruptionbudget_created | Gauge | `poddisruptionbudget`=<pdb-name> <br> `namespace`=<pdb-namespace> | STABLE
|
||||
| kube_poddisruptionbudget_status_current_healthy | Gauge | `poddisruptionbudget`=<pdb-name> <br> `namespace`=<pdb-namespace> | STABLE
|
||||
| kube_poddisruptionbudget_status_desired_healthy | Gauge | `poddisruptionbudget`=<pdb-name> <br> `namespace`=<pdb-namespace> | STABLE
|
||||
| kube_poddisruptionbudget_status_pod_disruptions_allowed | Gauge | `poddisruptionbudget`=<pdb-name> <br> `namespace`=<pdb-namespace> | STABLE
|
||||
| kube_poddisruptionbudget_status_expected_pods | Gauge | `poddisruptionbudget`=<pdb-name> <br> `namespace`=<pdb-namespace> | STABLE
|
||||
| kube_poddisruptionbudget_status_observed_generation | Gauge | `poddisruptionbudget`=<pdb-name> <br> `namespace`=<pdb-namespace> | STABLE
|
||||
|
|
@ -38,3 +38,7 @@ rules:
|
|||
resources:
|
||||
- horizontalpodautoscalers
|
||||
verbs: ["list", "watch"]
|
||||
- apiGroups: ["policy"]
|
||||
resources:
|
||||
- poddisruptionbudgets
|
||||
verbs: ["list", "watch"]
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import (
|
|||
"github.com/golang/glog"
|
||||
"golang.org/x/net/context"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/api/policy/v1beta1"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/kube-state-metrics/pkg/metrics"
|
||||
|
|
@ -106,6 +107,7 @@ var availableCollectors = map[string]func(f *Builder) *Collector{
|
|||
"nodes": func(b *Builder) *Collector { return b.buildNodeCollector() },
|
||||
"persistentvolumeclaims": func(b *Builder) *Collector { return b.buildPersistentVolumeClaimCollector() },
|
||||
"persistentvolumes": func(b *Builder) *Collector { return b.buildPersistentVolumeCollector() },
|
||||
"poddisruptionbudgets": func(b *Builder) *Collector { return b.buildPodDisruptionBudgetCollector() },
|
||||
"pods": func(b *Builder) *Collector { return b.buildPodCollector() },
|
||||
"replicasets": func(b *Builder) *Collector { return b.buildReplicaSetCollector() },
|
||||
"replicationcontrollers": func(b *Builder) *Collector { return b.buildReplicationControllerCollector() },
|
||||
|
|
@ -212,6 +214,13 @@ func (b *Builder) buildPersistentVolumeClaimCollector() *Collector {
|
|||
return newCollector(store)
|
||||
}
|
||||
|
||||
func (b *Builder) buildPodDisruptionBudgetCollector() *Collector {
|
||||
store := metricsstore.NewMetricsStore(generatePodDisruptionBudgetMetrics)
|
||||
reflectorPerNamespace(b.ctx, b.kubeClient, &v1beta1.PodDisruptionBudget{}, store, b.namespaces, createPodDisruptionBudgetListWatch)
|
||||
|
||||
return newCollector(store)
|
||||
}
|
||||
|
||||
func (b *Builder) buildReplicaSetCollector() *Collector {
|
||||
store := metricsstore.NewMetricsStore(generateReplicaSetMetrics)
|
||||
reflectorPerNamespace(b.ctx, b.kubeClient, &extensions.ReplicaSet{}, store, b.namespaces, createReplicaSetListWatch)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
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/api/policy/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/kube-state-metrics/pkg/metrics"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
var (
|
||||
descPodDisruptionBudgetLabelsDefaultLabels = []string{"poddisruptionbudget", "namespace"}
|
||||
|
||||
descPodDisruptionBudgetCreated = newMetricFamilyDef(
|
||||
"kube_poddisruptionbudget_created",
|
||||
"Unix creation timestamp",
|
||||
descPodDisruptionBudgetLabelsDefaultLabels,
|
||||
nil,
|
||||
)
|
||||
|
||||
descPodDisruptionBudgetStatusCurrentHealthy = newMetricFamilyDef(
|
||||
"kube_poddisruptionbudget_status_current_healthy",
|
||||
"Current number of healthy pods",
|
||||
descPodDisruptionBudgetLabelsDefaultLabels,
|
||||
nil,
|
||||
)
|
||||
descPodDisruptionBudgetStatusDesiredHealthy = newMetricFamilyDef(
|
||||
"kube_poddisruptionbudget_status_desired_healthy",
|
||||
"Minimum desired number of healthy pods",
|
||||
descPodDisruptionBudgetLabelsDefaultLabels,
|
||||
nil,
|
||||
)
|
||||
descPodDisruptionBudgetStatusPodDisruptionsAllowed = newMetricFamilyDef(
|
||||
"kube_poddisruptionbudget_status_pod_disruptions_allowed",
|
||||
"Number of pod disruptions that are currently allowed",
|
||||
descPodDisruptionBudgetLabelsDefaultLabels,
|
||||
nil,
|
||||
)
|
||||
descPodDisruptionBudgetStatusExpectedPods = newMetricFamilyDef(
|
||||
"kube_poddisruptionbudget_status_expected_pods",
|
||||
"Total number of pods counted by this disruption budget",
|
||||
descPodDisruptionBudgetLabelsDefaultLabels,
|
||||
nil,
|
||||
)
|
||||
descPodDisruptionBudgetStatusObservedGeneration = newMetricFamilyDef(
|
||||
"kube_poddisruptionbudget_status_observed_generation",
|
||||
"Most recent generation observed when updating this PDB status",
|
||||
descPodDisruptionBudgetLabelsDefaultLabels,
|
||||
nil,
|
||||
)
|
||||
)
|
||||
|
||||
func createPodDisruptionBudgetListWatch(kubeClient clientset.Interface, ns string) cache.ListWatch {
|
||||
return cache.ListWatch{
|
||||
ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
|
||||
return kubeClient.PolicyV1beta1().PodDisruptionBudgets(ns).List(opts)
|
||||
},
|
||||
WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
|
||||
return kubeClient.PolicyV1beta1().PodDisruptionBudgets(ns).Watch(opts)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func generatePodDisruptionBudgetMetrics(obj interface{}) []*metrics.Metric {
|
||||
ms := []*metrics.Metric{}
|
||||
|
||||
// TODO: Refactor
|
||||
pPointer := obj.(*v1beta1.PodDisruptionBudget)
|
||||
p := *pPointer
|
||||
|
||||
addGauge := func(desc *metricFamilyDef, v float64, lv ...string) {
|
||||
lv = append([]string{p.Name, p.Namespace}, lv...)
|
||||
m, err := metrics.NewMetric(desc.Name, desc.LabelKeys, lv, v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ms = append(ms, m)
|
||||
}
|
||||
|
||||
if !p.CreationTimestamp.IsZero() {
|
||||
addGauge(descPodDisruptionBudgetCreated, float64(p.CreationTimestamp.Unix()))
|
||||
}
|
||||
addGauge(descPodDisruptionBudgetStatusCurrentHealthy, float64(p.Status.CurrentHealthy))
|
||||
addGauge(descPodDisruptionBudgetStatusDesiredHealthy, float64(p.Status.DesiredHealthy))
|
||||
addGauge(descPodDisruptionBudgetStatusPodDisruptionsAllowed, float64(p.Status.PodDisruptionsAllowed))
|
||||
addGauge(descPodDisruptionBudgetStatusExpectedPods, float64(p.Status.ExpectedPods))
|
||||
addGauge(descPodDisruptionBudgetStatusObservedGeneration, float64(p.Status.ObservedGeneration))
|
||||
|
||||
return ms
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
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"
|
||||
"time"
|
||||
|
||||
"k8s.io/api/policy/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestPodDisruptionBudgetCollector(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_poddisruptionbudget_created Unix creation timestamp
|
||||
# TYPE kube_poddisruptionbudget_created gauge
|
||||
# HELP kube_poddisruptionbudget_status_current_healthy Current number of healthy pods
|
||||
# TYPE kube_poddisruptionbudget_status_current_healthy gauge
|
||||
# HELP kube_poddisruptionbudget_status_desired_healthy Minimum desired number of healthy pods
|
||||
# TYPE kube_poddisruptionbudget_status_desired_healthy gauge
|
||||
# HELP kube_poddisruptionbudget_status_pod_disruptions_allowed Number of pod disruptions that are currently allowed
|
||||
# TYPE kube_poddisruptionbudget_status_pod_disruptions_allowed gauge
|
||||
# HELP kube_poddisruptionbudget_status_expected_pods Total number of pods counted by this disruption budget
|
||||
# TYPE kube_poddisruptionbudget_status_expected_pods gauge
|
||||
# HELP kube_poddisruptionbudget_status_observed_generation Most recent generation observed when updating this PDB status
|
||||
# TYPE kube_poddisruptionbudget_status_observed_generation gauge
|
||||
`
|
||||
cases := []generateMetricsTestCase{
|
||||
{
|
||||
Obj: &v1beta1.PodDisruptionBudget{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pdb1",
|
||||
CreationTimestamp: metav1.Time{Time: time.Unix(1500000000, 0)},
|
||||
Namespace: "ns1",
|
||||
Generation: 21,
|
||||
},
|
||||
Status: v1beta1.PodDisruptionBudgetStatus{
|
||||
CurrentHealthy: 12,
|
||||
DesiredHealthy: 10,
|
||||
PodDisruptionsAllowed: 2,
|
||||
ExpectedPods: 15,
|
||||
ObservedGeneration: 111,
|
||||
},
|
||||
},
|
||||
Want: `
|
||||
kube_poddisruptionbudget_created{namespace="ns1",poddisruptionbudget="pdb1"} 1.5e+09
|
||||
kube_poddisruptionbudget_status_current_healthy{namespace="ns1",poddisruptionbudget="pdb1"} 12
|
||||
kube_poddisruptionbudget_status_desired_healthy{namespace="ns1",poddisruptionbudget="pdb1"} 10
|
||||
kube_poddisruptionbudget_status_pod_disruptions_allowed{namespace="ns1",poddisruptionbudget="pdb1"} 2
|
||||
kube_poddisruptionbudget_status_expected_pods{namespace="ns1",poddisruptionbudget="pdb1"} 15
|
||||
kube_poddisruptionbudget_status_observed_generation{namespace="ns1",poddisruptionbudget="pdb1"} 111
|
||||
`,
|
||||
},
|
||||
{
|
||||
Obj: &v1beta1.PodDisruptionBudget{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pdb2",
|
||||
Namespace: "ns2",
|
||||
Generation: 14,
|
||||
},
|
||||
Status: v1beta1.PodDisruptionBudgetStatus{
|
||||
CurrentHealthy: 8,
|
||||
DesiredHealthy: 9,
|
||||
PodDisruptionsAllowed: 0,
|
||||
ExpectedPods: 10,
|
||||
ObservedGeneration: 1111,
|
||||
},
|
||||
},
|
||||
Want: `
|
||||
kube_poddisruptionbudget_status_current_healthy{namespace="ns2",poddisruptionbudget="pdb2"} 8
|
||||
kube_poddisruptionbudget_status_desired_healthy{namespace="ns2",poddisruptionbudget="pdb2"} 9
|
||||
kube_poddisruptionbudget_status_pod_disruptions_allowed{namespace="ns2",poddisruptionbudget="pdb2"} 0
|
||||
kube_poddisruptionbudget_status_expected_pods{namespace="ns2",poddisruptionbudget="pdb2"} 10
|
||||
kube_poddisruptionbudget_status_observed_generation{namespace="ns2",poddisruptionbudget="pdb2"} 1111
|
||||
`,
|
||||
},
|
||||
}
|
||||
for i, c := range cases {
|
||||
c.Func = generatePodDisruptionBudgetMetrics
|
||||
if err := c.run(); err != nil {
|
||||
t.Errorf("unexpected collecting result in %vth run:\n%s", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -28,6 +28,7 @@ var (
|
|||
"limitranges": struct{}{},
|
||||
"nodes": struct{}{},
|
||||
"pods": struct{}{},
|
||||
"poddisruptionbudgets": struct{}{},
|
||||
"replicasets": struct{}{},
|
||||
"replicationcontrollers": struct{}{},
|
||||
"resourcequotas": struct{}{},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
apiVersion: policy/v1beta1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: pdb
|
||||
spec:
|
||||
minAvailable: "50%"
|
||||
selector:
|
||||
matchLabels:
|
||||
name: pdb
|
||||
Loading…
Reference in New Issue