Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for rolebindings #1799

Merged
merged 6 commits into from
Aug 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion docs/cli-arguments.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions docs/clusterrolebinding-metrics.md
Original file line number Diff line number Diff line change
@@ -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`=&lt;clusterrolebinding-name&gt; <br> `roleref_kind`=&lt;role-kind&gt; <br> `roleref_name`=&lt;role-name&gt; | EXPERIMENTAL |
| kube_clusterrolebinding_created | Gauge | `clusterrolebinding`=&lt;clusterrolebinding-name&gt; | EXPERIMENTAL |
| kube_clusterrolebinding_metadata_resource_version | Gauge | `clusterrolebinding`=&lt;clusterrolebinding-name&gt; | EXPERIMENTAL |
9 changes: 9 additions & 0 deletions docs/rolebinding-metrics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# RoleBinding Metrics

| Metric name| Metric type | Labels/tags | Status |
| ---------- | ----------- | ----------- | ----------- |
| kube_rolebinding_annotations | Gauge | `rolebinding`=&lt;rolebinding-name&gt; <br> `namespace`=&lt;rolebinding-namespace&gt; | EXPERIMENTAL
| kube_rolebinding_labels | Gauge | `rolebinding`=&lt;rolebinding-name&gt; <br> `namespace`=&lt;rolebinding-namespace&gt; | EXPERIMENTAL
| kube_rolebinding_info | Gauge | `rolebinding`=&lt;rolebinding-name&gt; <br> `namespace`=&lt;rolebinding-namespace&gt; <br> `roleref_kind`=&lt;role-kind&gt; <br> `roleref_name`=&lt;role-name&gt;| EXPERIMENTAL
| kube_rolebinding_created | Gauge | `rolebinding`=&lt;rolebinding-name&gt; <br> `namespace`=&lt;rolebinding-namespace&gt; | EXPERIMENTAL |
| kube_rolebinding_metadata_resource_version | Gauge | `rolebinding`=&lt;rolebinding-name&gt; <br> `namespace`=&lt;rolebinding-namespace&gt; | EXPERIMENTAL |
2 changes: 2 additions & 0 deletions examples/autosharding/cluster-role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ rules:
- apiGroups:
- rbac.authorization.k8s.io
resources:
- clusterrolebindings
- clusterroles
- rolebindings
- roles
verbs:
- list
Expand Down
2 changes: 2 additions & 0 deletions examples/standard/cluster-role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ rules:
- apiGroups:
- rbac.authorization.k8s.io
resources:
- clusterrolebindings
- clusterroles
- rolebindings
- roles
verbs:
- list
Expand Down
10 changes: 10 additions & 0 deletions internal/store/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() },
Expand All @@ -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() },
Expand Down Expand Up @@ -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{},
Expand Down
156 changes: 156 additions & 0 deletions internal/store/clusterrolebinding.go
Original file line number Diff line number Diff line change
@@ -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"}
kaitoii11 marked this conversation as resolved.
Show resolved Hide resolved
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
}
}
113 changes: 113 additions & 0 deletions internal/store/clusterrolebinding_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
}
Loading