Skip to content

Commit

Permalink
Merge pull request #1759 from kaitoii11/roles
Browse files Browse the repository at this point in the history
Add support for role and cluster role
  • Loading branch information
k8s-ci-robot authored Jul 4, 2022
2 parents e4011f8 + 64926a3 commit 335e9e1
Show file tree
Hide file tree
Showing 15 changed files with 594 additions and 5 deletions.
2 changes: 2 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ As of v2.3.0, kube-state-metrics supports additional opt-in metrics via the CLI
Per group of metrics there is one file for each metrics. See each file for specific documentation about the exposed metrics:

- [CertificateSigningRequest Metrics](certificatesigningrequest-metrics.md)
- [ClusterRole Metrics](clusterrole-metrics.md)
- [ConfigMap Metrics](configmap-metrics.md)
- [CronJob Metrics](cronjob-metrics.md)
- [DaemonSet Metrics](daemonset-metrics.md)
Expand All @@ -51,6 +52,7 @@ Per group of metrics there is one file for each metrics. See each file for speci
- [ReplicaSet Metrics](replicaset-metrics.md)
- [ReplicationController Metrics](replicationcontroller-metrics.md)
- [ResourceQuota Metrics](resourcequota-metrics.md)
- [Role Metrics](role-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,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"
--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"
--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/clusterrole-metrics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# ClusterRole Metrics

| Metric name| Metric type | Labels/tags | Status |
| ---------- | ----------- | ----------- | ----------- |
| kube_clusterrole_annotations | Gauge | `clusterrole`=<clusterrole-name> | EXPERIMENTAL
| kube_clusterrole_labels | Gauge | `clusterrole`=<clusterrole-name> | EXPERIMENTAL
| kube_clusterrole_info | Gauge | `clusterrole`=<clusterrole-name> | EXPERIMENTAL |
| kube_clusterrole_created | Gauge | `clusterrole`=<clusterrole-name> | EXPERIMENTAL |
| kube_clusterrole_metadata_resource_version | Gauge | `clusterrole`=<clusterrole-name> | EXPERIMENTAL |
9 changes: 9 additions & 0 deletions docs/role-metrics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Role Metrics

| Metric name| Metric type | Labels/tags | Status |
| ---------- | ----------- | ----------- | ----------- |
| kube_role_annotations | Gauge | `role`=&lt;role-name&gt; <br> `namespace`=&lt;role-namespace&gt; | EXPERIMENTAL
| kube_role_labels | Gauge | `role`=&lt;role-name&gt; <br> `namespace`=&lt;role-namespace&gt; | EXPERIMENTAL
| kube_role_info | Gauge | `role`=&lt;role-name&gt; <br> `namespace`=&lt;role-namespace&gt; | EXPERIMENTAL
| kube_role_created | Gauge | `role`=&lt;role-name&gt; <br> `namespace`=&lt;role-namespace&gt; | EXPERIMENTAL |
| kube_role_metadata_resource_version | Gauge | `role`=&lt;role-name&gt; <br> `namespace`=&lt;role-namespace&gt; | EXPERIMENTAL |
8 changes: 8 additions & 0 deletions examples/autosharding/cluster-role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,11 @@ rules:
verbs:
- list
- watch
- apiGroups:
- rbac.authorization.k8s.io
resources:
- clusterroles
- roles
verbs:
- list
- watch
8 changes: 8 additions & 0 deletions examples/standard/cluster-role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,11 @@ rules:
verbs:
- list
- watch
- apiGroups:
- rbac.authorization.k8s.io
resources:
- clusterroles
- roles
verbs:
- list
- watch
11 changes: 11 additions & 0 deletions internal/store/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
v1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
policyv1 "k8s.io/api/policy/v1"
rbacv1 "k8s.io/api/rbac/v1"
storagev1 "k8s.io/api/storage/v1"
vpaautoscaling "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1beta2"
vpaclientset "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/client/clientset/versioned"
Expand Down Expand Up @@ -261,6 +262,7 @@ func (b *Builder) BuildStores() [][]cache.Store {

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() },
"cronjobs": func(b *Builder) []cache.Store { return b.buildCronJobStores() },
"daemonsets": func(b *Builder) []cache.Store { return b.buildDaemonSetStores() },
Expand All @@ -282,6 +284,7 @@ var availableStores = map[string]func(f *Builder) []cache.Store{
"replicasets": func(b *Builder) []cache.Store { return b.buildReplicaSetStores() },
"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() },
"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 @@ -425,6 +428,14 @@ func (b *Builder) buildLeasesStores() []cache.Store {
return b.buildStoresFunc(leaseMetricFamilies, &coordinationv1.Lease{}, createLeaseListWatch, b.useAPIServerCache)
}

func (b *Builder) buildClusterRoleStores() []cache.Store {
return b.buildStoresFunc(clusterRoleMetricFamilies(b.allowAnnotationsList["clusterroles"], b.allowLabelsList["clusterroles"]), &rbacv1.ClusterRole{}, createClusterRoleListWatch, b.useAPIServerCache)
}

func (b *Builder) buildRoleStores() []cache.Store {
return b.buildStoresFunc(roleMetricFamilies(b.allowAnnotationsList["roles"], b.allowLabelsList["roles"]), &rbacv1.Role{}, createRoleListWatch, b.useAPIServerCache)
}

func (b *Builder) buildStores(
metricFamilies []generator.FamilyGenerator,
expectedType interface{},
Expand Down
154 changes: 154 additions & 0 deletions internal/store/clusterrole.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/*
Copyright 2018 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 (
descClusterRoleAnnotationsName = "kube_clusterrole_annotations"
descClusterRoleAnnotationsHelp = "Kubernetes annotations converted to Prometheus labels."
descClusterRoleLabelsName = "kube_clusterrole_labels"
descClusterRoleLabelsHelp = "Kubernetes labels converted to Prometheus labels."
descClusterRoleLabelsDefaultLabels = []string{"clusterrole"}
)

func clusterRoleMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator {
return []generator.FamilyGenerator{
*generator.NewFamilyGenerator(
descClusterRoleAnnotationsName,
descClusterRoleAnnotationsHelp,
metric.Gauge,
"",
wrapClusterRoleFunc(func(r *rbacv1.ClusterRole) *metric.Family {
annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", r.Annotations, allowAnnotationsList)
return &metric.Family{
Metrics: []*metric.Metric{
{
LabelKeys: annotationKeys,
LabelValues: annotationValues,
Value: 1,
},
},
}
}),
),
*generator.NewFamilyGenerator(
descClusterRoleLabelsName,
descClusterRoleLabelsHelp,
metric.Gauge,
"",
wrapClusterRoleFunc(func(r *rbacv1.ClusterRole) *metric.Family {
labelKeys, labelValues := createPrometheusLabelKeysValues("label", r.Labels, allowLabelsList)
return &metric.Family{
Metrics: []*metric.Metric{
{
LabelKeys: labelKeys,
LabelValues: labelValues,
Value: 1,
},
},
}
}),
),
*generator.NewFamilyGenerator(
"kube_clusterrole_info",
"Information about cluster role.",
metric.Gauge,
"",
wrapClusterRoleFunc(func(r *rbacv1.ClusterRole) *metric.Family {
return &metric.Family{
Metrics: []*metric.Metric{{
LabelKeys: []string{},
LabelValues: []string{},
Value: 1,
}},
}
}),
),
*generator.NewFamilyGenerator(
"kube_clusterrole_created",
"Unix creation timestamp",
metric.Gauge,
"",
wrapClusterRoleFunc(func(r *rbacv1.ClusterRole) *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_clusterrole_metadata_resource_version",
"Resource version representing a specific version of the cluster role.",
metric.Gauge,
"",
wrapClusterRoleFunc(func(r *rbacv1.ClusterRole) *metric.Family {
return &metric.Family{
Metrics: resourceVersionMetric(r.ObjectMeta.ResourceVersion),
}
}),
),
}
}

func createClusterRoleListWatch(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().ClusterRoles().List(context.TODO(), opts)
},
WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
opts.FieldSelector = fieldSelector
return kubeClient.RbacV1().ClusterRoles().Watch(context.TODO(), opts)
},
}
}

func wrapClusterRoleFunc(f func(*rbacv1.ClusterRole) *metric.Family) func(interface{}) *metric.Family {
return func(obj interface{}) *metric.Family {
clusterrole := obj.(*rbacv1.ClusterRole)

metricFamily := f(clusterrole)

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

return metricFamily
}
}
103 changes: 103 additions & 0 deletions internal/store/clusterrole_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
Copyright 2012 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 TestClusterRoleStore(t *testing.T) {
startTime := 1501569018
metav1StartTime := metav1.Unix(int64(startTime), 0)

cases := []generateMetricsTestCase{
{
AllowAnnotationsList: []string{
"app.k8s.io/owner",
},
AllowLabelsList: []string{
"app",
},
Obj: &rbacv1.ClusterRole{
ObjectMeta: metav1.ObjectMeta{
Name: "role1",
ResourceVersion: "BBBBB",
Annotations: map[string]string{
"app": "mysql-server",
"app.k8s.io/owner": "@foo",
},
Labels: map[string]string{
"excluded": "me",
"app": "mysql-server",
},
},
},
Want: `
# HELP kube_clusterrole_annotations Kubernetes annotations converted to Prometheus labels.
# HELP kube_clusterrole_labels Kubernetes labels converted to Prometheus labels.
# HELP kube_clusterrole_info Information about cluster role.
# HELP kube_clusterrole_metadata_resource_version Resource version representing a specific version of the cluster role.
# TYPE kube_clusterrole_annotations gauge
# TYPE kube_clusterrole_labels gauge
# TYPE kube_clusterrole_info gauge
# TYPE kube_clusterrole_metadata_resource_version gauge
kube_clusterrole_annotations{annotation_app_k8s_io_owner="@foo",clusterrole="role1"} 1
kube_clusterrole_labels{clusterrole="role1",label_app="mysql-server"} 1
kube_clusterrole_info{clusterrole="role1"} 1
`,
MetricNames: []string{
"kube_clusterrole_annotations",
"kube_clusterrole_labels",
"kube_clusterrole_info",
"kube_clusterrole_metadata_resource_version",
},
},
{
Obj: &rbacv1.ClusterRole{
ObjectMeta: metav1.ObjectMeta{
Name: "role2",
CreationTimestamp: metav1StartTime,
ResourceVersion: "10596",
},
},
Want: `
# HELP kube_clusterrole_created Unix creation timestamp
# HELP kube_clusterrole_info Information about cluster role.
# HELP kube_clusterrole_metadata_resource_version Resource version representing a specific version of the cluster role.
# TYPE kube_clusterrole_created gauge
# TYPE kube_clusterrole_info gauge
# TYPE kube_clusterrole_metadata_resource_version gauge
kube_clusterrole_info{clusterrole="role2"} 1
kube_clusterrole_created{clusterrole="role2"} 1.501569018e+09
kube_clusterrole_metadata_resource_version{clusterrole="role2"} 10596
`,
MetricNames: []string{"kube_clusterrole_info", "kube_clusterrole_created", "kube_clusterrole_metadata_resource_version"},
},
}
for i, c := range cases {
c.Func = generator.ComposeMetricGenFuncs(clusterRoleMetricFamilies(c.AllowAnnotationsList, c.AllowLabelsList))
c.Headers = generator.ExtractMetricFamilyHeaders(clusterRoleMetricFamilies(c.AllowAnnotationsList, c.AllowLabelsList))
if err := c.run(); err != nil {
t.Errorf("unexpected collecting result in %vth run:\n%s", i, err)
}
}
}
Loading

0 comments on commit 335e9e1

Please sign in to comment.