Skip to content

Commit 3c9908d

Browse files
committed
add role and cluster role
Signed-off-by: Kaito Ii <[email protected]>
1 parent e4011f8 commit 3c9908d

File tree

13 files changed

+574
-1
lines changed

13 files changed

+574
-1
lines changed

docs/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ As of v2.3.0, kube-state-metrics supports additional opt-in metrics via the CLI
3030
Per group of metrics there is one file for each metrics. See each file for specific documentation about the exposed metrics:
3131

3232
- [CertificateSigningRequest Metrics](certificatesigningrequest-metrics.md)
33+
- [ClusterRole Metrics](clusterrole-metrics.md)
3334
- [ConfigMap Metrics](configmap-metrics.md)
3435
- [CronJob Metrics](cronjob-metrics.md)
3536
- [DaemonSet Metrics](daemonset-metrics.md)
@@ -51,6 +52,7 @@ Per group of metrics there is one file for each metrics. See each file for speci
5152
- [ReplicaSet Metrics](replicaset-metrics.md)
5253
- [ReplicationController Metrics](replicationcontroller-metrics.md)
5354
- [ResourceQuota Metrics](resourcequota-metrics.md)
55+
- [Role Metrics](role-metrics.md)
5456
- [Secret Metrics](secret-metrics.md)
5557
- [Service Metrics](service-metrics.md)
5658
- [ServiceAccount Metrics](serviceaccount-metrics.md)

docs/cli-arguments.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Usage of ./kube-state-metrics:
5050
--pod string Name of the pod that contains the kube-state-metrics container. When set, it is expected that --pod and --pod-namespace are both set. Most likely this should be passed via the downward API. This is used for auto-detecting sharding. If set, this has preference over statically configured sharding. This is experimental, it may be removed without notice.
5151
--pod-namespace string Name of the namespace of the pod specified by --pod. When set, it is expected that --pod and --pod-namespace are both set. Most likely this should be passed via the downward API. This is used for auto-detecting sharding. If set, this has preference over statically configured sharding. This is experimental, it may be removed without notice.
5252
--port int Port to expose metrics on. (default 8080)
53-
--resources string Comma-separated list of Resources to be enabled. Defaults to "certificatesigningrequests,configmaps,cronjobs,daemonsets,deployments,endpoints,horizontalpodautoscalers,ingresses,jobs,leases,limitranges,mutatingwebhookconfigurations,namespaces,networkpolicies,nodes,persistentvolumeclaims,persistentvolumes,poddisruptionbudgets,pods,replicasets,replicationcontrollers,resourcequotas,secrets,serviceaccounts,services,statefulsets,storageclasses,validatingwebhookconfigurations,volumeattachments"
53+
--resources string Comma-separated list of Resources to be enabled. Defaults to "certificatesigningrequests,clusterroles,configmaps,cronjobs,daemonsets,deployments,endpoints,horizontalpodautoscalers,ingresses,jobs,leases,limitranges,mutatingwebhookconfigurations,namespaces,networkpolicies,nodes,persistentvolumeclaims,persistentvolumes,poddisruptionbudgets,pods,replicasets,replicationcontrollers,resourcequotas,roles,secrets,serviceaccounts,services,statefulsets,storageclasses,validatingwebhookconfigurations,volumeattachments"
5454
--shard int32 The instances shard nominal (zero indexed) within the total number of shards. (default 0)
5555
--skip_headers If true, avoid header prefixes in the log messages
5656
--skip_log_headers If true, avoid headers when opening log files

docs/clusterrole-metrics.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# ClusterRole Metrics
2+
3+
| Metric name| Metric type | Labels/tags | Status |
4+
| ---------- | ----------- | ----------- | ----------- |
5+
| kube_clusterole_annotations | Gauge | `clusterole`=&lt;clusterole-name&gt; | EXPERIMENTAL
6+
| kube_clusterole_labels | Gauge | `clusterole`=&lt;clusterole-name&gt; | EXPERIMENTAL
7+
| kube_clusterole_info | Gauge | `clusterole`=&lt;clusterole-name&gt; | EXPERIMENTAL |
8+
| kube_clusterole_created | Gauge | `clusterole`=&lt;clusterole-name&gt; | EXPERIMENTAL |
9+
| kube_clusterole_metadata_resource_version | Gauge | `clusterole`=&lt;clusterole-name&gt; | EXPERIMENTAL |

docs/role-metrics.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Role Metrics
2+
3+
| Metric name| Metric type | Labels/tags | Status |
4+
| ---------- | ----------- | ----------- | ----------- |
5+
| kube_role_annotations | Gauge | `role`=&lt;role-name&gt; <br> `namespace`=&lt;role-namespace&gt; | EXPERIMENTAL
6+
| kube_role_labels | Gauge | `role`=&lt;role-name&gt; <br> `namespace`=&lt;role-namespace&gt; | EXPERIMENTAL
7+
| kube_role_info | Gauge | `role`=&lt;role-name&gt; <br> `namespace`=&lt;role-namespace&gt; | EXPERIMENTAL
8+
| kube_role_created | Gauge | `role`=&lt;role-name&gt; <br> `namespace`=&lt;role-namespace&gt; | EXPERIMENTAL |
9+
| kube_role_metadata_resource_version | Gauge | `role`=&lt;role-name&gt; <br> `namespace`=&lt;role-namespace&gt; | EXPERIMENTAL |

examples/standard/cluster-role.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,11 @@ rules:
108108
verbs:
109109
- list
110110
- watch
111+
- apiGroups:
112+
- rbac.authorization.k8s.io
113+
resources:
114+
- clusterroles
115+
- roles
116+
verbs:
117+
- list
118+
- watch

internal/store/builder.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
v1 "k8s.io/api/core/v1"
3535
networkingv1 "k8s.io/api/networking/v1"
3636
policyv1 "k8s.io/api/policy/v1"
37+
rbacv1 "k8s.io/api/rbac/v1"
3738
storagev1 "k8s.io/api/storage/v1"
3839
vpaautoscaling "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1beta2"
3940
vpaclientset "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/client/clientset/versioned"
@@ -261,6 +262,7 @@ func (b *Builder) BuildStores() [][]cache.Store {
261262

262263
var availableStores = map[string]func(f *Builder) []cache.Store{
263264
"certificatesigningrequests": func(b *Builder) []cache.Store { return b.buildCsrStores() },
265+
"clusterroles": func(b *Builder) []cache.Store { return b.buildClusterRoleStores() },
264266
"configmaps": func(b *Builder) []cache.Store { return b.buildConfigMapStores() },
265267
"cronjobs": func(b *Builder) []cache.Store { return b.buildCronJobStores() },
266268
"daemonsets": func(b *Builder) []cache.Store { return b.buildDaemonSetStores() },
@@ -282,6 +284,7 @@ var availableStores = map[string]func(f *Builder) []cache.Store{
282284
"replicasets": func(b *Builder) []cache.Store { return b.buildReplicaSetStores() },
283285
"replicationcontrollers": func(b *Builder) []cache.Store { return b.buildReplicationControllerStores() },
284286
"resourcequotas": func(b *Builder) []cache.Store { return b.buildResourceQuotaStores() },
287+
"roles": func(b *Builder) []cache.Store { return b.buildRoleStores() },
285288
"secrets": func(b *Builder) []cache.Store { return b.buildSecretStores() },
286289
"serviceaccounts": func(b *Builder) []cache.Store { return b.buildServiceAccountStores() },
287290
"services": func(b *Builder) []cache.Store { return b.buildServiceStores() },
@@ -425,6 +428,14 @@ func (b *Builder) buildLeasesStores() []cache.Store {
425428
return b.buildStoresFunc(leaseMetricFamilies, &coordinationv1.Lease{}, createLeaseListWatch, b.useAPIServerCache)
426429
}
427430

431+
func (b *Builder) buildClusterRoleStores() []cache.Store {
432+
return b.buildStoresFunc(clusterRoleMetricFamilies(b.allowAnnotationsList["clusterroles"], b.allowLabelsList["clusterroles"]), &rbacv1.ClusterRole{}, createClusterRoleListWatch, b.useAPIServerCache)
433+
}
434+
435+
func (b *Builder) buildRoleStores() []cache.Store {
436+
return b.buildStoresFunc(roleMetricFamilies(b.allowAnnotationsList["roles"], b.allowLabelsList["roles"]), &rbacv1.Role{}, createRoleListWatch, b.useAPIServerCache)
437+
}
438+
428439
func (b *Builder) buildStores(
429440
metricFamilies []generator.FamilyGenerator,
430441
expectedType interface{},

internal/store/clusterrole.go

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

internal/store/clusterrole_test.go

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

0 commit comments

Comments
 (0)