Skip to content

Commit 4d9ee4b

Browse files
committed
feat: Use PartialObjectMetadata for Configmaps and Secrets
1 parent f8aa7d9 commit 4d9ee4b

File tree

6 files changed

+131
-17
lines changed

6 files changed

+131
-17
lines changed

internal/store/builder.go

+65-5
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

@@ -65,9 +67,10 @@ var _ ksmtypes.BuilderInterface = &Builder{}
6567
// Builder helps to build store. It follows the builder pattern
6668
// (https://en.wikipedia.org/wiki/Builder_pattern).
6769
type Builder struct {
68-
kubeClient clientset.Interface
69-
customResourceClients map[string]interface{}
70-
namespaces options.NamespaceList
70+
kubeClient clientset.Interface
71+
metadataOnlyKubeClient metadata.Interface
72+
customResourceClients map[string]interface{}
73+
namespaces options.NamespaceList
7174
// namespaceFilter is inside fieldSelectorFilter
7275
fieldSelectorFilter string
7376
ctx context.Context
@@ -78,6 +81,7 @@ type Builder struct {
7881
shard int32
7982
totalShards int
8083
buildStoresFunc ksmtypes.BuildStoresFunc
84+
buildMetadataOnlyStoresFunc ksmtypes.BuildMetadataOnlyStoresFunc
8185
buildCustomResourceStoresFunc ksmtypes.BuildCustomResourceStoresFunc
8286
allowAnnotationsList map[string][]string
8387
allowLabelsList map[string][]string
@@ -157,6 +161,11 @@ func (b *Builder) WithKubeClient(c clientset.Interface) {
157161
b.kubeClient = c
158162
}
159163

164+
// WithMetadataOnlyKubeClient sets the metadataOnlyKubeClient property of a Builder.
165+
func (b *Builder) WithMetadataOnlyKubeClient(c metadata.Interface) {
166+
b.metadataOnlyKubeClient = c
167+
}
168+
160169
// WithCustomResourceClients sets the customResourceClients property of a Builder.
161170
func (b *Builder) WithCustomResourceClients(cs map[string]interface{}) {
162171
b.customResourceClients = cs
@@ -178,6 +187,11 @@ func (b *Builder) WithGenerateStoresFunc(f ksmtypes.BuildStoresFunc) {
178187
b.buildStoresFunc = f
179188
}
180189

190+
// WithGenerateMetadataOnlyStoresFunc configures a custom generate custom resource store function
191+
func (b *Builder) WithGenerateMetadataOnlyStoresFunc(f ksmtypes.BuildMetadataOnlyStoresFunc) {
192+
b.buildMetadataOnlyStoresFunc = f
193+
}
194+
181195
// WithGenerateCustomResourceStoresFunc configures a custom generate custom resource store function
182196
func (b *Builder) WithGenerateCustomResourceStoresFunc(f ksmtypes.BuildCustomResourceStoresFunc) {
183197
b.buildCustomResourceStoresFunc = f
@@ -188,6 +202,11 @@ func (b *Builder) DefaultGenerateStoresFunc() ksmtypes.BuildStoresFunc {
188202
return b.buildStores
189203
}
190204

205+
// DefaultGenerateMetadataOnlyStoresFunc returns default buildStores function
206+
func (b *Builder) DefaultGenerateMetadataOnlyStoresFunc() ksmtypes.BuildMetadataOnlyStoresFunc {
207+
return b.buildMetadataOnlyStores
208+
}
209+
191210
// DefaultGenerateCustomResourceStoresFunc returns default buildCustomResourceStores function
192211
func (b *Builder) DefaultGenerateCustomResourceStoresFunc() ksmtypes.BuildCustomResourceStoresFunc {
193212
return b.buildCustomResourceStores
@@ -362,7 +381,7 @@ func availableResources() []string {
362381
}
363382

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

368387
func (b *Builder) buildCronJobStores() []cache.Store {
@@ -519,7 +538,8 @@ func (b *Builder) buildStores(
519538
if b.fieldSelectorFilter != "" {
520539
klog.InfoS("FieldSelector is used", "fieldSelector", b.fieldSelectorFilter)
521540
}
522-
listWatcher := listWatchFunc(b.kubeClient, v1.NamespaceAll, b.fieldSelectorFilter)
541+
kubeClient := b.kubeClient
542+
listWatcher := listWatchFunc(kubeClient, v1.NamespaceAll, b.fieldSelectorFilter)
523543
b.startReflector(expectedType, store, listWatcher, useAPIServerCache)
524544
return []cache.Store{store}
525545
}
@@ -541,6 +561,46 @@ func (b *Builder) buildStores(
541561
return stores
542562
}
543563

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

internal/store/configmap.go

+12-12
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

pkg/app/server.go

+7
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ func RunKubeStateMetrics(ctx context.Context, opts *options.Options) error {
266266

267267
storeBuilder.WithUsingAPIServerCache(opts.UseAPIServerCache)
268268
storeBuilder.WithGenerateStoresFunc(storeBuilder.DefaultGenerateStoresFunc())
269+
storeBuilder.WithGenerateMetadataOnlyStoresFunc(storeBuilder.DefaultGenerateMetadataOnlyStoresFunc())
269270
proc.StartReaper()
270271

271272
storeBuilder.WithUtilOptions(opts)
@@ -275,6 +276,12 @@ func RunKubeStateMetrics(ctx context.Context, opts *options.Options) error {
275276
}
276277
storeBuilder.WithKubeClient(kubeClient)
277278

279+
metadataOnlyKubeClient, err := util.CreateMetadataOnlyKubeClient(opts.Apiserver, opts.Kubeconfig)
280+
if err != nil {
281+
return fmt.Errorf("failed to create metadata-only client: %v", err)
282+
}
283+
storeBuilder.WithMetadataOnlyKubeClient(metadataOnlyKubeClient)
284+
278285
storeBuilder.WithSharding(opts.Shard, opts.TotalShards)
279286
if err := storeBuilder.WithAllowAnnotations(opts.AnnotationsAllowList); err != nil {
280287
return fmt.Errorf("failed to set up annotations allowlist: %v", err)

pkg/builder/builder.go

+6
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121

2222
"github.com/prometheus/client_golang/prometheus"
2323
clientset "k8s.io/client-go/kubernetes"
24+
"k8s.io/client-go/metadata"
2425
"k8s.io/client-go/tools/cache"
2526

2627
internalstore "k8s.io/kube-state-metrics/v2/internal/store"
@@ -84,6 +85,11 @@ func (b *Builder) WithKubeClient(c clientset.Interface) {
8485
b.internal.WithKubeClient(c)
8586
}
8687

88+
// WithMetadataOnlyKubeClient sets the metadataOnlyKubeClient property of a Builder.
89+
func (b *Builder) WithMetadataOnlyKubeClient(c metadata.Interface) {
90+
b.internal.WithMetadataOnlyKubeClient(c)
91+
}
92+
8793
// WithCustomResourceClients sets the customResourceClients property of a Builder.
8894
func (b *Builder) WithCustomResourceClients(cs map[string]interface{}) {
8995
b.internal.WithCustomResourceClients(cs)

pkg/builder/types/interfaces.go

+11
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323

2424
"github.com/prometheus/client_golang/prometheus"
2525
clientset "k8s.io/client-go/kubernetes"
26+
"k8s.io/client-go/metadata"
2627
"k8s.io/client-go/tools/cache"
2728

2829
"k8s.io/kube-state-metrics/v2/pkg/customresource"
@@ -38,6 +39,7 @@ type BuilderInterface interface {
3839
WithFieldSelectorFilter(fieldSelectors string)
3940
WithSharding(shard int32, totalShards int)
4041
WithContext(ctx context.Context)
42+
WithMetadataOnlyKubeClient(c metadata.Interface)
4143
WithKubeClient(c clientset.Interface)
4244
WithCustomResourceClients(cs map[string]interface{})
4345
WithUsingAPIServerCache(u bool)
@@ -46,6 +48,8 @@ type BuilderInterface interface {
4648
WithAllowLabels(l map[string][]string) error
4749
WithGenerateStoresFunc(f BuildStoresFunc)
4850
DefaultGenerateStoresFunc() BuildStoresFunc
51+
WithGenerateMetadataOnlyStoresFunc(f BuildMetadataOnlyStoresFunc)
52+
DefaultGenerateMetadataOnlyStoresFunc() BuildMetadataOnlyStoresFunc
4953
DefaultGenerateCustomResourceStoresFunc() BuildCustomResourceStoresFunc
5054
WithCustomResourceStoreFactories(fs ...customresource.RegistryFactory)
5155
Build() metricsstore.MetricsWriterList
@@ -60,6 +64,13 @@ type BuildStoresFunc func(metricFamilies []generator.FamilyGenerator,
6064
useAPIServerCache bool,
6165
) []cache.Store
6266

67+
// BuildMetadataOnlyStoresFunc function signature that is used to return a list of cache.Store
68+
type BuildMetadataOnlyStoresFunc func(metricFamilies []generator.FamilyGenerator,
69+
expectedType interface{},
70+
listWatchFunc func(kubeClient metadata.Interface, ns string, fieldSelector string) cache.ListerWatcher,
71+
useAPIServerCache bool,
72+
) []cache.Store
73+
6374
// BuildCustomResourceStoresFunc function signature that is used to return a list of custom resource cache.Store
6475
type BuildCustomResourceStoresFunc func(resourceName string,
6576
metricFamilies []generator.FamilyGenerator,

pkg/util/utils.go

+30
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"k8s.io/apimachinery/pkg/runtime/schema"
2626
"k8s.io/client-go/discovery"
2727
clientset "k8s.io/client-go/kubernetes"
28+
"k8s.io/client-go/metadata"
2829
"k8s.io/client-go/rest"
2930
"k8s.io/client-go/tools/clientcmd"
3031
"k8s.io/klog/v2"
@@ -38,6 +39,7 @@ import (
3839

3940
var config *rest.Config
4041
var currentKubeClient clientset.Interface
42+
var currentMetadataOnlyKubeClient metadata.Interface
4143
var currentDiscoveryClient *discovery.DiscoveryClient
4244

4345
// CreateKubeClient creates a Kubernetes clientset and a custom resource clientset.
@@ -79,6 +81,34 @@ func CreateKubeClient(apiserver string, kubeconfig string) (clientset.Interface,
7981
return kubeClient, nil
8082
}
8183

84+
// CreateMetadataOnlyKubeClient creates a Kubernetes clientset and a custom resource clientset.
85+
func CreateMetadataOnlyKubeClient(apiserver string, kubeconfig string) (metadata.Interface, error) {
86+
if currentMetadataOnlyKubeClient != nil {
87+
return currentMetadataOnlyKubeClient, nil
88+
}
89+
90+
var err error
91+
92+
if config == nil {
93+
var err error
94+
config, err = clientcmd.BuildConfigFromFlags(apiserver, kubeconfig)
95+
if err != nil {
96+
return nil, err
97+
}
98+
}
99+
config.UserAgent = fmt.Sprintf("%s/%s (%s/%s) kubernetes/%s", "kube-state-metrics (metadataonly)", version.Version, runtime.GOOS, runtime.GOARCH, version.Revision)
100+
config.AcceptContentTypes = "application/vnd.kubernetes.protobuf;as=PartialObjectMetadataList;g=meta.k8s.io;v=v1,application/json;as=PartialObjectMetadataList;g=meta.k8s.io;v=v1,application/json,application/vnd.kubernetes.protobuf;as=PartialObjectMetadata;g=meta.k8s.io;v=v1,application/json;as=PartialObjectMetadata;g=meta.k8s.io;v=v1"
101+
config.ContentType = "application/vnd.kubernetes.protobuf"
102+
103+
kubeClient, err := metadata.NewForConfig(config)
104+
if err != nil {
105+
return nil, err
106+
}
107+
108+
currentMetadataOnlyKubeClient = kubeClient
109+
return kubeClient, nil
110+
}
111+
82112
// CreateCustomResourceClients creates a custom resource clientset.
83113
func CreateCustomResourceClients(apiserver string, kubeconfig string, factories ...customresource.RegistryFactory) (map[string]interface{}, error) {
84114
// Not relying on memoized clients here because the factories are subject to change.

0 commit comments

Comments
 (0)