Skip to content

Commit 081cc3c

Browse files
authored
Merge pull request #1644 from Garrybest/pr_crd
Extend kube-state-metrics to support Custom Resource metrics
2 parents f629b25 + acd5e74 commit 081cc3c

File tree

9 files changed

+837
-290
lines changed

9 files changed

+837
-290
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ require (
2121
k8s.io/autoscaler/vertical-pod-autoscaler v0.9.2
2222
k8s.io/client-go v0.23.0
2323
k8s.io/klog/v2 v2.30.0
24+
k8s.io/sample-controller v0.23.0
2425
)
2526

2627
require (

go.sum

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,13 @@ github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34
148148
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
149149
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
150150
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
151+
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
151152
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
152153
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
153154
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
154155
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
155156
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
157+
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
156158
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
157159
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
158160
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -249,6 +251,7 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
249251
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
250252
github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q=
251253
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
254+
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
252255
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
253256
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
254257
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@@ -280,6 +283,7 @@ github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN
280283
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
281284
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
282285
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
286+
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
283287
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
284288
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
285289
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@@ -379,6 +383,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
379383
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
380384
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
381385
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
386+
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
382387
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
383388
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
384389
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
@@ -478,6 +483,7 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
478483
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
479484
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
480485
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
486+
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
481487
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
482488
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY=
483489
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@@ -565,6 +571,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
565571
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
566572
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
567573
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
574+
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
568575
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
569576
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0=
570577
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -641,6 +648,7 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f
641648
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
642649
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
643650
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
651+
golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM=
644652
golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w=
645653
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
646654
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -793,6 +801,7 @@ k8s.io/client-go v0.18.3/go.mod h1:4a/dpQEvzAhT1BbuWW09qvIaGw6Gbu1gZYiQZIi1DMw=
793801
k8s.io/client-go v0.23.0 h1:vcsOqyPq7XV3QmQRCBH/t9BICJM9Q1M18qahjv+rebY=
794802
k8s.io/client-go v0.23.0/go.mod h1:hrDnpnK1mSr65lHHcUuIZIXDgEbzc7/683c6hyG4jTA=
795803
k8s.io/code-generator v0.18.3/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c=
804+
k8s.io/code-generator v0.23.0/go.mod h1:vQvOhDXhuzqiVfM/YHp+dmg10WDZCchJVObc9MvowsE=
796805
k8s.io/component-base v0.18.3/go.mod h1:bp5GzGR0aGkYEfTj+eTY0AN/vXTgkJdQXjNTTVUaa3k=
797806
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
798807
k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
@@ -809,6 +818,8 @@ k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C
809818
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4=
810819
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
811820
k8s.io/metrics v0.18.3/go.mod h1:TkuJE3ezDZ1ym8pYkZoEzJB7HDiFE7qxl+EmExEBoPA=
821+
k8s.io/sample-controller v0.23.0 h1:Zwxi+BQxEQDg63jGzxrLUbWBp+Qkqse/web1nkpSG9g=
822+
k8s.io/sample-controller v0.23.0/go.mod h1:8a1Cgok9A5JRa1rJgg9AQKrOF0hqwbaHt/wcndZ6fmY=
812823
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
813824
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
814825
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b h1:wxEMGetGMur3J1xuGLQY7GEQYg9bZxKn3tKo5k/eYcs=

internal/store/builder.go

Lines changed: 99 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import (
4343
"k8s.io/klog/v2"
4444

4545
ksmtypes "k8s.io/kube-state-metrics/v2/pkg/builder/types"
46+
"k8s.io/kube-state-metrics/v2/pkg/customresource"
4647
generator "k8s.io/kube-state-metrics/v2/pkg/metric_generator"
4748
metricsstore "k8s.io/kube-state-metrics/v2/pkg/metrics_store"
4849
"k8s.io/kube-state-metrics/v2/pkg/options"
@@ -57,21 +58,23 @@ var _ ksmtypes.BuilderInterface = &Builder{}
5758
// Builder helps to build store. It follows the builder pattern
5859
// (https://en.wikipedia.org/wiki/Builder_pattern).
5960
type Builder struct {
60-
kubeClient clientset.Interface
61-
vpaClient vpaclientset.Interface
62-
namespaces options.NamespaceList
63-
namespaceFilter string
64-
ctx context.Context
65-
enabledResources []string
66-
familyGeneratorFilter generator.FamilyGeneratorFilter
67-
listWatchMetrics *watch.ListWatchMetrics
68-
shardingMetrics *sharding.Metrics
69-
shard int32
70-
totalShards int
71-
buildStoresFunc ksmtypes.BuildStoresFunc
72-
allowAnnotationsList map[string][]string
73-
allowLabelsList map[string][]string
74-
useAPIServerCache bool
61+
kubeClient clientset.Interface
62+
customResourceClients map[string]interface{}
63+
vpaClient vpaclientset.Interface
64+
namespaces options.NamespaceList
65+
namespaceFilter string
66+
ctx context.Context
67+
enabledResources []string
68+
familyGeneratorFilter generator.FamilyGeneratorFilter
69+
listWatchMetrics *watch.ListWatchMetrics
70+
shardingMetrics *sharding.Metrics
71+
shard int32
72+
totalShards int
73+
buildStoresFunc ksmtypes.BuildStoresFunc
74+
buildCustomResourceStoresFunc ksmtypes.BuildCustomResourceStoresFunc
75+
allowAnnotationsList map[string][]string
76+
allowLabelsList map[string][]string
77+
useAPIServerCache bool
7578
}
7679

7780
// NewBuilder returns a new builder.
@@ -134,23 +137,61 @@ func (b *Builder) WithVPAClient(c vpaclientset.Interface) {
134137
b.vpaClient = c
135138
}
136139

140+
// WithCustomResourceClients sets the customResourceClients property of a Builder.
141+
func (b *Builder) WithCustomResourceClients(cs map[string]interface{}) {
142+
b.customResourceClients = cs
143+
}
144+
145+
// WithUsingAPIServerCache configures whether using APIServer cache or not.
146+
func (b *Builder) WithUsingAPIServerCache(u bool) {
147+
b.useAPIServerCache = u
148+
}
149+
137150
// WithFamilyGeneratorFilter configures the family generator filter which decides which
138151
// metrics are to be exposed by the store build by the Builder.
139152
func (b *Builder) WithFamilyGeneratorFilter(l generator.FamilyGeneratorFilter) {
140153
b.familyGeneratorFilter = l
141154
}
142155

143156
// WithGenerateStoresFunc configures a custom generate store function
144-
func (b *Builder) WithGenerateStoresFunc(f ksmtypes.BuildStoresFunc, u bool) {
157+
func (b *Builder) WithGenerateStoresFunc(f ksmtypes.BuildStoresFunc) {
145158
b.buildStoresFunc = f
146-
b.useAPIServerCache = u
159+
}
160+
161+
// WithGenerateCustomResourceStoresFunc configures a custom generate custom resource store function
162+
func (b *Builder) WithGenerateCustomResourceStoresFunc(f ksmtypes.BuildCustomResourceStoresFunc) {
163+
b.buildCustomResourceStoresFunc = f
147164
}
148165

149166
// DefaultGenerateStoresFunc returns default buildStores function
150167
func (b *Builder) DefaultGenerateStoresFunc() ksmtypes.BuildStoresFunc {
151168
return b.buildStores
152169
}
153170

171+
// DefaultGenerateCustomResourceStoresFunc returns default buildCustomResourceStores function
172+
func (b *Builder) DefaultGenerateCustomResourceStoresFunc() ksmtypes.BuildCustomResourceStoresFunc {
173+
return b.buildCustomResourceStores
174+
}
175+
176+
// WithCustomResourceStoreFactories returns configures a custom resource stores factory
177+
func (b *Builder) WithCustomResourceStoreFactories(fs ...customresource.RegistryFactory) {
178+
for i := range fs {
179+
f := fs[i]
180+
if _, ok := availableStores[f.Name()]; ok {
181+
klog.Warningf("The internal resource store named %s already exists and is overridden by a custom resource store with the same name, please make sure it meets your expectation", f.Name())
182+
}
183+
availableStores[f.Name()] = func(b *Builder) []cache.Store {
184+
return b.buildCustomResourceStoresFunc(
185+
f.Name(),
186+
f.MetricFamilyGenerators(b.allowAnnotationsList[f.Name()], b.allowLabelsList[f.Name()]),
187+
f.ExpectedType(),
188+
f.ListWatch,
189+
b.useAPIServerCache,
190+
)
191+
}
192+
}
193+
}
194+
154195
// WithAllowAnnotations configures which annotations can be returned for metrics
155196
func (b *Builder) WithAllowAnnotations(annotations map[string][]string) {
156197
if len(annotations) > 0 {
@@ -414,6 +455,47 @@ func (b *Builder) buildStores(
414455
return stores
415456
}
416457

458+
// TODO(Garrybest): Merge `buildStores` and `buildCustomResourceStores`
459+
func (b *Builder) buildCustomResourceStores(resourceName string,
460+
metricFamilies []generator.FamilyGenerator,
461+
expectedType interface{},
462+
listWatchFunc func(customResourceClient interface{}, ns string, fieldSelector string) cache.ListerWatcher,
463+
useAPIServerCache bool,
464+
) []cache.Store {
465+
metricFamilies = generator.FilterFamilyGenerators(b.familyGeneratorFilter, metricFamilies)
466+
composedMetricGenFuncs := generator.ComposeMetricGenFuncs(metricFamilies)
467+
familyHeaders := generator.ExtractMetricFamilyHeaders(metricFamilies)
468+
469+
customResourceClient, ok := b.customResourceClients[resourceName]
470+
if !ok {
471+
klog.Warningf("Custom resource client %s does not exist", resourceName)
472+
return []cache.Store{}
473+
}
474+
475+
if b.namespaces.IsAllNamespaces() {
476+
store := metricsstore.NewMetricsStore(
477+
familyHeaders,
478+
composedMetricGenFuncs,
479+
)
480+
listWatcher := listWatchFunc(customResourceClient, v1.NamespaceAll, b.namespaceFilter)
481+
b.startReflector(expectedType, store, listWatcher, useAPIServerCache)
482+
return []cache.Store{store}
483+
}
484+
485+
stores := make([]cache.Store, 0, len(b.namespaces))
486+
for _, ns := range b.namespaces {
487+
store := metricsstore.NewMetricsStore(
488+
familyHeaders,
489+
composedMetricGenFuncs,
490+
)
491+
listWatcher := listWatchFunc(customResourceClient, ns, b.namespaceFilter)
492+
b.startReflector(expectedType, store, listWatcher, useAPIServerCache)
493+
stores = append(stores, store)
494+
}
495+
496+
return stores
497+
}
498+
417499
// startReflector starts a Kubernetes client-go reflector with the given
418500
// listWatcher and registers it with the given store.
419501
func (b *Builder) startReflector(

0 commit comments

Comments
 (0)