Add DaemonSet metrics (#54)
This commit is contained in:
parent
02d57f63b2
commit
6622d0a6e6
|
|
@ -40,6 +40,15 @@ additional metrics!
|
|||
| kube_node_status_allocatable_memory_bytes | Gauge | `node`=<node-address>|
|
||||
| kube_node_status_allocatable_pods | Gauge | `node`=<node-address>|
|
||||
|
||||
### DaemonSet Metrics
|
||||
|
||||
| Metric name| Metric type | Labels/tags |
|
||||
| ---------- | ----------- | ----------- |
|
||||
| kube_daemonset_status_current_number_scheduled | Gauge | `daemonset`=<daemonset-name> <br> `namespace`=<daemonset-namespace> |
|
||||
| kube_daemonset_status_number_misscheduled | Gauge | `daemonset`=<daemonset-name> <br> `namespace`=<daemonset-namespace> |
|
||||
| kube_daemonset_status_desired_number_scheduled | Gauge | `daemonset`=<daemonset-name> <br> `namespace`=<daemonset-namespace> |
|
||||
| kube_daemonset_metadata_generation | Gauge | `daemonset`=<daemonset-name> <br> `namespace`=<daemonset-namespace> |
|
||||
|
||||
### Deployment Metrics
|
||||
|
||||
| Metric name| Metric type | Labels/tags |
|
||||
|
|
|
|||
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
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 main
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"k8s.io/client-go/1.5/pkg/apis/extensions/v1beta1"
|
||||
)
|
||||
|
||||
var (
|
||||
descDaemonSetCurrentNumberScheduled = prometheus.NewDesc(
|
||||
"kube_daemonset_status_current_number_scheduled",
|
||||
"The number of nodes running at least one daemon pod and are supposed to.",
|
||||
[]string{"namespace", "daemonset"}, nil,
|
||||
)
|
||||
descDaemonSetNumberMisscheduled = prometheus.NewDesc(
|
||||
"kube_daemonset_status_number_misscheduled",
|
||||
"The number of nodes running a daemon pod but are not supposed to.",
|
||||
[]string{"namespace", "daemonset"}, nil,
|
||||
)
|
||||
descDaemonSetDesiredNumberScheduled = prometheus.NewDesc(
|
||||
"kube_daemonset_status_desired_number_scheduled",
|
||||
"The number of nodes that should be running the daemon pod.",
|
||||
[]string{"namespace", "daemonset"}, nil,
|
||||
)
|
||||
descDaemonSetMetadataGeneration = prometheus.NewDesc(
|
||||
"kube_daemonset_metadata_generation",
|
||||
"Sequence number representing a specific generation of the desired state.",
|
||||
[]string{"namespace", "daemonset"}, nil,
|
||||
)
|
||||
)
|
||||
|
||||
type daemonsetStore interface {
|
||||
List() (daemonsets []v1beta1.DaemonSet, err error)
|
||||
}
|
||||
|
||||
// daemonsetCollector collects metrics about all daemonsets in the cluster.
|
||||
type daemonsetCollector struct {
|
||||
store daemonsetStore
|
||||
}
|
||||
|
||||
// Describe implements the prometheus.Collector interface.
|
||||
func (dc *daemonsetCollector) Describe(ch chan<- *prometheus.Desc) {
|
||||
ch <- descDaemonSetCurrentNumberScheduled
|
||||
ch <- descDaemonSetNumberMisscheduled
|
||||
ch <- descDaemonSetDesiredNumberScheduled
|
||||
ch <- descDaemonSetMetadataGeneration
|
||||
}
|
||||
|
||||
// Collect implements the prometheus.Collector interface.
|
||||
func (dc *daemonsetCollector) Collect(ch chan<- prometheus.Metric) {
|
||||
dpls, err := dc.store.List()
|
||||
if err != nil {
|
||||
glog.Errorf("listing daemonsets failed: %s", err)
|
||||
return
|
||||
}
|
||||
for _, d := range dpls {
|
||||
dc.collectDaemonSet(ch, d)
|
||||
}
|
||||
}
|
||||
|
||||
func (dc *daemonsetCollector) collectDaemonSet(ch chan<- prometheus.Metric, d v1beta1.DaemonSet) {
|
||||
addGauge := func(desc *prometheus.Desc, v float64, lv ...string) {
|
||||
lv = append([]string{d.Namespace, d.Name}, lv...)
|
||||
ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, v, lv...)
|
||||
}
|
||||
addGauge(descDaemonSetCurrentNumberScheduled, float64(d.Status.CurrentNumberScheduled))
|
||||
addGauge(descDaemonSetNumberMisscheduled, float64(d.Status.NumberMisscheduled))
|
||||
addGauge(descDaemonSetDesiredNumberScheduled, float64(d.Status.DesiredNumberScheduled))
|
||||
addGauge(descDaemonSetMetadataGeneration, float64(d.ObjectMeta.Generation))
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
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 main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/client-go/1.5/pkg/api/v1"
|
||||
"k8s.io/client-go/1.5/pkg/apis/extensions/v1beta1"
|
||||
)
|
||||
|
||||
type mockDaemonSetStore struct {
|
||||
f func() ([]v1beta1.DaemonSet, error)
|
||||
}
|
||||
|
||||
func (ds mockDaemonSetStore) List() (daemonsets []v1beta1.DaemonSet, err error) {
|
||||
return ds.f()
|
||||
}
|
||||
|
||||
func TestDaemonSetCollector(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_daemonset_metadata_generation Sequence number representing a specific generation of the desired state.
|
||||
# TYPE kube_daemonset_metadata_generation gauge
|
||||
# HELP kube_daemonset_status_current_number_scheduled The number of nodes running at least one daemon pod and are supposed to.
|
||||
# TYPE kube_daemonset_status_current_number_scheduled gauge
|
||||
# HELP kube_daemonset_status_number_misscheduled The number of nodes running a daemon pod but are not supposed to.
|
||||
# TYPE kube_daemonset_status_number_misscheduled gauge
|
||||
# HELP kube_daemonset_status_desired_number_scheduled The number of nodes that should be running the daemon pod.
|
||||
# TYPE kube_daemonset_status_desired_number_scheduled gauge
|
||||
`
|
||||
cases := []struct {
|
||||
dss []v1beta1.DaemonSet
|
||||
want string
|
||||
}{
|
||||
{
|
||||
dss: []v1beta1.DaemonSet{
|
||||
{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "ds1",
|
||||
Namespace: "ns1",
|
||||
Generation: 21,
|
||||
},
|
||||
Status: v1beta1.DaemonSetStatus{
|
||||
CurrentNumberScheduled: 15,
|
||||
NumberMisscheduled: 10,
|
||||
DesiredNumberScheduled: 5,
|
||||
},
|
||||
}, {
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "ds2",
|
||||
Namespace: "ns2",
|
||||
Generation: 14,
|
||||
},
|
||||
Status: v1beta1.DaemonSetStatus{
|
||||
CurrentNumberScheduled: 10,
|
||||
NumberMisscheduled: 5,
|
||||
DesiredNumberScheduled: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
want: metadata + `
|
||||
kube_daemonset_metadata_generation{namespace="ns1",daemonset="ds1"} 21
|
||||
kube_daemonset_metadata_generation{namespace="ns2",daemonset="ds2"} 14
|
||||
kube_daemonset_status_current_number_scheduled{namespace="ns1",daemonset="ds1"} 15
|
||||
kube_daemonset_status_current_number_scheduled{namespace="ns2",daemonset="ds2"} 10
|
||||
kube_daemonset_status_number_misscheduled{namespace="ns1",daemonset="ds1"} 10
|
||||
kube_daemonset_status_number_misscheduled{namespace="ns2",daemonset="ds2"} 5
|
||||
kube_daemonset_status_desired_number_scheduled{namespace="ns1",daemonset="ds1"} 5
|
||||
kube_daemonset_status_desired_number_scheduled{namespace="ns2",daemonset="ds2"} 0
|
||||
`,
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
dc := &daemonsetCollector{
|
||||
store: mockDaemonSetStore{
|
||||
f: func() ([]v1beta1.DaemonSet, error) { return c.dss, nil },
|
||||
},
|
||||
}
|
||||
if err := gatherAndCompare(dc, c.want, nil); err != nil {
|
||||
t.Errorf("unexpected collecting result:\n%s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
17
main.go
17
main.go
|
|
@ -169,6 +169,12 @@ func metricsServer() {
|
|||
log.Fatal(http.ListenAndServe(listenAddress, nil))
|
||||
}
|
||||
|
||||
type DaemonSetLister func() ([]v1beta1.DaemonSet, error)
|
||||
|
||||
func (l DaemonSetLister) List() ([]v1beta1.DaemonSet, error) {
|
||||
return l()
|
||||
}
|
||||
|
||||
type DeploymentLister func() ([]v1beta1.Deployment, error)
|
||||
|
||||
func (l DeploymentLister) List() ([]v1beta1.Deployment, error) {
|
||||
|
|
@ -193,14 +199,23 @@ func initializeMetricCollection(kubeClient clientset.Interface) {
|
|||
cclient := kubeClient.Core().GetRESTClient()
|
||||
eclient := kubeClient.Extensions().GetRESTClient()
|
||||
|
||||
dslw := cache.NewListWatchFromClient(eclient, "daemonsets", api.NamespaceAll, nil)
|
||||
dlw := cache.NewListWatchFromClient(eclient, "deployments", api.NamespaceAll, nil)
|
||||
plw := cache.NewListWatchFromClient(cclient, "pods", api.NamespaceAll, nil)
|
||||
nlw := cache.NewListWatchFromClient(cclient, "nodes", api.NamespaceAll, nil)
|
||||
|
||||
dsinf := cache.NewSharedInformer(dslw, &v1beta1.DaemonSet{}, resyncPeriod)
|
||||
dinf := cache.NewSharedInformer(dlw, &v1beta1.Deployment{}, resyncPeriod)
|
||||
pinf := cache.NewSharedInformer(plw, &v1.Pod{}, resyncPeriod)
|
||||
ninf := cache.NewSharedInformer(nlw, &v1.Node{}, resyncPeriod)
|
||||
|
||||
dsLister := DaemonSetLister(func() (daemonsets []v1beta1.DaemonSet, err error) {
|
||||
for _, c := range dsinf.GetStore().List() {
|
||||
daemonsets = append(daemonsets, *(c.(*v1beta1.DaemonSet)))
|
||||
}
|
||||
return daemonsets, nil
|
||||
})
|
||||
|
||||
dplLister := DeploymentLister(func() (deployments []v1beta1.Deployment, err error) {
|
||||
for _, c := range dinf.GetStore().List() {
|
||||
deployments = append(deployments, *(c.(*v1beta1.Deployment)))
|
||||
|
|
@ -222,10 +237,12 @@ func initializeMetricCollection(kubeClient clientset.Interface) {
|
|||
return machines, nil
|
||||
})
|
||||
|
||||
prometheus.MustRegister(&daemonsetCollector{store: dsLister})
|
||||
prometheus.MustRegister(&deploymentCollector{store: dplLister})
|
||||
prometheus.MustRegister(&podCollector{store: podLister})
|
||||
prometheus.MustRegister(&nodeCollector{store: nodeLister})
|
||||
|
||||
go dsinf.Run(context.Background().Done())
|
||||
go dinf.Run(context.Background().Done())
|
||||
go pinf.Run(context.Background().Done())
|
||||
go ninf.Run(context.Background().Done())
|
||||
|
|
|
|||
Loading…
Reference in New Issue