pkg/collectors: Refactor limit range collector

This commit is contained in:
Max Leonard Inden 2018-11-23 11:34:35 +01:00
parent e44b956eeb
commit ddb54cacd7
No known key found for this signature in database
GPG Key ID: 5403C5464810BC26
4 changed files with 234 additions and 7 deletions

View File

@ -179,6 +179,8 @@ func TestFullScrapeCycle(t *testing.T) {
# HELP kube_job_failed The job has failed its execution.
# HELP kube_job_status_start_time StartTime represents time when the job was acknowledged by the Job Manager.
# HELP kube_job_status_completion_time CompletionTime represents time when the job was completed.
# HELP kube_limitrange Information about limit range.
# HELP kube_limitrange_created Unix creation timestamp
# HELP kube_pod_info Information about pod.
# HELP kube_pod_start_time Start time in unix timestamp for a pod.
# HELP kube_pod_completion_time Completion time in unix timestamp for a pod.

View File

@ -123,6 +123,7 @@ var availableCollectors = map[string]func(f *Builder) *Collector{
"daemonsets": func(b *Builder) *Collector { return b.buildDaemonSetCollector() },
"deployments": func(b *Builder) *Collector { return b.buildDeploymentCollector() },
"jobs": func(b *Builder) *Collector { return b.buildJobCollector() },
"limitranges": func(b *Builder) *Collector { return b.buildLimitRangeCollector() },
"pods": func(b *Builder) *Collector { return b.buildPodCollector() },
"services": func(b *Builder) *Collector { return b.buildServiceCollector() },
// "configmaps": func(b *Builder) *Collector { return b.buildConfigMapCollector() },
@ -143,13 +144,6 @@ var availableCollectors = map[string]func(f *Builder) *Collector{
// "statefulsets": func(b *Builder) *Collector { return b.buildStatefulSetCollector() },
}
// func (b *Builder) buildLimitRangeCollector() *Collector {
// store := metricsstore.NewMetricsStore(generateLimitRangeMetrics)
// reflectorPerNamespace(b.ctx, b.kubeClient, &v1.LimitRange{}, store, b.namespaces, createLimitRangeListWatch)
//
// return NewCollector(store)
// }
func (b *Builder) buildDaemonSetCollector() *Collector {
filteredMetricFamilies := filterMetricFamilies(b.whiteBlackList, daemonSetMetricFamilies)
composedMetricGenFuncs := composeMetricGenFuncs(filteredMetricFamilies)
@ -195,6 +189,21 @@ func (b *Builder) buildJobCollector() *Collector {
return NewCollector(store)
}
func (b *Builder) buildLimitRangeCollector() *Collector {
filteredMetricFamilies := filterMetricFamilies(b.whiteBlackList, limitRangeMetricFamilies)
composedMetricGenFuncs := composeMetricGenFuncs(filteredMetricFamilies)
helpTexts := extractHelpText(filteredMetricFamilies)
store := metricsstore.NewMetricsStore(
helpTexts,
composedMetricGenFuncs,
)
reflectorPerNamespace(b.ctx, b.kubeClient, &v1.LimitRange{}, store, b.namespaces, createLimitRangeListWatch)
return NewCollector(store)
}
func (b *Builder) buildServiceCollector() *Collector {
filteredMetricFamilies := filterMetricFamilies(b.whiteBlackList, serviceMetricFamilies)
composedMetricGenFuncs := composeMetricGenFuncs(filteredMetricFamilies)

View File

@ -0,0 +1,129 @@
/*
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"
"k8s.io/api/core/v1"
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 (
descLimitRangeLabelsDefaultLabels = []string{"namespace", "limitrange"}
limitRangeMetricFamilies = []metrics.FamilyGenerator{
metrics.FamilyGenerator{
Name: "kube_limitrange",
Help: "Information about limit range.",
GenerateFunc: wrapLimitRangeFunc(func(r *v1.LimitRange) metrics.Family {
f := metrics.Family{}
rawLimitRanges := r.Spec.Limits
for _, rawLimitRange := range rawLimitRanges {
for resource, min := range rawLimitRange.Min {
f = append(f, &metrics.Metric{
LabelValues: []string{string(resource), string(rawLimitRange.Type), "min"},
Value: float64(min.MilliValue()) / 1000,
})
}
for resource, max := range rawLimitRange.Max {
f = append(f, &metrics.Metric{
LabelValues: []string{string(resource), string(rawLimitRange.Type), "max"},
Value: float64(max.MilliValue()) / 1000,
})
}
for resource, df := range rawLimitRange.Default {
f = append(f, &metrics.Metric{
LabelValues: []string{string(resource), string(rawLimitRange.Type), "default"},
Value: float64(df.MilliValue()) / 1000,
})
}
for resource, dfR := range rawLimitRange.DefaultRequest {
f = append(f, &metrics.Metric{
LabelValues: []string{string(resource), string(rawLimitRange.Type), "defaultRequest"},
Value: float64(dfR.MilliValue()) / 1000,
})
}
for resource, mLR := range rawLimitRange.MaxLimitRequestRatio {
f = append(f, &metrics.Metric{
LabelValues: []string{string(resource), string(rawLimitRange.Type), "maxLimitRequestRatio"},
Value: float64(mLR.MilliValue()) / 1000,
})
}
}
for _, m := range f {
m.Name = "kube_limitrange"
m.LabelKeys = []string{"resource", "type", "constraint"}
}
return f
}),
},
metrics.FamilyGenerator{
Name: "kube_limitrange_created",
Help: "Unix creation timestamp",
GenerateFunc: wrapLimitRangeFunc(func(r *v1.LimitRange) metrics.Family {
f := metrics.Family{}
if !r.CreationTimestamp.IsZero() {
f = append(f, &metrics.Metric{
Name: "kube_limitrange_created",
Value: float64(r.CreationTimestamp.Unix()),
})
}
return f
}),
},
}
)
func wrapLimitRangeFunc(f func(*v1.LimitRange) metrics.Family) func(interface{}) metrics.Family {
return func(obj interface{}) metrics.Family {
limitRange := obj.(*v1.LimitRange)
metricFamily := f(limitRange)
for _, m := range metricFamily {
m.LabelKeys = append(descLimitRangeLabelsDefaultLabels, m.LabelKeys...)
m.LabelValues = append([]string{limitRange.Namespace, limitRange.Name}, m.LabelValues...)
}
return metricFamily
}
}
func createLimitRangeListWatch(kubeClient clientset.Interface, ns string) cache.ListWatch {
return cache.ListWatch{
ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
return kubeClient.CoreV1().LimitRanges(ns).List(opts)
},
WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
return kubeClient.CoreV1().LimitRanges(ns).Watch(opts)
},
}
}

View File

@ -0,0 +1,87 @@
/*
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/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func TestLimitRangeollector(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.
testMemory := "2.1G"
testMemoryQuantity := resource.MustParse(testMemory)
const metadata = `
# HELP kube_limitrange_created Unix creation timestamp
# TYPE kube_limitrange_created gauge
# HELP kube_limitrange Information about limit range.
# TYPE kube_limitrange gauge
`
cases := []generateMetricsTestCase{
{
Obj: &v1.LimitRange{
ObjectMeta: metav1.ObjectMeta{
Name: "quotaTest",
CreationTimestamp: metav1.Time{Time: time.Unix(1500000000, 0)},
Namespace: "testNS",
},
Spec: v1.LimitRangeSpec{
Limits: []v1.LimitRangeItem{
{
Type: v1.LimitTypePod,
Max: map[v1.ResourceName]resource.Quantity{
v1.ResourceMemory: testMemoryQuantity,
},
Min: map[v1.ResourceName]resource.Quantity{
v1.ResourceMemory: testMemoryQuantity,
},
Default: map[v1.ResourceName]resource.Quantity{
v1.ResourceMemory: testMemoryQuantity,
},
DefaultRequest: map[v1.ResourceName]resource.Quantity{
v1.ResourceMemory: testMemoryQuantity,
},
MaxLimitRequestRatio: map[v1.ResourceName]resource.Quantity{
v1.ResourceMemory: testMemoryQuantity,
},
},
},
},
},
Want: `
kube_limitrange_created{limitrange="quotaTest",namespace="testNS"} 1.5e+09
kube_limitrange{constraint="default",limitrange="quotaTest",namespace="testNS",resource="memory",type="Pod"} 2.1e+09
kube_limitrange{constraint="defaultRequest",limitrange="quotaTest",namespace="testNS",resource="memory",type="Pod"} 2.1e+09
kube_limitrange{constraint="max",limitrange="quotaTest",namespace="testNS",resource="memory",type="Pod"} 2.1e+09
kube_limitrange{constraint="maxLimitRequestRatio",limitrange="quotaTest",namespace="testNS",resource="memory",type="Pod"} 2.1e+09
kube_limitrange{constraint="min",limitrange="quotaTest",namespace="testNS",resource="memory",type="Pod"} 2.1e+09
`,
},
}
for i, c := range cases {
c.Func = composeMetricGenFuncs(limitRangeMetricFamilies)
if err := c.run(); err != nil {
t.Errorf("unexpected collecting result in %vth run:\n%s", i, err)
}
}
}