Skip to content

Commit

Permalink
add ingress class metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
kaitoii11 committed Nov 23, 2022
1 parent 898345f commit 4abefe2
Show file tree
Hide file tree
Showing 10 changed files with 265 additions and 1 deletion.
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ See each file for specific documentation about the exposed metrics:

- [ClusterRole Metrics](clusterrole-metrics.md)
- [ClusterRoleBinding Metrics](clusterrolebinding-metrics.md)
- [IngressClass Metrics](ingressclass-metrics.md)
- [Role Metrics](role-metrics.md)
- [RoleBinding Metrics](rolebinding-metrics.md)
- [ServiceAccount Metrics](serviceaccount-metrics.md)
Expand Down
8 changes: 8 additions & 0 deletions docs/ingressclass-metrics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# IngressClass Metrics

| Metric name| Metric type | Labels/tags | Status |
| ---------- | ----------- | ----------- | ----------- |
| kube_ingressclass_annotations | Gauge | `ingressclass`=&lt;ingressclass-name&gt; <br> `annotation_INGRESSCLASS_ANNOTATION`=&lt;INGRESSCLASS_ANNOTATION&gt; | EXPERIMENTAL |
| kube_ingressclass_info | Gauge | `ingressclass`=&lt;ingressclass-name&gt; <br> `controller`=&lt;ingress-controller-name&gt; <br> | STABLE |
| kube_ingressclass_labels | Gauge | `ingressclass`=&lt;ingressclass-name&gt; <br> `label_INGRESSCLASS_LABEL`=&lt;INGRESSCLASS_LABEL&gt; | STABLE |
| kube_ingressclass_created | Gauge | `ingressclass`=&lt;ingressclass-name&gt; | STABLE |
1 change: 1 addition & 0 deletions examples/autosharding/cluster-role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ rules:
- networking.k8s.io
resources:
- networkpolicies
- ingressclasses
- ingresses
verbs:
- list
Expand Down
1 change: 1 addition & 0 deletions examples/standard/cluster-role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ rules:
- networking.k8s.io
resources:
- networkpolicies
- ingressclasses
- ingresses
verbs:
- list
Expand Down
5 changes: 5 additions & 0 deletions internal/store/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ var availableStores = map[string]func(f *Builder) []cache.Store{
"endpoints": func(b *Builder) []cache.Store { return b.buildEndpointsStores() },
"horizontalpodautoscalers": func(b *Builder) []cache.Store { return b.buildHPAStores() },
"ingresses": func(b *Builder) []cache.Store { return b.buildIngressStores() },
"ingressclasses": func(b *Builder) []cache.Store { return b.buildIngressClassStores() },
"jobs": func(b *Builder) []cache.Store { return b.buildJobStores() },
"leases": func(b *Builder) []cache.Store { return b.buildLeasesStores() },
"limitranges": func(b *Builder) []cache.Store { return b.buildLimitRangeStores() },
Expand Down Expand Up @@ -470,6 +471,10 @@ func (b *Builder) buildRoleBindingStores() []cache.Store {
return b.buildStoresFunc(roleBindingMetricFamilies(b.allowAnnotationsList["rolebindings"], b.allowLabelsList["rolebindings"]), &rbacv1.RoleBinding{}, createRoleBindingListWatch, b.useAPIServerCache)
}

func (b *Builder) buildIngressClassStores() []cache.Store {
return b.buildStoresFunc(ingressClassMetricFamilies(b.allowAnnotationsList["ingressclass"], b.allowLabelsList["ingressclass"]), &networkingv1.IngressClass{}, createIngressClassListWatch, b.useAPIServerCache)
}

func (b *Builder) buildStores(
metricFamilies []generator.FamilyGenerator,
expectedType interface{},
Expand Down
134 changes: 134 additions & 0 deletions internal/store/ingressclass.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
Copyright 2022 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 store

import (
"context"

"k8s.io/kube-state-metrics/v2/pkg/metric"
generator "k8s.io/kube-state-metrics/v2/pkg/metric_generator"

networkingv1 "k8s.io/api/networking/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 (
descIngressClassAnnotationsName = "kube_ingressclass_annotations"
descIngressClassAnnotationsHelp = "Kubernetes annotations converted to Prometheus labels."
descIngressClassLabelsName = "kube_ingressclass_labels"
descIngressClassLabelsHelp = "Kubernetes labels converted to Prometheus labels."
descIngressClassLabelsDefaultLabels = []string{"ingressclass"}
)

func ingressClassMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator {
return []generator.FamilyGenerator{
*generator.NewFamilyGenerator(
"kube_ingressclass_info",
"Information about ingressclass.",
metric.Gauge,
"",
wrapIngressClassFunc(func(s *networkingv1.IngressClass) *metric.Family {

m := metric.Metric{
LabelKeys: []string{"controller"},
LabelValues: []string{s.Spec.Controller},
Value: 1,
}
return &metric.Family{Metrics: []*metric.Metric{&m}}
}),
),
*generator.NewFamilyGenerator(
"kube_ingressclass_created",
"Unix creation timestamp",
metric.Gauge,
"",
wrapIngressClassFunc(func(s *networkingv1.IngressClass) *metric.Family {
ms := []*metric.Metric{}
if !s.CreationTimestamp.IsZero() {
ms = append(ms, &metric.Metric{
Value: float64(s.CreationTimestamp.Unix()),
})
}
return &metric.Family{
Metrics: ms,
}
}),
),
*generator.NewFamilyGenerator(
descIngressClassAnnotationsName,
descIngressClassAnnotationsHelp,
metric.Gauge,
"",
wrapIngressClassFunc(func(s *networkingv1.IngressClass) *metric.Family {
annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", s.Annotations, allowAnnotationsList)
return &metric.Family{
Metrics: []*metric.Metric{
{
LabelKeys: annotationKeys,
LabelValues: annotationValues,
Value: 1,
},
},
}
}),
),
*generator.NewFamilyGenerator(
descIngressClassLabelsName,
descIngressClassLabelsHelp,
metric.Gauge,
"",
wrapIngressClassFunc(func(s *networkingv1.IngressClass) *metric.Family {
labelKeys, labelValues := createPrometheusLabelKeysValues("label", s.Labels, allowLabelsList)
return &metric.Family{
Metrics: []*metric.Metric{
{
LabelKeys: labelKeys,
LabelValues: labelValues,
Value: 1,
},
},
}
}),
),
}
}

func wrapIngressClassFunc(f func(*networkingv1.IngressClass) *metric.Family) func(interface{}) *metric.Family {
return func(obj interface{}) *metric.Family {
ingressClass := obj.(*networkingv1.IngressClass)

metricFamily := f(ingressClass)

for _, m := range metricFamily.Metrics {
m.LabelKeys, m.LabelValues = mergeKeyValues(descIngressClassLabelsDefaultLabels, []string{ingressClass.Name}, m.LabelKeys, m.LabelValues)
}

return metricFamily
}
}

func createIngressClassListWatch(kubeClient clientset.Interface, ns string, fieldSelector string) cache.ListerWatcher {
return &cache.ListWatch{
ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
return kubeClient.NetworkingV1().IngressClasses().List(context.TODO(), opts)
},
WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
return kubeClient.NetworkingV1().IngressClasses().Watch(context.TODO(), opts)
},
}
}
105 changes: 105 additions & 0 deletions internal/store/ingressclass_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
Copyright 2022 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 store

import (
"testing"

networkingv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

generator "k8s.io/kube-state-metrics/v2/pkg/metric_generator"
)

func TestIngressClassStore(t *testing.T) {
startTime := 1501569018
metav1StartTime := metav1.Unix(int64(startTime), 0)

cases := []generateMetricsTestCase{
{
Obj: &networkingv1.IngressClass{
ObjectMeta: metav1.ObjectMeta{
Name: "test_ingressclass-info",
},
Spec: networkingv1.IngressClassSpec{
Controller: "controller",
},
},
Want: `
# HELP kube_ingressclass_info Information about ingressclass.
# TYPE kube_ingressclass_info gauge
kube_ingressclass_info{ingressclass="test_ingressclass-info",controller="controller"} 1
`,
MetricNames: []string{
"kube_ingressclass_info",
},
},
{
Obj: &networkingv1.IngressClass{
ObjectMeta: metav1.ObjectMeta{
Name: "test_kube_ingressclass-created",
CreationTimestamp: metav1StartTime,
},
Spec: networkingv1.IngressClassSpec{
Controller: "controller",
},
},
Want: `
# HELP kube_ingressclass_created Unix creation timestamp
# TYPE kube_ingressclass_created gauge
kube_ingressclass_created{ingressclass="test_kube_ingressclass-created"} 1.501569018e+09
`,
MetricNames: []string{
"kube_ingressclass_created",
},
},
{
AllowAnnotationsList: []string{
"ingressclass.kubernetes.io/is-default-class",
},
Obj: &networkingv1.IngressClass{
ObjectMeta: metav1.ObjectMeta{
Name: "test_ingressclass-labels",
Annotations: map[string]string{
"ingressclass.kubernetes.io/is-default-class": "true",
},
Labels: map[string]string{
"foo": "bar",
},
},
Spec: networkingv1.IngressClassSpec{
Controller: "controller",
},
},
Want: `
# HELP kube_ingressclass_annotations Kubernetes annotations converted to Prometheus labels.
# HELP kube_ingressclass_labels Kubernetes labels converted to Prometheus labels.
# TYPE kube_ingressclass_annotations gauge
# TYPE kube_ingressclass_labels gauge
kube_ingressclass_annotations{ingressclass="test_ingressclass-labels",annotation_ingressclass_kubernetes_io_is_default_class="true"} 1
kube_ingressclass_labels{ingressclass="test_ingressclass-labels"} 1
`,
MetricNames: []string{
"kube_ingressclass_annotations", "kube_ingressclass_labels",
},
},
}
for i, c := range cases {
c.Func = generator.ComposeMetricGenFuncs(ingressClassMetricFamilies(c.AllowAnnotationsList, nil))
c.Headers = generator.ExtractMetricFamilyHeaders(ingressClassMetricFamilies(c.AllowAnnotationsList, nil))
if err := c.run(); err != nil {
t.Errorf("unexpected collecting result in %vth run:\n%s", i, err)
}
}
}
1 change: 1 addition & 0 deletions jsonnet/kube-state-metrics/kube-state-metrics.libsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@
apiGroups: ['networking.k8s.io'],
resources: [
'networkpolicies',
'ingressclasses',
'ingresses',
],
verbs: ['list', 'watch'],
Expand Down
2 changes: 1 addition & 1 deletion tests/manifests/ingress.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
apiVersion: networking.k8s.io/v1
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
Expand Down
8 changes: 8 additions & 0 deletions tests/manifests/ingressclass.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: example-ingressclass
annotations:
ingressclass.kubernetes.io/is-default-class: "true"
spec:
controller: example-ingress/controller

0 comments on commit 4abefe2

Please sign in to comment.