pkg/collectors: Refactor resource quota collector
This commit is contained in:
parent
56b4211eb1
commit
13c990201f
|
|
@ -263,6 +263,8 @@ func TestFullScrapeCycle(t *testing.T) {
|
|||
# HELP kube_replicationcontroller_status_observed_generation The generation observed by the ReplicationController controller.
|
||||
# HELP kube_replicationcontroller_spec_replicas Number of desired pods for a ReplicationController.
|
||||
# HELP kube_replicationcontroller_metadata_generation Sequence number representing a specific generation of the desired state.
|
||||
# HELP kube_resourcequota_created Unix creation timestamp
|
||||
# HELP kube_resourcequota Information about resource quota.
|
||||
# HELP kube_secret_info Information about secret.
|
||||
# HELP kube_secret_type Type about secret.
|
||||
# HELP kube_secret_labels Kubernetes labels converted to Prometheus labels.
|
||||
|
|
|
|||
|
|
@ -130,14 +130,12 @@ var availableCollectors = map[string]func(f *Builder) *Collector{
|
|||
"pods": func(b *Builder) *Collector { return b.buildPodCollector() },
|
||||
"replicasets": func(b *Builder) *Collector { return b.buildReplicaSetCollector() },
|
||||
"replicationcontrollers": func(b *Builder) *Collector { return b.buildReplicationControllerCollector() },
|
||||
"resourcequotas": func(b *Builder) *Collector { return b.buildResourceQuotaCollector() },
|
||||
"secrets": func(b *Builder) *Collector { return b.buildSecretCollector() },
|
||||
"services": func(b *Builder) *Collector { return b.buildServiceCollector() },
|
||||
"statefulsets": func(b *Builder) *Collector { return b.buildStatefulSetCollector() },
|
||||
// "configmaps": func(b *Builder) *Collector { return b.buildConfigMapCollector() },
|
||||
// "cronjobs": func(b *Builder) *Collector { return b.buildCronJobCollector() },
|
||||
// "endpoints": func(b *Builder) *Collector { return b.buildEndpointsCollector() },
|
||||
// "horizontalpodautoscalers": func(b *Builder) *Collector { return b.buildHPACollector() },
|
||||
// "resourcequotas": func(b *Builder) *Collector { return b.buildResourceQuotaCollector() },
|
||||
}
|
||||
|
||||
func (b *Builder) buildConfigMapCollector() *Collector {
|
||||
|
|
@ -335,6 +333,21 @@ func (b *Builder) buildReplicationControllerCollector() *Collector {
|
|||
return NewCollector(store)
|
||||
}
|
||||
|
||||
func (b *Builder) buildResourceQuotaCollector() *Collector {
|
||||
filteredMetricFamilies := filterMetricFamilies(b.whiteBlackList, resourceQuotaMetricFamilies)
|
||||
composedMetricGenFuncs := composeMetricGenFuncs(filteredMetricFamilies)
|
||||
|
||||
helpTexts := extractHelpText(filteredMetricFamilies)
|
||||
|
||||
store := metricsstore.NewMetricsStore(
|
||||
helpTexts,
|
||||
composedMetricGenFuncs,
|
||||
)
|
||||
reflectorPerNamespace(b.ctx, b.kubeClient, &v1.ResourceQuota{}, store, b.namespaces, createResourceQuotaListWatch)
|
||||
|
||||
return NewCollector(store)
|
||||
}
|
||||
|
||||
func (b *Builder) buildSecretCollector() *Collector {
|
||||
filteredMetricFamilies := filterMetricFamilies(b.whiteBlackList, secretMetricFamilies)
|
||||
composedMetricGenFuncs := composeMetricGenFuncs(filteredMetricFamilies)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
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 (
|
||||
descResourceQuotaLabelsDefaultLabels = []string{"namespace", "resourcequota"}
|
||||
|
||||
resourceQuotaMetricFamilies = []metrics.FamilyGenerator{
|
||||
metrics.FamilyGenerator{
|
||||
Name: "kube_resourcequota_created",
|
||||
Help: "Unix creation timestamp",
|
||||
GenerateFunc: wrapResourceQuotaFunc(func(r *v1.ResourceQuota) metrics.Family {
|
||||
f := metrics.Family{}
|
||||
|
||||
if !r.CreationTimestamp.IsZero() {
|
||||
f = append(f, &metrics.Metric{
|
||||
Name: "kube_resourcequota_created",
|
||||
Value: float64(r.CreationTimestamp.Unix()),
|
||||
})
|
||||
}
|
||||
|
||||
return f
|
||||
}),
|
||||
},
|
||||
metrics.FamilyGenerator{
|
||||
Name: "kube_resourcequota",
|
||||
Help: "Information about resource quota.",
|
||||
GenerateFunc: wrapResourceQuotaFunc(func(r *v1.ResourceQuota) metrics.Family {
|
||||
f := metrics.Family{}
|
||||
|
||||
for res, qty := range r.Status.Hard {
|
||||
f = append(f, &metrics.Metric{
|
||||
LabelValues: []string{string(res), "hard"},
|
||||
Value: float64(qty.MilliValue()) / 1000,
|
||||
})
|
||||
}
|
||||
for res, qty := range r.Status.Used {
|
||||
f = append(f, &metrics.Metric{
|
||||
LabelValues: []string{string(res), "used"},
|
||||
Value: float64(qty.MilliValue()) / 1000,
|
||||
})
|
||||
}
|
||||
|
||||
for _, m := range f {
|
||||
m.Name = "kube_resourcequota"
|
||||
m.LabelKeys = []string{"resource", "type"}
|
||||
}
|
||||
|
||||
return f
|
||||
}),
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func wrapResourceQuotaFunc(f func(*v1.ResourceQuota) metrics.Family) func(interface{}) metrics.Family {
|
||||
return func(obj interface{}) metrics.Family {
|
||||
resourceQuota := obj.(*v1.ResourceQuota)
|
||||
|
||||
metricFamily := f(resourceQuota)
|
||||
|
||||
for _, m := range metricFamily {
|
||||
m.LabelKeys = append(descResourceQuotaLabelsDefaultLabels, m.LabelKeys...)
|
||||
m.LabelValues = append([]string{resourceQuota.Namespace, resourceQuota.Name}, m.LabelValues...)
|
||||
}
|
||||
|
||||
return metricFamily
|
||||
}
|
||||
}
|
||||
|
||||
func createResourceQuotaListWatch(kubeClient clientset.Interface, ns string) cache.ListWatch {
|
||||
return cache.ListWatch{
|
||||
ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
|
||||
return kubeClient.CoreV1().ResourceQuotas(ns).List(opts)
|
||||
},
|
||||
WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
|
||||
return kubeClient.CoreV1().ResourceQuotas(ns).Watch(opts)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
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 TestResourceQuotaCollector(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_resourcequota Information about resource quota.
|
||||
# TYPE kube_resourcequota gauge
|
||||
# HELP kube_resourcequota_created Unix creation timestamp
|
||||
# TYPE kube_resourcequota_created gauge
|
||||
`
|
||||
cases := []generateMetricsTestCase{
|
||||
// Verify populating base metrics and that metrics for unset fields are skipped.
|
||||
{
|
||||
Obj: &v1.ResourceQuota{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "quotaTest",
|
||||
CreationTimestamp: metav1.Time{Time: time.Unix(1500000000, 0)},
|
||||
Namespace: "testNS",
|
||||
},
|
||||
Status: v1.ResourceQuotaStatus{},
|
||||
},
|
||||
Want: `
|
||||
kube_resourcequota_created{namespace="testNS",resourcequota="quotaTest"} 1.5e+09
|
||||
`,
|
||||
},
|
||||
// Verify resource metrics.
|
||||
{
|
||||
Obj: &v1.ResourceQuota{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "quotaTest",
|
||||
Namespace: "testNS",
|
||||
},
|
||||
Spec: v1.ResourceQuotaSpec{
|
||||
Hard: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("4.3"),
|
||||
v1.ResourceMemory: resource.MustParse("2.1G"),
|
||||
v1.ResourceStorage: resource.MustParse("10G"),
|
||||
v1.ResourcePods: resource.MustParse("9"),
|
||||
v1.ResourceServices: resource.MustParse("8"),
|
||||
v1.ResourceReplicationControllers: resource.MustParse("7"),
|
||||
v1.ResourceQuotas: resource.MustParse("6"),
|
||||
v1.ResourceSecrets: resource.MustParse("5"),
|
||||
v1.ResourceConfigMaps: resource.MustParse("4"),
|
||||
v1.ResourcePersistentVolumeClaims: resource.MustParse("3"),
|
||||
v1.ResourceServicesNodePorts: resource.MustParse("2"),
|
||||
v1.ResourceServicesLoadBalancers: resource.MustParse("1"),
|
||||
},
|
||||
},
|
||||
Status: v1.ResourceQuotaStatus{
|
||||
Hard: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("4.3"),
|
||||
v1.ResourceMemory: resource.MustParse("2.1G"),
|
||||
v1.ResourceStorage: resource.MustParse("10G"),
|
||||
v1.ResourcePods: resource.MustParse("9"),
|
||||
v1.ResourceServices: resource.MustParse("8"),
|
||||
v1.ResourceReplicationControllers: resource.MustParse("7"),
|
||||
v1.ResourceQuotas: resource.MustParse("6"),
|
||||
v1.ResourceSecrets: resource.MustParse("5"),
|
||||
v1.ResourceConfigMaps: resource.MustParse("4"),
|
||||
v1.ResourcePersistentVolumeClaims: resource.MustParse("3"),
|
||||
v1.ResourceServicesNodePorts: resource.MustParse("2"),
|
||||
v1.ResourceServicesLoadBalancers: resource.MustParse("1"),
|
||||
},
|
||||
Used: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("2.1"),
|
||||
v1.ResourceMemory: resource.MustParse("500M"),
|
||||
v1.ResourceStorage: resource.MustParse("9G"),
|
||||
v1.ResourcePods: resource.MustParse("8"),
|
||||
v1.ResourceServices: resource.MustParse("7"),
|
||||
v1.ResourceReplicationControllers: resource.MustParse("6"),
|
||||
v1.ResourceQuotas: resource.MustParse("5"),
|
||||
v1.ResourceSecrets: resource.MustParse("4"),
|
||||
v1.ResourceConfigMaps: resource.MustParse("3"),
|
||||
v1.ResourcePersistentVolumeClaims: resource.MustParse("2"),
|
||||
v1.ResourceServicesNodePorts: resource.MustParse("1"),
|
||||
v1.ResourceServicesLoadBalancers: resource.MustParse("0"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Want: `
|
||||
kube_resourcequota{namespace="testNS",resource="configmaps",resourcequota="quotaTest",type="hard"} 4
|
||||
kube_resourcequota{namespace="testNS",resource="configmaps",resourcequota="quotaTest",type="used"} 3
|
||||
kube_resourcequota{namespace="testNS",resource="cpu",resourcequota="quotaTest",type="hard"} 4.3
|
||||
kube_resourcequota{namespace="testNS",resource="cpu",resourcequota="quotaTest",type="used"} 2.1
|
||||
kube_resourcequota{namespace="testNS",resource="memory",resourcequota="quotaTest",type="hard"} 2.1e+09
|
||||
kube_resourcequota{namespace="testNS",resource="memory",resourcequota="quotaTest",type="used"} 5e+08
|
||||
kube_resourcequota{namespace="testNS",resource="persistentvolumeclaims",resourcequota="quotaTest",type="hard"} 3
|
||||
kube_resourcequota{namespace="testNS",resource="persistentvolumeclaims",resourcequota="quotaTest",type="used"} 2
|
||||
kube_resourcequota{namespace="testNS",resource="pods",resourcequota="quotaTest",type="hard"} 9
|
||||
kube_resourcequota{namespace="testNS",resource="pods",resourcequota="quotaTest",type="used"} 8
|
||||
kube_resourcequota{namespace="testNS",resource="replicationcontrollers",resourcequota="quotaTest",type="hard"} 7
|
||||
kube_resourcequota{namespace="testNS",resource="replicationcontrollers",resourcequota="quotaTest",type="used"} 6
|
||||
kube_resourcequota{namespace="testNS",resource="resourcequotas",resourcequota="quotaTest",type="hard"} 6
|
||||
kube_resourcequota{namespace="testNS",resource="resourcequotas",resourcequota="quotaTest",type="used"} 5
|
||||
kube_resourcequota{namespace="testNS",resource="secrets",resourcequota="quotaTest",type="hard"} 5
|
||||
kube_resourcequota{namespace="testNS",resource="secrets",resourcequota="quotaTest",type="used"} 4
|
||||
kube_resourcequota{namespace="testNS",resource="services",resourcequota="quotaTest",type="hard"} 8
|
||||
kube_resourcequota{namespace="testNS",resource="services",resourcequota="quotaTest",type="used"} 7
|
||||
kube_resourcequota{namespace="testNS",resource="services.loadbalancers",resourcequota="quotaTest",type="hard"} 1
|
||||
kube_resourcequota{namespace="testNS",resource="services.loadbalancers",resourcequota="quotaTest",type="used"} 0
|
||||
kube_resourcequota{namespace="testNS",resource="services.nodeports",resourcequota="quotaTest",type="hard"} 2
|
||||
kube_resourcequota{namespace="testNS",resource="services.nodeports",resourcequota="quotaTest",type="used"} 1
|
||||
kube_resourcequota{namespace="testNS",resource="storage",resourcequota="quotaTest",type="hard"} 1e+10
|
||||
kube_resourcequota{namespace="testNS",resource="storage",resourcequota="quotaTest",type="used"} 9e+09
|
||||
`,
|
||||
},
|
||||
}
|
||||
for i, c := range cases {
|
||||
c.Func = composeMetricGenFuncs(resourceQuotaMetricFamilies)
|
||||
if err := c.run(); err != nil {
|
||||
t.Errorf("unexpected collecting result in %vth run:\n%s", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue