diff --git a/docs/README.md b/docs/README.md
index ddf69681bf..9ae52d803e 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -31,6 +31,7 @@ Per group of metrics there is one file for each metrics. See each file for speci
- [CertificateSigningRequest Metrics](certificatesigningrequest-metrics.md)
- [ClusterRole Metrics](clusterrole-metrics.md)
+- [ClusterRoleBinding Metrics](clusterrolebinding-metrics.md)
- [ConfigMap Metrics](configmap-metrics.md)
- [CronJob Metrics](cronjob-metrics.md)
- [DaemonSet Metrics](daemonset-metrics.md)
@@ -53,6 +54,7 @@ Per group of metrics there is one file for each metrics. See each file for speci
- [ReplicationController Metrics](replicationcontroller-metrics.md)
- [ResourceQuota Metrics](resourcequota-metrics.md)
- [Role Metrics](role-metrics.md)
+- [RoleBinding Metrics](rolebinding-metrics.md)
- [Secret Metrics](secret-metrics.md)
- [Service Metrics](service-metrics.md)
- [ServiceAccount Metrics](serviceaccount-metrics.md)
diff --git a/docs/cli-arguments.md b/docs/cli-arguments.md
index f5cf56ded7..299f17e796 100644
--- a/docs/cli-arguments.md
+++ b/docs/cli-arguments.md
@@ -50,7 +50,7 @@ Usage of ./kube-state-metrics:
--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.
--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.
--port int Port to expose metrics on. (default 8080)
- --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"
+ --resources string Comma-separated list of Resources to be enabled. Defaults to "certificatesigningrequests,clusterrolebindings,clusterroles,configmaps,cronjobs,daemonsets,deployments,endpoints,horizontalpodautoscalers,ingresses,jobs,leases,limitranges,mutatingwebhookconfigurations,namespaces,networkpolicies,nodes,persistentvolumeclaims,persistentvolumes,poddisruptionbudgets,pods,replicasets,replicationcontrollers,resourcequotas,rolebindings,roles,secrets,serviceaccounts,services,statefulsets,storageclasses,validatingwebhookconfigurations,volumeattachments"
--shard int32 The instances shard nominal (zero indexed) within the total number of shards. (default 0)
--skip_headers If true, avoid header prefixes in the log messages
--skip_log_headers If true, avoid headers when opening log files
diff --git a/docs/clusterrolebinding-metrics.md b/docs/clusterrolebinding-metrics.md
new file mode 100644
index 0000000000..936ae63726
--- /dev/null
+++ b/docs/clusterrolebinding-metrics.md
@@ -0,0 +1,9 @@
+# ClusterRoleBinding Metrics
+
+| Metric name| Metric type | Labels/tags | Status |
+| ---------- | ----------- | ----------- | ----------- |
+| kube_clusterrolebinding_annotations | Gauge | `clusterrolebinding`=<clusterrolebinding-name> | EXPERIMENTAL
+| kube_clusterrolebinding_labels | Gauge | `clusterrolebinding`=<clusterrolebinding-name> | EXPERIMENTAL
+| kube_clusterrolebinding_info | Gauge | `clusterrolebinding`=<clusterrolebinding-name>
`roleref_kind`=<role-kind>
`roleref_name`=<role-name> | EXPERIMENTAL |
+| kube_clusterrolebinding_created | Gauge | `clusterrolebinding`=<clusterrolebinding-name> | EXPERIMENTAL |
+| kube_clusterrolebinding_metadata_resource_version | Gauge | `clusterrolebinding`=<clusterrolebinding-name> | EXPERIMENTAL |
diff --git a/docs/rolebinding-metrics.md b/docs/rolebinding-metrics.md
new file mode 100644
index 0000000000..2a0b6986d0
--- /dev/null
+++ b/docs/rolebinding-metrics.md
@@ -0,0 +1,9 @@
+# RoleBinding Metrics
+
+| Metric name| Metric type | Labels/tags | Status |
+| ---------- | ----------- | ----------- | ----------- |
+| kube_rolebinding_annotations | Gauge | `rolebinding`=<rolebinding-name>
`namespace`=<rolebinding-namespace> | EXPERIMENTAL
+| kube_rolebinding_labels | Gauge | `rolebinding`=<rolebinding-name>
`namespace`=<rolebinding-namespace> | EXPERIMENTAL
+| kube_rolebinding_info | Gauge | `rolebinding`=<rolebinding-name>
`namespace`=<rolebinding-namespace>
`roleref_kind`=<role-kind>
`roleref_name`=<role-name>| EXPERIMENTAL
+| kube_rolebinding_created | Gauge | `rolebinding`=<rolebinding-name>
`namespace`=<rolebinding-namespace> | EXPERIMENTAL |
+| kube_rolebinding_metadata_resource_version | Gauge | `rolebinding`=<rolebinding-name>
`namespace`=<rolebinding-namespace> | EXPERIMENTAL |
diff --git a/examples/autosharding/cluster-role.yaml b/examples/autosharding/cluster-role.yaml
index 574452e9e1..0b30e46a5d 100644
--- a/examples/autosharding/cluster-role.yaml
+++ b/examples/autosharding/cluster-role.yaml
@@ -111,7 +111,9 @@ rules:
- apiGroups:
- rbac.authorization.k8s.io
resources:
+ - clusterrolebindings
- clusterroles
+ - rolebindings
- roles
verbs:
- list
diff --git a/examples/standard/cluster-role.yaml b/examples/standard/cluster-role.yaml
index 574452e9e1..0b30e46a5d 100644
--- a/examples/standard/cluster-role.yaml
+++ b/examples/standard/cluster-role.yaml
@@ -111,7 +111,9 @@ rules:
- apiGroups:
- rbac.authorization.k8s.io
resources:
+ - clusterrolebindings
- clusterroles
+ - rolebindings
- roles
verbs:
- list
diff --git a/internal/store/builder.go b/internal/store/builder.go
index 783cfeea87..111a73247d 100644
--- a/internal/store/builder.go
+++ b/internal/store/builder.go
@@ -264,6 +264,7 @@ var availableStores = map[string]func(f *Builder) []cache.Store{
"certificatesigningrequests": func(b *Builder) []cache.Store { return b.buildCsrStores() },
"clusterroles": func(b *Builder) []cache.Store { return b.buildClusterRoleStores() },
"configmaps": func(b *Builder) []cache.Store { return b.buildConfigMapStores() },
+ "clusterrolebindings": func(b *Builder) []cache.Store { return b.buildClusterRoleBindingStores() },
"cronjobs": func(b *Builder) []cache.Store { return b.buildCronJobStores() },
"daemonsets": func(b *Builder) []cache.Store { return b.buildDaemonSetStores() },
"deployments": func(b *Builder) []cache.Store { return b.buildDeploymentStores() },
@@ -285,6 +286,7 @@ var availableStores = map[string]func(f *Builder) []cache.Store{
"replicationcontrollers": func(b *Builder) []cache.Store { return b.buildReplicationControllerStores() },
"resourcequotas": func(b *Builder) []cache.Store { return b.buildResourceQuotaStores() },
"roles": func(b *Builder) []cache.Store { return b.buildRoleStores() },
+ "rolebindings": func(b *Builder) []cache.Store { return b.buildRoleBindingStores() },
"secrets": func(b *Builder) []cache.Store { return b.buildSecretStores() },
"serviceaccounts": func(b *Builder) []cache.Store { return b.buildServiceAccountStores() },
"services": func(b *Builder) []cache.Store { return b.buildServiceStores() },
@@ -436,6 +438,14 @@ func (b *Builder) buildRoleStores() []cache.Store {
return b.buildStoresFunc(roleMetricFamilies(b.allowAnnotationsList["roles"], b.allowLabelsList["roles"]), &rbacv1.Role{}, createRoleListWatch, b.useAPIServerCache)
}
+func (b *Builder) buildClusterRoleBindingStores() []cache.Store {
+ return b.buildStoresFunc(clusterRoleBindingMetricFamilies(b.allowAnnotationsList["clusterrolebindings"], b.allowLabelsList["clusterrolebindings"]), &rbacv1.ClusterRoleBinding{}, createClusterRoleBindingListWatch, b.useAPIServerCache)
+}
+
+func (b *Builder) buildRoleBindingStores() []cache.Store {
+ return b.buildStoresFunc(roleBindingMetricFamilies(b.allowAnnotationsList["rolebindings"], b.allowLabelsList["rolebindings"]), &rbacv1.RoleBinding{}, createRoleBindingListWatch, b.useAPIServerCache)
+}
+
func (b *Builder) buildStores(
metricFamilies []generator.FamilyGenerator,
expectedType interface{},
diff --git a/internal/store/clusterrolebinding.go b/internal/store/clusterrolebinding.go
new file mode 100644
index 0000000000..fb90a83396
--- /dev/null
+++ b/internal/store/clusterrolebinding.go
@@ -0,0 +1,156 @@
+/*
+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"
+
+ rbacv1 "k8s.io/api/rbac/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"
+
+ "k8s.io/kube-state-metrics/v2/pkg/metric"
+ generator "k8s.io/kube-state-metrics/v2/pkg/metric_generator"
+)
+
+var (
+ descClusterRoleBindingAnnotationsName = "kube_clusterrolebinding_annotations"
+ descClusterRoleBindingAnnotationsHelp = "Kubernetes annotations converted to Prometheus labels."
+ descClusterRoleBindingLabelsName = "kube_clusterrolebinding_labels"
+ descClusterRoleBindingLabelsHelp = "Kubernetes labels converted to Prometheus labels."
+ descClusterRoleBindingLabelsDefaultLabels = []string{"clusterrolebinding"}
+)
+
+func clusterRoleBindingMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator {
+ return []generator.FamilyGenerator{
+ *generator.NewFamilyGenerator(
+ descClusterRoleBindingAnnotationsName,
+ descClusterRoleBindingAnnotationsHelp,
+ metric.Gauge,
+ "",
+ wrapClusterRoleBindingFunc(func(r *rbacv1.ClusterRoleBinding) *metric.Family {
+ annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", r.Annotations, allowAnnotationsList)
+ return &metric.Family{
+ Metrics: []*metric.Metric{
+ {
+ LabelKeys: annotationKeys,
+ LabelValues: annotationValues,
+ Value: 1,
+ },
+ },
+ }
+ }),
+ ),
+ *generator.NewFamilyGenerator(
+ descClusterRoleBindingLabelsName,
+ descClusterRoleBindingLabelsHelp,
+ metric.Gauge,
+ "",
+ wrapClusterRoleBindingFunc(func(r *rbacv1.ClusterRoleBinding) *metric.Family {
+ labelKeys, labelValues := createPrometheusLabelKeysValues("label", r.Labels, allowLabelsList)
+ return &metric.Family{
+ Metrics: []*metric.Metric{
+ {
+ LabelKeys: labelKeys,
+ LabelValues: labelValues,
+ Value: 1,
+ },
+ },
+ }
+ }),
+ ),
+ *generator.NewFamilyGenerator(
+ "kube_clusterrolebinding_info",
+ "Information about clusterrolebinding.",
+ metric.Gauge,
+ "",
+ wrapClusterRoleBindingFunc(func(r *rbacv1.ClusterRoleBinding) *metric.Family {
+ labelKeys := []string{"roleref_kind", "roleref_name"}
+ labelValues := []string{r.RoleRef.Kind, r.RoleRef.Name}
+ return &metric.Family{
+ Metrics: []*metric.Metric{{
+ LabelKeys: labelKeys,
+ LabelValues: labelValues,
+ Value: 1,
+ }},
+ }
+ }),
+ ),
+ *generator.NewFamilyGenerator(
+ "kube_clusterrolebinding_created",
+ "Unix creation timestamp",
+ metric.Gauge,
+ "",
+ wrapClusterRoleBindingFunc(func(r *rbacv1.ClusterRoleBinding) *metric.Family {
+ ms := []*metric.Metric{}
+
+ if !r.CreationTimestamp.IsZero() {
+ ms = append(ms, &metric.Metric{
+ LabelKeys: []string{},
+ LabelValues: []string{},
+ Value: float64(r.CreationTimestamp.Unix()),
+ })
+ }
+
+ return &metric.Family{
+ Metrics: ms,
+ }
+ }),
+ ),
+ *generator.NewFamilyGenerator(
+ "kube_clusterrolebinding_metadata_resource_version",
+ "Resource version representing a specific version of the clusterrolebinding.",
+ metric.Gauge,
+ "",
+ wrapClusterRoleBindingFunc(func(r *rbacv1.ClusterRoleBinding) *metric.Family {
+ return &metric.Family{
+ Metrics: resourceVersionMetric(r.ObjectMeta.ResourceVersion),
+ }
+ }),
+ ),
+ }
+}
+
+func createClusterRoleBindingListWatch(kubeClient clientset.Interface, ns string, fieldSelector string) cache.ListerWatcher {
+ return &cache.ListWatch{
+ ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
+ opts.FieldSelector = fieldSelector
+ return kubeClient.RbacV1().ClusterRoleBindings().List(context.TODO(), opts)
+ },
+ WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
+ opts.FieldSelector = fieldSelector
+ return kubeClient.RbacV1().ClusterRoleBindings().Watch(context.TODO(), opts)
+ },
+ }
+}
+
+func wrapClusterRoleBindingFunc(f func(*rbacv1.ClusterRoleBinding) *metric.Family) func(interface{}) *metric.Family {
+ return func(obj interface{}) *metric.Family {
+ clusterrolebinding := obj.(*rbacv1.ClusterRoleBinding)
+
+ metricFamily := f(clusterrolebinding)
+
+ for _, m := range metricFamily.Metrics {
+ m.LabelKeys, m.LabelValues = mergeKeyValues(descClusterRoleBindingLabelsDefaultLabels, []string{clusterrolebinding.Name}, m.LabelKeys, m.LabelValues)
+ }
+
+ return metricFamily
+ }
+}
diff --git a/internal/store/clusterrolebinding_test.go b/internal/store/clusterrolebinding_test.go
new file mode 100644
index 0000000000..e367425853
--- /dev/null
+++ b/internal/store/clusterrolebinding_test.go
@@ -0,0 +1,113 @@
+/*
+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"
+
+ rbacv1 "k8s.io/api/rbac/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+ generator "k8s.io/kube-state-metrics/v2/pkg/metric_generator"
+)
+
+func TestClusterRoleBindingStore(t *testing.T) {
+ startTime := 1501569018
+ metav1StartTime := metav1.Unix(int64(startTime), 0)
+
+ cases := []generateMetricsTestCase{
+ {
+ AllowAnnotationsList: []string{
+ "app.k8s.io/owner",
+ },
+ AllowLabelsList: []string{
+ "app",
+ },
+ Obj: &rbacv1.ClusterRoleBinding{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "clusterrolebinding1",
+ ResourceVersion: "BBBBB",
+ Annotations: map[string]string{
+ "app": "mysql-server",
+ "app.k8s.io/owner": "@foo",
+ },
+ Labels: map[string]string{
+ "excluded": "me",
+ "app": "mysql-server",
+ },
+ },
+ RoleRef: rbacv1.RoleRef{
+ APIGroup: "rbac.authorization.k8s.io",
+ Kind: "Role",
+ Name: "role",
+ },
+ },
+ Want: `
+ # HELP kube_clusterrolebinding_annotations Kubernetes annotations converted to Prometheus labels.
+ # HELP kube_clusterrolebinding_labels Kubernetes labels converted to Prometheus labels.
+ # HELP kube_clusterrolebinding_info Information about clusterrolebinding.
+ # HELP kube_clusterrolebinding_metadata_resource_version Resource version representing a specific version of the clusterrolebinding.
+ # TYPE kube_clusterrolebinding_annotations gauge
+ # TYPE kube_clusterrolebinding_labels gauge
+ # TYPE kube_clusterrolebinding_info gauge
+ # TYPE kube_clusterrolebinding_metadata_resource_version gauge
+ kube_clusterrolebinding_annotations{annotation_app_k8s_io_owner="@foo",clusterrolebinding="clusterrolebinding1"} 1
+ kube_clusterrolebinding_labels{clusterrolebinding="clusterrolebinding1",label_app="mysql-server"} 1
+ kube_clusterrolebinding_info{clusterrolebinding="clusterrolebinding1",roleref_kind="Role",roleref_name="role"} 1
+`,
+ MetricNames: []string{
+ "kube_clusterrolebinding_annotations",
+ "kube_clusterrolebinding_labels",
+ "kube_clusterrolebinding_info",
+ "kube_clusterrolebinding_metadata_resource_version",
+ },
+ },
+ {
+ Obj: &rbacv1.ClusterRoleBinding{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "clusterrolebinding2",
+ CreationTimestamp: metav1StartTime,
+ ResourceVersion: "10596",
+ },
+ RoleRef: rbacv1.RoleRef{
+ APIGroup: "rbac.authorization.k8s.io",
+ Kind: "Role",
+ Name: "role",
+ },
+ },
+ Want: `
+ # HELP kube_clusterrolebinding_created Unix creation timestamp
+ # HELP kube_clusterrolebinding_info Information about clusterrolebinding.
+ # HELP kube_clusterrolebinding_metadata_resource_version Resource version representing a specific version of the clusterrolebinding.
+ # TYPE kube_clusterrolebinding_created gauge
+ # TYPE kube_clusterrolebinding_info gauge
+ # TYPE kube_clusterrolebinding_metadata_resource_version gauge
+ kube_clusterrolebinding_info{clusterrolebinding="clusterrolebinding2",roleref_kind="Role",roleref_name="role"} 1
+ kube_clusterrolebinding_created{clusterrolebinding="clusterrolebinding2"} 1.501569018e+09
+ kube_clusterrolebinding_metadata_resource_version{clusterrolebinding="clusterrolebinding2"} 10596
+ `,
+ MetricNames: []string{"kube_clusterrolebinding_info", "kube_clusterrolebinding_created", "kube_clusterrolebinding_metadata_resource_version"},
+ },
+ }
+ for i, c := range cases {
+ c.Func = generator.ComposeMetricGenFuncs(clusterRoleBindingMetricFamilies(c.AllowAnnotationsList, c.AllowLabelsList))
+ c.Headers = generator.ExtractMetricFamilyHeaders(clusterRoleBindingMetricFamilies(c.AllowAnnotationsList, c.AllowLabelsList))
+ if err := c.run(); err != nil {
+ t.Errorf("unexpected collecting result in %vth run:\n%s", i, err)
+ }
+ }
+}
diff --git a/internal/store/rolebinding.go b/internal/store/rolebinding.go
new file mode 100644
index 0000000000..cdf95b9e04
--- /dev/null
+++ b/internal/store/rolebinding.go
@@ -0,0 +1,156 @@
+/*
+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"
+
+ rbacv1 "k8s.io/api/rbac/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"
+
+ "k8s.io/kube-state-metrics/v2/pkg/metric"
+ generator "k8s.io/kube-state-metrics/v2/pkg/metric_generator"
+)
+
+var (
+ descRoleBindingAnnotationsName = "kube_rolebinding_annotations"
+ descRoleBindingAnnotationsHelp = "Kubernetes annotations converted to Prometheus labels."
+ descRoleBindingLabelsName = "kube_rolebinding_labels"
+ descRoleBindingLabelsHelp = "Kubernetes labels converted to Prometheus labels."
+ descRoleBindingLabelsDefaultLabels = []string{"namespace", "rolebinding"}
+)
+
+func roleBindingMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator {
+ return []generator.FamilyGenerator{
+ *generator.NewFamilyGenerator(
+ descRoleBindingAnnotationsName,
+ descRoleBindingAnnotationsHelp,
+ metric.Gauge,
+ "",
+ wrapRoleBindingFunc(func(r *rbacv1.RoleBinding) *metric.Family {
+ annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", r.Annotations, allowAnnotationsList)
+ return &metric.Family{
+ Metrics: []*metric.Metric{
+ {
+ LabelKeys: annotationKeys,
+ LabelValues: annotationValues,
+ Value: 1,
+ },
+ },
+ }
+ }),
+ ),
+ *generator.NewFamilyGenerator(
+ descRoleBindingLabelsName,
+ descRoleBindingLabelsHelp,
+ metric.Gauge,
+ "",
+ wrapRoleBindingFunc(func(r *rbacv1.RoleBinding) *metric.Family {
+ labelKeys, labelValues := createPrometheusLabelKeysValues("label", r.Labels, allowLabelsList)
+ return &metric.Family{
+ Metrics: []*metric.Metric{
+ {
+ LabelKeys: labelKeys,
+ LabelValues: labelValues,
+ Value: 1,
+ },
+ },
+ }
+ }),
+ ),
+ *generator.NewFamilyGenerator(
+ "kube_rolebinding_info",
+ "Information about rolebinding.",
+ metric.Gauge,
+ "",
+ wrapRoleBindingFunc(func(r *rbacv1.RoleBinding) *metric.Family {
+ labelKeys := []string{"roleref_kind", "roleref_name"}
+ labelValues := []string{r.RoleRef.Kind, r.RoleRef.Name}
+ return &metric.Family{
+ Metrics: []*metric.Metric{{
+ LabelKeys: labelKeys,
+ LabelValues: labelValues,
+ Value: 1,
+ }},
+ }
+ }),
+ ),
+ *generator.NewFamilyGenerator(
+ "kube_rolebinding_created",
+ "Unix creation timestamp",
+ metric.Gauge,
+ "",
+ wrapRoleBindingFunc(func(r *rbacv1.RoleBinding) *metric.Family {
+ ms := []*metric.Metric{}
+
+ if !r.CreationTimestamp.IsZero() {
+ ms = append(ms, &metric.Metric{
+ LabelKeys: []string{},
+ LabelValues: []string{},
+ Value: float64(r.CreationTimestamp.Unix()),
+ })
+ }
+
+ return &metric.Family{
+ Metrics: ms,
+ }
+ }),
+ ),
+ *generator.NewFamilyGenerator(
+ "kube_rolebinding_metadata_resource_version",
+ "Resource version representing a specific version of the rolebinding.",
+ metric.Gauge,
+ "",
+ wrapRoleBindingFunc(func(r *rbacv1.RoleBinding) *metric.Family {
+ return &metric.Family{
+ Metrics: resourceVersionMetric(r.ObjectMeta.ResourceVersion),
+ }
+ }),
+ ),
+ }
+}
+
+func createRoleBindingListWatch(kubeClient clientset.Interface, ns string, fieldSelector string) cache.ListerWatcher {
+ return &cache.ListWatch{
+ ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
+ opts.FieldSelector = fieldSelector
+ return kubeClient.RbacV1().RoleBindings(ns).List(context.TODO(), opts)
+ },
+ WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
+ opts.FieldSelector = fieldSelector
+ return kubeClient.RbacV1().RoleBindings(ns).Watch(context.TODO(), opts)
+ },
+ }
+}
+
+func wrapRoleBindingFunc(f func(*rbacv1.RoleBinding) *metric.Family) func(interface{}) *metric.Family {
+ return func(obj interface{}) *metric.Family {
+ rolebinding := obj.(*rbacv1.RoleBinding)
+
+ metricFamily := f(rolebinding)
+
+ for _, m := range metricFamily.Metrics {
+ m.LabelKeys, m.LabelValues = mergeKeyValues(descRoleBindingLabelsDefaultLabels, []string{rolebinding.Namespace, rolebinding.Name}, m.LabelKeys, m.LabelValues)
+ }
+
+ return metricFamily
+ }
+}
diff --git a/internal/store/rolebinding_test.go b/internal/store/rolebinding_test.go
new file mode 100644
index 0000000000..17ce4848cd
--- /dev/null
+++ b/internal/store/rolebinding_test.go
@@ -0,0 +1,115 @@
+/*
+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"
+
+ rbacv1 "k8s.io/api/rbac/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+ generator "k8s.io/kube-state-metrics/v2/pkg/metric_generator"
+)
+
+func TestRoleBindingStore(t *testing.T) {
+ startTime := 1501569018
+ metav1StartTime := metav1.Unix(int64(startTime), 0)
+
+ cases := []generateMetricsTestCase{
+ {
+ AllowAnnotationsList: []string{
+ "app.k8s.io/owner",
+ },
+ AllowLabelsList: []string{
+ "app",
+ },
+ Obj: &rbacv1.RoleBinding{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "rolebinding1",
+ Namespace: "ns1",
+ ResourceVersion: "BBBBB",
+ Annotations: map[string]string{
+ "app": "mysql-server",
+ "app.k8s.io/owner": "@foo",
+ },
+ Labels: map[string]string{
+ "excluded": "me",
+ "app": "mysql-server",
+ },
+ },
+ RoleRef: rbacv1.RoleRef{
+ APIGroup: "rbac.authorization.k8s.io",
+ Kind: "Role",
+ Name: "role",
+ },
+ },
+ Want: `
+ # HELP kube_rolebinding_annotations Kubernetes annotations converted to Prometheus labels.
+ # HELP kube_rolebinding_labels Kubernetes labels converted to Prometheus labels.
+ # HELP kube_rolebinding_info Information about rolebinding.
+ # HELP kube_rolebinding_metadata_resource_version Resource version representing a specific version of the rolebinding.
+ # TYPE kube_rolebinding_annotations gauge
+ # TYPE kube_rolebinding_labels gauge
+ # TYPE kube_rolebinding_info gauge
+ # TYPE kube_rolebinding_metadata_resource_version gauge
+ kube_rolebinding_annotations{annotation_app_k8s_io_owner="@foo",rolebinding="rolebinding1",namespace="ns1"} 1
+ kube_rolebinding_labels{rolebinding="rolebinding1",label_app="mysql-server",namespace="ns1"} 1
+ kube_rolebinding_info{rolebinding="rolebinding1",namespace="ns1",roleref_kind="Role",roleref_name="role"} 1
+`,
+ MetricNames: []string{
+ "kube_rolebinding_annotations",
+ "kube_rolebinding_labels",
+ "kube_rolebinding_info",
+ "kube_rolebinding_metadata_resource_version",
+ },
+ },
+ {
+ Obj: &rbacv1.RoleBinding{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "rolebinding2",
+ Namespace: "ns2",
+ CreationTimestamp: metav1StartTime,
+ ResourceVersion: "10596",
+ },
+ RoleRef: rbacv1.RoleRef{
+ APIGroup: "rbac.authorization.k8s.io",
+ Kind: "Role",
+ Name: "role",
+ },
+ },
+ Want: `
+ # HELP kube_rolebinding_created Unix creation timestamp
+ # HELP kube_rolebinding_info Information about rolebinding.
+ # HELP kube_rolebinding_metadata_resource_version Resource version representing a specific version of the rolebinding.
+ # TYPE kube_rolebinding_created gauge
+ # TYPE kube_rolebinding_info gauge
+ # TYPE kube_rolebinding_metadata_resource_version gauge
+ kube_rolebinding_info{rolebinding="rolebinding2",namespace="ns2",roleref_kind="Role",roleref_name="role"} 1
+ kube_rolebinding_created{rolebinding="rolebinding2",namespace="ns2"} 1.501569018e+09
+ kube_rolebinding_metadata_resource_version{rolebinding="rolebinding2",namespace="ns2"} 10596
+ `,
+ MetricNames: []string{"kube_rolebinding_info", "kube_rolebinding_created", "kube_rolebinding_metadata_resource_version"},
+ },
+ }
+ for i, c := range cases {
+ c.Func = generator.ComposeMetricGenFuncs(roleBindingMetricFamilies(c.AllowAnnotationsList, c.AllowLabelsList))
+ c.Headers = generator.ExtractMetricFamilyHeaders(roleBindingMetricFamilies(c.AllowAnnotationsList, c.AllowLabelsList))
+ if err := c.run(); err != nil {
+ t.Errorf("unexpected collecting result in %vth run:\n%s", i, err)
+ }
+ }
+}
diff --git a/jsonnet/kube-state-metrics/kube-state-metrics.libsonnet b/jsonnet/kube-state-metrics/kube-state-metrics.libsonnet
index 80e259dc51..44ff393ebc 100644
--- a/jsonnet/kube-state-metrics/kube-state-metrics.libsonnet
+++ b/jsonnet/kube-state-metrics/kube-state-metrics.libsonnet
@@ -148,7 +148,9 @@
{
apiGroups: ['rbac.authorization.k8s.io'],
resources: [
+ 'clusterrolebindings',
'clusterroles',
+ 'rolebindings',
'roles',
],
verbs: ['list', 'watch'],
diff --git a/pkg/options/resource.go b/pkg/options/resource.go
index 3ca7cd5fd2..1ce4b5ee64 100644
--- a/pkg/options/resource.go
+++ b/pkg/options/resource.go
@@ -27,6 +27,7 @@ var (
// DefaultResources represents the default set of resources in kube-state-metrics.
DefaultResources = ResourceSet{
"certificatesigningrequests": struct{}{},
+ "clusterrolebindings": struct{}{},
"clusterroles": struct{}{},
"configmaps": struct{}{},
"cronjobs": struct{}{},
@@ -49,6 +50,7 @@ var (
"replicasets": struct{}{},
"replicationcontrollers": struct{}{},
"resourcequotas": struct{}{},
+ "rolebindings": struct{}{},
"roles": struct{}{},
"secrets": struct{}{},
"serviceaccounts": struct{}{},
diff --git a/tests/manifests/clusterrolebinding.yaml b/tests/manifests/clusterrolebinding.yaml
new file mode 100644
index 0000000000..fc8c3a58d9
--- /dev/null
+++ b/tests/manifests/clusterrolebinding.yaml
@@ -0,0 +1,12 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: clusterrolebinding
+subjects:
+- kind: ServiceAccount
+ name: test-service-account
+ namespace: default
+roleRef:
+ kind: ClusterRole
+ name: clusterrole
+ apiGroup: rbac.authorization.k8s.io
diff --git a/tests/manifests/rolebinding.yaml b/tests/manifests/rolebinding.yaml
new file mode 100644
index 0000000000..7b01c65bea
--- /dev/null
+++ b/tests/manifests/rolebinding.yaml
@@ -0,0 +1,11 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+ name: rolebinding
+subjects:
+- kind: ServiceAccount
+ name: test-service-account
+roleRef:
+ kind: Role
+ name: role
+ apiGroup: rbac.authorization.k8s.io