Skip to content

Commit 3cf1b16

Browse files
authored
Merge pull request #1905 from kaitoii11/ingressclass
Add ingress class metrics
2 parents 6e28b18 + df2d8f1 commit 3cf1b16

File tree

11 files changed

+272
-1
lines changed

11 files changed

+272
-1
lines changed

docs/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ See each file for specific documentation about the exposed metrics:
6565

6666
- [ClusterRole Metrics](clusterrole-metrics.md)
6767
- [ClusterRoleBinding Metrics](clusterrolebinding-metrics.md)
68+
- [IngressClass Metrics](ingressclass-metrics.md)
6869
- [Role Metrics](role-metrics.md)
6970
- [RoleBinding Metrics](rolebinding-metrics.md)
7071
- [ServiceAccount Metrics](serviceaccount-metrics.md)

docs/ingressclass-metrics.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# IngressClass Metrics
2+
3+
| Metric name| Metric type | Labels/tags | Status |
4+
| ---------- | ----------- | ----------- | ----------- |
5+
| kube_ingressclass_annotations | Gauge | `ingressclass`=&lt;ingressclass-name&gt; <br> `annotation_INGRESSCLASS_ANNOTATION`=&lt;INGRESSCLASS_ANNOTATION&gt; | EXPERIMENTAL |
6+
| kube_ingressclass_info | Gauge | `ingressclass`=&lt;ingressclass-name&gt; <br> `controller`=&lt;ingress-controller-name&gt; <br> | EXPERIMENTAL |
7+
| kube_ingressclass_labels | Gauge | `ingressclass`=&lt;ingressclass-name&gt; <br> `label_INGRESSCLASS_LABEL`=&lt;INGRESSCLASS_LABEL&gt; | EXPERIMENTAL|
8+
| kube_ingressclass_created | Gauge | `ingressclass`=&lt;ingressclass-name&gt; | EXPERIMENTAL|

examples/autosharding/cluster-role.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ rules:
9797
- networking.k8s.io
9898
resources:
9999
- networkpolicies
100+
- ingressclasses
100101
- ingresses
101102
verbs:
102103
- list

examples/standard/cluster-role.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ rules:
9797
- networking.k8s.io
9898
resources:
9999
- networkpolicies
100+
- ingressclasses
100101
- ingresses
101102
verbs:
102103
- list

internal/store/builder.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ var availableStores = map[string]func(f *Builder) []cache.Store{
295295
"endpoints": func(b *Builder) []cache.Store { return b.buildEndpointsStores() },
296296
"horizontalpodautoscalers": func(b *Builder) []cache.Store { return b.buildHPAStores() },
297297
"ingresses": func(b *Builder) []cache.Store { return b.buildIngressStores() },
298+
"ingressclasses": func(b *Builder) []cache.Store { return b.buildIngressClassStores() },
298299
"jobs": func(b *Builder) []cache.Store { return b.buildJobStores() },
299300
"leases": func(b *Builder) []cache.Store { return b.buildLeasesStores() },
300301
"limitranges": func(b *Builder) []cache.Store { return b.buildLimitRangeStores() },
@@ -470,6 +471,10 @@ func (b *Builder) buildRoleBindingStores() []cache.Store {
470471
return b.buildStoresFunc(roleBindingMetricFamilies(b.allowAnnotationsList["rolebindings"], b.allowLabelsList["rolebindings"]), &rbacv1.RoleBinding{}, createRoleBindingListWatch, b.useAPIServerCache)
471472
}
472473

474+
func (b *Builder) buildIngressClassStores() []cache.Store {
475+
return b.buildStoresFunc(ingressClassMetricFamilies(b.allowAnnotationsList["ingressclasses"], b.allowLabelsList["ingressclasses"]), &networkingv1.IngressClass{}, createIngressClassListWatch, b.useAPIServerCache)
476+
}
477+
473478
func (b *Builder) buildStores(
474479
metricFamilies []generator.FamilyGenerator,
475480
expectedType interface{},

internal/store/ingressclass.go

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/*
2+
Copyright 2022 The Kubernetes Authors All rights reserved.
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
package store
15+
16+
import (
17+
"context"
18+
19+
basemetrics "k8s.io/component-base/metrics"
20+
21+
"k8s.io/kube-state-metrics/v2/pkg/metric"
22+
generator "k8s.io/kube-state-metrics/v2/pkg/metric_generator"
23+
24+
networkingv1 "k8s.io/api/networking/v1"
25+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26+
"k8s.io/apimachinery/pkg/runtime"
27+
"k8s.io/apimachinery/pkg/watch"
28+
clientset "k8s.io/client-go/kubernetes"
29+
"k8s.io/client-go/tools/cache"
30+
)
31+
32+
var (
33+
descIngressClassAnnotationsName = "kube_ingressclass_annotations"
34+
descIngressClassAnnotationsHelp = "Kubernetes annotations converted to Prometheus labels."
35+
descIngressClassLabelsName = "kube_ingressclass_labels"
36+
descIngressClassLabelsHelp = "Kubernetes labels converted to Prometheus labels."
37+
descIngressClassLabelsDefaultLabels = []string{"ingressclass"}
38+
)
39+
40+
func ingressClassMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator {
41+
return []generator.FamilyGenerator{
42+
*generator.NewFamilyGeneratorWithStability(
43+
"kube_ingressclass_info",
44+
"Information about ingressclass.",
45+
metric.Gauge,
46+
basemetrics.ALPHA,
47+
"",
48+
wrapIngressClassFunc(func(s *networkingv1.IngressClass) *metric.Family {
49+
50+
m := metric.Metric{
51+
LabelKeys: []string{"controller"},
52+
LabelValues: []string{s.Spec.Controller},
53+
Value: 1,
54+
}
55+
return &metric.Family{Metrics: []*metric.Metric{&m}}
56+
}),
57+
),
58+
*generator.NewFamilyGeneratorWithStability(
59+
"kube_ingressclass_created",
60+
"Unix creation timestamp",
61+
metric.Gauge,
62+
basemetrics.ALPHA,
63+
"",
64+
wrapIngressClassFunc(func(s *networkingv1.IngressClass) *metric.Family {
65+
ms := []*metric.Metric{}
66+
if !s.CreationTimestamp.IsZero() {
67+
ms = append(ms, &metric.Metric{
68+
Value: float64(s.CreationTimestamp.Unix()),
69+
})
70+
}
71+
return &metric.Family{
72+
Metrics: ms,
73+
}
74+
}),
75+
),
76+
*generator.NewFamilyGeneratorWithStability(
77+
descIngressClassAnnotationsName,
78+
descIngressClassAnnotationsHelp,
79+
metric.Gauge,
80+
basemetrics.ALPHA,
81+
"",
82+
wrapIngressClassFunc(func(s *networkingv1.IngressClass) *metric.Family {
83+
annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", s.Annotations, allowAnnotationsList)
84+
return &metric.Family{
85+
Metrics: []*metric.Metric{
86+
{
87+
LabelKeys: annotationKeys,
88+
LabelValues: annotationValues,
89+
Value: 1,
90+
},
91+
},
92+
}
93+
}),
94+
),
95+
*generator.NewFamilyGeneratorWithStability(
96+
descIngressClassLabelsName,
97+
descIngressClassLabelsHelp,
98+
metric.Gauge,
99+
basemetrics.ALPHA,
100+
"",
101+
wrapIngressClassFunc(func(s *networkingv1.IngressClass) *metric.Family {
102+
labelKeys, labelValues := createPrometheusLabelKeysValues("label", s.Labels, allowLabelsList)
103+
return &metric.Family{
104+
Metrics: []*metric.Metric{
105+
{
106+
LabelKeys: labelKeys,
107+
LabelValues: labelValues,
108+
Value: 1,
109+
},
110+
},
111+
}
112+
}),
113+
),
114+
}
115+
}
116+
117+
func wrapIngressClassFunc(f func(*networkingv1.IngressClass) *metric.Family) func(interface{}) *metric.Family {
118+
return func(obj interface{}) *metric.Family {
119+
ingressClass := obj.(*networkingv1.IngressClass)
120+
121+
metricFamily := f(ingressClass)
122+
123+
for _, m := range metricFamily.Metrics {
124+
m.LabelKeys, m.LabelValues = mergeKeyValues(descIngressClassLabelsDefaultLabels, []string{ingressClass.Name}, m.LabelKeys, m.LabelValues)
125+
}
126+
127+
return metricFamily
128+
}
129+
}
130+
131+
func createIngressClassListWatch(kubeClient clientset.Interface, ns string, fieldSelector string) cache.ListerWatcher {
132+
return &cache.ListWatch{
133+
ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
134+
return kubeClient.NetworkingV1().IngressClasses().List(context.TODO(), opts)
135+
},
136+
WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
137+
return kubeClient.NetworkingV1().IngressClasses().Watch(context.TODO(), opts)
138+
},
139+
}
140+
}

internal/store/ingressclass_test.go

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
Copyright 2022 The Kubernetes Authors All rights reserved.
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
package store
15+
16+
import (
17+
"testing"
18+
19+
networkingv1 "k8s.io/api/networking/v1"
20+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
22+
generator "k8s.io/kube-state-metrics/v2/pkg/metric_generator"
23+
)
24+
25+
func TestIngressClassStore(t *testing.T) {
26+
startTime := 1501569018
27+
metav1StartTime := metav1.Unix(int64(startTime), 0)
28+
29+
cases := []generateMetricsTestCase{
30+
{
31+
Obj: &networkingv1.IngressClass{
32+
ObjectMeta: metav1.ObjectMeta{
33+
Name: "test_ingressclass-info",
34+
},
35+
Spec: networkingv1.IngressClassSpec{
36+
Controller: "controller",
37+
},
38+
},
39+
Want: `
40+
# HELP kube_ingressclass_info Information about ingressclass.
41+
# TYPE kube_ingressclass_info gauge
42+
kube_ingressclass_info{ingressclass="test_ingressclass-info",controller="controller"} 1
43+
`,
44+
MetricNames: []string{
45+
"kube_ingressclass_info",
46+
},
47+
},
48+
{
49+
Obj: &networkingv1.IngressClass{
50+
ObjectMeta: metav1.ObjectMeta{
51+
Name: "test_kube_ingressclass-created",
52+
CreationTimestamp: metav1StartTime,
53+
},
54+
Spec: networkingv1.IngressClassSpec{
55+
Controller: "controller",
56+
},
57+
},
58+
Want: `
59+
# HELP kube_ingressclass_created Unix creation timestamp
60+
# TYPE kube_ingressclass_created gauge
61+
kube_ingressclass_created{ingressclass="test_kube_ingressclass-created"} 1.501569018e+09
62+
`,
63+
MetricNames: []string{
64+
"kube_ingressclass_created",
65+
},
66+
},
67+
{
68+
AllowAnnotationsList: []string{
69+
"ingressclass.kubernetes.io/is-default-class",
70+
},
71+
Obj: &networkingv1.IngressClass{
72+
ObjectMeta: metav1.ObjectMeta{
73+
Name: "test_ingressclass-labels",
74+
Annotations: map[string]string{
75+
"ingressclass.kubernetes.io/is-default-class": "true",
76+
},
77+
Labels: map[string]string{
78+
"foo": "bar",
79+
},
80+
},
81+
Spec: networkingv1.IngressClassSpec{
82+
Controller: "controller",
83+
},
84+
},
85+
Want: `
86+
# HELP kube_ingressclass_annotations Kubernetes annotations converted to Prometheus labels.
87+
# HELP kube_ingressclass_labels Kubernetes labels converted to Prometheus labels.
88+
# TYPE kube_ingressclass_annotations gauge
89+
# TYPE kube_ingressclass_labels gauge
90+
kube_ingressclass_annotations{ingressclass="test_ingressclass-labels",annotation_ingressclass_kubernetes_io_is_default_class="true"} 1
91+
kube_ingressclass_labels{ingressclass="test_ingressclass-labels"} 1
92+
`,
93+
MetricNames: []string{
94+
"kube_ingressclass_annotations", "kube_ingressclass_labels",
95+
},
96+
},
97+
}
98+
for i, c := range cases {
99+
c.Func = generator.ComposeMetricGenFuncs(ingressClassMetricFamilies(c.AllowAnnotationsList, nil))
100+
c.Headers = generator.ExtractMetricFamilyHeaders(ingressClassMetricFamilies(c.AllowAnnotationsList, nil))
101+
if err := c.run(); err != nil {
102+
t.Errorf("unexpected collecting result in %vth run:\n%s", i, err)
103+
}
104+
}
105+
}

jsonnet/kube-state-metrics/kube-state-metrics.libsonnet

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@
134134
apiGroups: ['networking.k8s.io'],
135135
resources: [
136136
'networkpolicies',
137+
'ingressclasses',
137138
'ingresses',
138139
],
139140
verbs: ['list', 'watch'],

tests/e2e/main_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ func TestDefaultCollectorMetricsAvailable(t *testing.T) {
256256
nonDefaultResources := map[string]bool{
257257
"clusterrole": true,
258258
"clusterrolebinding": true,
259+
"ingressclass": true,
259260
"role": true,
260261
"rolebinding": true,
261262
"serviceaccount": true,

tests/manifests/ingress.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
apiVersion: networking.k8s.io/v1
1+
apiVersion: networking.k8s.io/v1
22
kind: Ingress
33
metadata:
44
name: example-ingress

0 commit comments

Comments
 (0)