Skip to content

Commit 7db82c1

Browse files
committed
feat: Use PartialObjectMetadata for Configmaps
1 parent c804368 commit 7db82c1

File tree

9 files changed

+160
-19
lines changed

9 files changed

+160
-19
lines changed

internal/store/builder.go

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ import (
3838
policyv1 "k8s.io/api/policy/v1"
3939
rbacv1 "k8s.io/api/rbac/v1"
4040
storagev1 "k8s.io/api/storage/v1"
41+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
4142
clientset "k8s.io/client-go/kubernetes"
43+
"k8s.io/client-go/metadata"
4244
"k8s.io/client-go/tools/cache"
4345
"k8s.io/klog/v2"
4446

@@ -66,12 +68,14 @@ var _ ksmtypes.BuilderInterface = &Builder{}
6668
// (https://en.wikipedia.org/wiki/Builder_pattern).
6769
type Builder struct {
6870
kubeClient clientset.Interface
71+
metadataOnlyKubeClient metadata.Interface
72+
customResourceClients map[string]interface{}
6973
ctx context.Context
7074
familyGeneratorFilter generator.FamilyGeneratorFilter
71-
customResourceClients map[string]interface{}
7275
listWatchMetrics *watch.ListWatchMetrics
7376
shardingMetrics *sharding.Metrics
7477
buildStoresFunc ksmtypes.BuildStoresFunc
78+
buildMetadataOnlyStoresFunc ksmtypes.BuildMetadataOnlyStoresFunc
7579
buildCustomResourceStoresFunc ksmtypes.BuildCustomResourceStoresFunc
7680
allowAnnotationsList map[string][]string
7781
allowLabelsList map[string][]string
@@ -155,6 +159,11 @@ func (b *Builder) WithKubeClient(c clientset.Interface) {
155159
b.kubeClient = c
156160
}
157161

162+
// WithMetadataOnlyKubeClient sets the metadataOnlyKubeClient property of a Builder.
163+
func (b *Builder) WithMetadataOnlyKubeClient(c metadata.Interface) {
164+
b.metadataOnlyKubeClient = c
165+
}
166+
158167
// WithCustomResourceClients sets the customResourceClients property of a Builder.
159168
func (b *Builder) WithCustomResourceClients(cs map[string]interface{}) {
160169
b.customResourceClients = cs
@@ -176,6 +185,11 @@ func (b *Builder) WithGenerateStoresFunc(f ksmtypes.BuildStoresFunc) {
176185
b.buildStoresFunc = f
177186
}
178187

188+
// WithGenerateMetadataOnlyStoresFunc configures a custom generate custom resource store function
189+
func (b *Builder) WithGenerateMetadataOnlyStoresFunc(f ksmtypes.BuildMetadataOnlyStoresFunc) {
190+
b.buildMetadataOnlyStoresFunc = f
191+
}
192+
179193
// WithGenerateCustomResourceStoresFunc configures a custom generate custom resource store function
180194
func (b *Builder) WithGenerateCustomResourceStoresFunc(f ksmtypes.BuildCustomResourceStoresFunc) {
181195
b.buildCustomResourceStoresFunc = f
@@ -186,6 +200,11 @@ func (b *Builder) DefaultGenerateStoresFunc() ksmtypes.BuildStoresFunc {
186200
return b.buildStores
187201
}
188202

203+
// DefaultGenerateMetadataOnlyStoresFunc returns default buildStores function
204+
func (b *Builder) DefaultGenerateMetadataOnlyStoresFunc() ksmtypes.BuildMetadataOnlyStoresFunc {
205+
return b.buildMetadataOnlyStores
206+
}
207+
189208
// DefaultGenerateCustomResourceStoresFunc returns default buildCustomResourceStores function
190209
func (b *Builder) DefaultGenerateCustomResourceStoresFunc() ksmtypes.BuildCustomResourceStoresFunc {
191210
return b.buildCustomResourceStores
@@ -360,7 +379,7 @@ func availableResources() []string {
360379
}
361380

362381
func (b *Builder) buildConfigMapStores() []cache.Store {
363-
return b.buildStoresFunc(configMapMetricFamilies(b.allowAnnotationsList["configmaps"], b.allowLabelsList["configmaps"]), &v1.ConfigMap{}, createConfigMapListWatch, b.useAPIServerCache)
382+
return b.buildMetadataOnlyStoresFunc(configMapMetricFamilies(b.allowAnnotationsList["configmaps"], b.allowLabelsList["configmaps"]), &metav1.PartialObjectMetadata{}, createConfigMapListWatch, b.useAPIServerCache)
364383
}
365384

366385
func (b *Builder) buildCronJobStores() []cache.Store {
@@ -517,7 +536,8 @@ func (b *Builder) buildStores(
517536
if b.fieldSelectorFilter != "" {
518537
klog.InfoS("FieldSelector is used", "fieldSelector", b.fieldSelectorFilter)
519538
}
520-
listWatcher := listWatchFunc(b.kubeClient, v1.NamespaceAll, b.fieldSelectorFilter)
539+
kubeClient := b.kubeClient
540+
listWatcher := listWatchFunc(kubeClient, v1.NamespaceAll, b.fieldSelectorFilter)
521541
b.startReflector(expectedType, store, listWatcher, useAPIServerCache)
522542
return []cache.Store{store}
523543
}
@@ -539,6 +559,46 @@ func (b *Builder) buildStores(
539559
return stores
540560
}
541561

562+
func (b *Builder) buildMetadataOnlyStores(
563+
metricFamilies []generator.FamilyGenerator,
564+
expectedType interface{},
565+
listWatchFunc func(kubeClient metadata.Interface, ns string, fieldSelector string) cache.ListerWatcher,
566+
useAPIServerCache bool,
567+
) []cache.Store {
568+
metricFamilies = generator.FilterFamilyGenerators(b.familyGeneratorFilter, metricFamilies)
569+
composedMetricGenFuncs := generator.ComposeMetricGenFuncs(metricFamilies)
570+
familyHeaders := generator.ExtractMetricFamilyHeaders(metricFamilies)
571+
572+
if b.namespaces.IsAllNamespaces() {
573+
store := metricsstore.NewMetricsStore(
574+
familyHeaders,
575+
composedMetricGenFuncs,
576+
)
577+
if b.fieldSelectorFilter != "" {
578+
klog.InfoS("FieldSelector is used", "fieldSelector", b.fieldSelectorFilter)
579+
}
580+
listWatcher := listWatchFunc(b.metadataOnlyKubeClient, v1.NamespaceAll, b.fieldSelectorFilter)
581+
b.startReflector(expectedType, store, listWatcher, useAPIServerCache)
582+
return []cache.Store{store}
583+
}
584+
585+
stores := make([]cache.Store, 0, len(b.namespaces))
586+
for _, ns := range b.namespaces {
587+
store := metricsstore.NewMetricsStore(
588+
familyHeaders,
589+
composedMetricGenFuncs,
590+
)
591+
if b.fieldSelectorFilter != "" {
592+
klog.InfoS("FieldSelector is used", "fieldSelector", b.fieldSelectorFilter)
593+
}
594+
listWatcher := listWatchFunc(b.metadataOnlyKubeClient, ns, b.fieldSelectorFilter)
595+
b.startReflector(expectedType, store, listWatcher, useAPIServerCache)
596+
stores = append(stores, store)
597+
}
598+
599+
return stores
600+
}
601+
542602
// TODO(Garrybest): Merge `buildStores` and `buildCustomResourceStores`
543603
func (b *Builder) buildCustomResourceStores(resourceName string,
544604
metricFamilies []generator.FamilyGenerator,

internal/store/configmap.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ package store
1919
import (
2020
"context"
2121

22-
v1 "k8s.io/api/core/v1"
2322
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2423
"k8s.io/apimachinery/pkg/runtime"
24+
"k8s.io/apimachinery/pkg/runtime/schema"
2525
"k8s.io/apimachinery/pkg/watch"
26-
clientset "k8s.io/client-go/kubernetes"
26+
"k8s.io/client-go/metadata"
2727
"k8s.io/client-go/tools/cache"
2828
basemetrics "k8s.io/component-base/metrics"
2929

@@ -43,7 +43,7 @@ func configMapMetricFamilies(allowAnnotationsList, allowLabelsList []string) []g
4343
metric.Gauge,
4444
basemetrics.ALPHA,
4545
"",
46-
wrapConfigMapFunc(func(c *v1.ConfigMap) *metric.Family {
46+
wrapConfigMapFunc(func(c *metav1.PartialObjectMetadata) *metric.Family {
4747
if len(allowAnnotationsList) == 0 {
4848
return &metric.Family{}
4949
}
@@ -65,7 +65,7 @@ func configMapMetricFamilies(allowAnnotationsList, allowLabelsList []string) []g
6565
metric.Gauge,
6666
basemetrics.STABLE,
6767
"",
68-
wrapConfigMapFunc(func(c *v1.ConfigMap) *metric.Family {
68+
wrapConfigMapFunc(func(c *metav1.PartialObjectMetadata) *metric.Family {
6969
if len(allowLabelsList) == 0 {
7070
return &metric.Family{}
7171
}
@@ -87,7 +87,7 @@ func configMapMetricFamilies(allowAnnotationsList, allowLabelsList []string) []g
8787
metric.Gauge,
8888
basemetrics.STABLE,
8989
"",
90-
wrapConfigMapFunc(func(_ *v1.ConfigMap) *metric.Family {
90+
wrapConfigMapFunc(func(_ *metav1.PartialObjectMetadata) *metric.Family {
9191
return &metric.Family{
9292
Metrics: []*metric.Metric{{
9393
LabelKeys: []string{},
@@ -103,7 +103,7 @@ func configMapMetricFamilies(allowAnnotationsList, allowLabelsList []string) []g
103103
metric.Gauge,
104104
basemetrics.STABLE,
105105
"",
106-
wrapConfigMapFunc(func(c *v1.ConfigMap) *metric.Family {
106+
wrapConfigMapFunc(func(c *metav1.PartialObjectMetadata) *metric.Family {
107107
ms := []*metric.Metric{}
108108

109109
if !c.CreationTimestamp.IsZero() {
@@ -125,7 +125,7 @@ func configMapMetricFamilies(allowAnnotationsList, allowLabelsList []string) []g
125125
metric.Gauge,
126126
basemetrics.ALPHA,
127127
"",
128-
wrapConfigMapFunc(func(c *v1.ConfigMap) *metric.Family {
128+
wrapConfigMapFunc(func(c *metav1.PartialObjectMetadata) *metric.Family {
129129
return &metric.Family{
130130
Metrics: resourceVersionMetric(c.ObjectMeta.ResourceVersion),
131131
}
@@ -134,22 +134,22 @@ func configMapMetricFamilies(allowAnnotationsList, allowLabelsList []string) []g
134134
}
135135
}
136136

137-
func createConfigMapListWatch(kubeClient clientset.Interface, ns string, fieldSelector string) cache.ListerWatcher {
137+
func createConfigMapListWatch(kubeClient metadata.Interface, ns string, fieldSelector string) cache.ListerWatcher {
138138
return &cache.ListWatch{
139139
ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
140140
opts.FieldSelector = fieldSelector
141-
return kubeClient.CoreV1().ConfigMaps(ns).List(context.TODO(), opts)
141+
return kubeClient.Resource(schema.GroupVersionResource{Group: "", Version: "v1", Resource: "configmaps"}).Namespace(ns).List(context.TODO(), opts)
142142
},
143143
WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
144144
opts.FieldSelector = fieldSelector
145-
return kubeClient.CoreV1().ConfigMaps(ns).Watch(context.TODO(), opts)
145+
return kubeClient.Resource(schema.GroupVersionResource{Group: "", Version: "v1", Resource: "configmaps"}).Namespace(ns).Watch(context.TODO(), opts)
146146
},
147147
}
148148
}
149149

150-
func wrapConfigMapFunc(f func(*v1.ConfigMap) *metric.Family) func(interface{}) *metric.Family {
150+
func wrapConfigMapFunc(f func(*metav1.PartialObjectMetadata) *metric.Family) func(interface{}) *metric.Family {
151151
return func(obj interface{}) *metric.Family {
152-
configMap := obj.(*v1.ConfigMap)
152+
configMap := obj.(*metav1.PartialObjectMetadata)
153153

154154
metricFamily := f(configMap)
155155

internal/store/configmap_test.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package store
1919
import (
2020
"testing"
2121

22-
v1 "k8s.io/api/core/v1"
2322
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2423

2524
generator "k8s.io/kube-state-metrics/v2/pkg/metric_generator"
@@ -37,7 +36,7 @@ func TestConfigMapStore(t *testing.T) {
3736
AllowLabelsList: []string{
3837
"app",
3938
},
40-
Obj: &v1.ConfigMap{
39+
Obj: &metav1.PartialObjectMetadata{
4140
ObjectMeta: metav1.ObjectMeta{
4241
Name: "configmap1",
4342
Namespace: "ns1",
@@ -73,7 +72,7 @@ func TestConfigMapStore(t *testing.T) {
7372
},
7473
},
7574
{
76-
Obj: &v1.ConfigMap{
75+
Obj: &metav1.PartialObjectMetadata{
7776
ObjectMeta: metav1.ObjectMeta{
7877
Name: "configmap2",
7978
Namespace: "ns2",

pkg/app/server.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ func RunKubeStateMetrics(ctx context.Context, opts *options.Options) error {
255255

256256
storeBuilder.WithUsingAPIServerCache(opts.UseAPIServerCache)
257257
storeBuilder.WithGenerateStoresFunc(storeBuilder.DefaultGenerateStoresFunc())
258+
storeBuilder.WithGenerateMetadataOnlyStoresFunc(storeBuilder.DefaultGenerateMetadataOnlyStoresFunc())
258259
proc.StartReaper()
259260

260261
storeBuilder.WithUtilOptions(opts)
@@ -264,6 +265,12 @@ func RunKubeStateMetrics(ctx context.Context, opts *options.Options) error {
264265
}
265266
storeBuilder.WithKubeClient(kubeClient)
266267

268+
metadataOnlyKubeClient, err := util.CreateMetadataOnlyKubeClient(opts.Apiserver, opts.Kubeconfig)
269+
if err != nil {
270+
return fmt.Errorf("failed to create metadata-only client: %v", err)
271+
}
272+
storeBuilder.WithMetadataOnlyKubeClient(metadataOnlyKubeClient)
273+
267274
storeBuilder.WithSharding(opts.Shard, opts.TotalShards)
268275
if err := storeBuilder.WithAllowAnnotations(opts.AnnotationsAllowList); err != nil {
269276
return fmt.Errorf("failed to set up annotations allowlist: %v", err)

pkg/app/server_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import (
3939
"k8s.io/apimachinery/pkg/types"
4040
"k8s.io/apimachinery/pkg/watch"
4141
"k8s.io/client-go/kubernetes/fake"
42+
mfake "k8s.io/client-go/metadata/fake"
4243
"k8s.io/client-go/rest"
4344
"k8s.io/client-go/tools/cache"
4445
"k8s.io/klog/v2"
@@ -67,6 +68,7 @@ func BenchmarkKubeStateMetrics(b *testing.B) {
6768
)
6869

6970
kubeClient := fake.NewSimpleClientset()
71+
metadataOnlyKubeClient := mfake.NewSimpleMetadataClient(mfake.NewTestScheme())
7072

7173
if err := injectFixtures(kubeClient, fixtureMultiplier); err != nil {
7274
b.Errorf("error injecting resources: %v", err)
@@ -86,10 +88,12 @@ func BenchmarkKubeStateMetrics(b *testing.B) {
8688
b.Fatal(err)
8789
}
8890
builder.WithKubeClient(kubeClient)
91+
builder.WithMetadataOnlyKubeClient(metadataOnlyKubeClient)
8992
builder.WithSharding(0, 1)
9093
builder.WithContext(ctx)
9194
builder.WithNamespaces(options.DefaultNamespaces)
9295
builder.WithGenerateStoresFunc(builder.DefaultGenerateStoresFunc())
96+
builder.WithGenerateMetadataOnlyStoresFunc(builder.DefaultGenerateMetadataOnlyStoresFunc())
9397

9498
allowDenyListFilter, err := allowdenylist.New(map[string]struct{}{}, map[string]struct{}{})
9599
if err != nil {
@@ -147,6 +151,7 @@ func TestFullScrapeCycle(t *testing.T) {
147151
t.Parallel()
148152

149153
kubeClient := fake.NewSimpleClientset()
154+
metadataOnlyKubeClient := mfake.NewSimpleMetadataClient(mfake.NewTestScheme())
150155

151156
err := pod(kubeClient, 0)
152157
if err != nil {
@@ -163,8 +168,10 @@ func TestFullScrapeCycle(t *testing.T) {
163168
t.Fatal(err)
164169
}
165170
builder.WithKubeClient(kubeClient)
171+
builder.WithMetadataOnlyKubeClient(metadataOnlyKubeClient)
166172
builder.WithNamespaces(options.DefaultNamespaces)
167173
builder.WithGenerateStoresFunc(builder.DefaultGenerateStoresFunc())
174+
builder.WithGenerateMetadataOnlyStoresFunc(builder.DefaultGenerateMetadataOnlyStoresFunc())
168175

169176
l, err := allowdenylist.New(map[string]struct{}{}, map[string]struct{}{})
170177
if err != nil {
@@ -442,6 +449,7 @@ func TestShardingEquivalenceScrapeCycle(t *testing.T) {
442449
t.Parallel()
443450

444451
kubeClient := fake.NewSimpleClientset()
452+
metadataOnlyKubeClient := mfake.NewSimpleMetadataClient(mfake.NewTestScheme())
445453

446454
for i := 0; i < 10; i++ {
447455
err := pod(kubeClient, i)
@@ -465,10 +473,12 @@ func TestShardingEquivalenceScrapeCycle(t *testing.T) {
465473
t.Fatal(err)
466474
}
467475
unshardedBuilder.WithKubeClient(kubeClient)
476+
unshardedBuilder.WithMetadataOnlyKubeClient(metadataOnlyKubeClient)
468477
unshardedBuilder.WithNamespaces(options.DefaultNamespaces)
469478
unshardedBuilder.WithFamilyGeneratorFilter(l)
470479
unshardedBuilder.WithAllowLabels(map[string][]string{})
471480
unshardedBuilder.WithGenerateStoresFunc(unshardedBuilder.DefaultGenerateStoresFunc())
481+
unshardedBuilder.WithGenerateMetadataOnlyStoresFunc(unshardedBuilder.DefaultGenerateMetadataOnlyStoresFunc())
472482

473483
unshardedHandler := metricshandler.New(&options.Options{}, kubeClient, unshardedBuilder, false)
474484
unshardedHandler.ConfigureSharding(ctx, 0, 1)
@@ -481,10 +491,13 @@ func TestShardingEquivalenceScrapeCycle(t *testing.T) {
481491
t.Fatal(err)
482492
}
483493
shardedBuilder1.WithKubeClient(kubeClient)
494+
shardedBuilder1.WithMetadataOnlyKubeClient(metadataOnlyKubeClient)
495+
484496
shardedBuilder1.WithNamespaces(options.DefaultNamespaces)
485497
shardedBuilder1.WithFamilyGeneratorFilter(l)
486498
shardedBuilder1.WithAllowLabels(map[string][]string{})
487499
shardedBuilder1.WithGenerateStoresFunc(shardedBuilder1.DefaultGenerateStoresFunc())
500+
shardedBuilder1.WithGenerateMetadataOnlyStoresFunc(shardedBuilder1.DefaultGenerateMetadataOnlyStoresFunc())
488501

489502
shardedHandler1 := metricshandler.New(&options.Options{}, kubeClient, shardedBuilder1, false)
490503
shardedHandler1.ConfigureSharding(ctx, 0, 2)
@@ -497,10 +510,12 @@ func TestShardingEquivalenceScrapeCycle(t *testing.T) {
497510
t.Fatal(err)
498511
}
499512
shardedBuilder2.WithKubeClient(kubeClient)
513+
shardedBuilder2.WithMetadataOnlyKubeClient(metadataOnlyKubeClient)
500514
shardedBuilder2.WithNamespaces(options.DefaultNamespaces)
501515
shardedBuilder2.WithFamilyGeneratorFilter(l)
502516
shardedBuilder2.WithAllowLabels(map[string][]string{})
503517
shardedBuilder2.WithGenerateStoresFunc(shardedBuilder2.DefaultGenerateStoresFunc())
518+
shardedBuilder2.WithGenerateMetadataOnlyStoresFunc(shardedBuilder2.DefaultGenerateMetadataOnlyStoresFunc())
504519

505520
shardedHandler2 := metricshandler.New(&options.Options{}, kubeClient, shardedBuilder2, false)
506521
shardedHandler2.ConfigureSharding(ctx, 1, 2)
@@ -612,6 +627,7 @@ func TestShardingEquivalenceScrapeCycle(t *testing.T) {
612627
// We use custom resource object samplev1alpha1.Foo in kubernetes/sample-controller as an example.
613628
func TestCustomResourceExtension(t *testing.T) {
614629
kubeClient := fake.NewSimpleClientset()
630+
metadataOnlyKubeClient := mfake.NewSimpleMetadataClient(mfake.NewTestScheme())
615631
factories := []customresource.RegistryFactory{new(fooFactory)}
616632
resources := options.DefaultResources.AsSlice()
617633
customResourceClients := make(map[string]interface{}, len(factories))
@@ -638,9 +654,11 @@ func TestCustomResourceExtension(t *testing.T) {
638654
}
639655

640656
builder.WithKubeClient(kubeClient)
657+
builder.WithMetadataOnlyKubeClient(metadataOnlyKubeClient)
641658
builder.WithCustomResourceClients(customResourceClients)
642659
builder.WithNamespaces(options.DefaultNamespaces)
643660
builder.WithGenerateStoresFunc(builder.DefaultGenerateStoresFunc())
661+
builder.WithGenerateMetadataOnlyStoresFunc(builder.DefaultGenerateMetadataOnlyStoresFunc())
644662
builder.WithGenerateCustomResourceStoresFunc(builder.DefaultGenerateCustomResourceStoresFunc())
645663

646664
l, err := allowdenylist.New(map[string]struct{}{}, map[string]struct{}{})

0 commit comments

Comments
 (0)