Skip to content

Commit d5bd2c8

Browse files
authored
Merge pull request #1823 from rexagod/1815
Support filtering label allowlist by "*"
2 parents d620e43 + d982bbc commit d5bd2c8

File tree

5 files changed

+135
-3
lines changed

5 files changed

+135
-3
lines changed

docs/cli-arguments.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ Usage of ./kube-state-metrics:
4242
--metric-allowlist string Comma-separated list of metrics to be exposed. This list comprises of exact metric names and/or regex patterns. The allowlist and denylist are mutually exclusive.
4343
--metric-annotations-allowlist string Comma-separated list of Kubernetes annotations keys that will be used in the resource' labels metric. By default the metric contains only name and namespace labels. To include additional annotations provide a list of resource names in their plural form and Kubernetes annotation keys you would like to allow for them (Example: '=namespaces=[kubernetes.io/team,...],pods=[kubernetes.io/team],...)'. A single '*' can be provided per resource instead to allow any annotations, but that has severe performance implications (Example: '=pods=[*]').
4444
--metric-denylist string Comma-separated list of metrics not to be enabled. This list comprises of exact metric names and/or regex patterns. The allowlist and denylist are mutually exclusive.
45-
--metric-labels-allowlist string Comma-separated list of additional Kubernetes label keys that will be used in the resource' labels metric. By default the metric contains only name and namespace labels. To include additional labels provide a list of resource names in their plural form and Kubernetes label keys you would like to allow for them (Example: '=namespaces=[k8s-label-1,k8s-label-n,...],pods=[app],...)'. A single '*' can be provided per resource instead to allow any labels, but that has severe performance implications (Example: '=pods=[*]').
45+
--metric-labels-allowlist string Comma-separated list of additional Kubernetes label keys that will be used in the resource' labels metric. By default the metric contains only name and namespace labels. To include additional labels provide a list of resource names in their plural form and Kubernetes label keys you would like to allow for them (Example: '=namespaces=[k8s-label-1,k8s-label-n,...],pods=[app],...)'. A single '*' can be provided per resource instead to allow any labels, but that has severe performance implications (Example: '=pods=[*]'). Additionally, an asterisk (*) can be provided as a key, which will resolve to all resources, i.e., assuming '--resources=deployments,pods', '=*=[*]' will resolve to '=deployments=[*],pods=[*]'.
4646
--metric-opt-in-list string Comma-separated list of metrics which are opt-in and not enabled by default. This is in addition to the metric allow- and denylists
4747
--namespaces string Comma-separated list of namespaces to be enabled. Defaults to ""
4848
--namespaces-denylist string Comma-separated list of namespaces not to be enabled. If namespaces and namespaces-denylist are both set, only namespaces that are excluded in namespaces-denylist will be used.

internal/store/builder.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,11 +213,19 @@ func (b *Builder) WithAllowAnnotations(annotations map[string][]string) {
213213
func (b *Builder) WithAllowLabels(labels map[string][]string) error {
214214
if len(labels) > 0 {
215215
for label := range labels {
216-
if !resourceExists(label) {
216+
if !resourceExists(label) && label != "*" {
217217
return fmt.Errorf("resource %s does not exist. Available resources: %s", label, strings.Join(availableResources(), ","))
218218
}
219219
}
220220
b.allowLabelsList = labels
221+
// "*" takes precedence over other specifications
222+
if allowedLabels, ok := labels["*"]; ok {
223+
m := make(map[string][]string)
224+
for _, resource := range b.enabledResources {
225+
m[resource] = allowedLabels
226+
}
227+
b.allowLabelsList = m
228+
}
221229
}
222230
return nil
223231
}

internal/store/builder_test.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
Copyright 2022 The Kubernetes Authors All rights reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package store
18+
19+
import (
20+
"reflect"
21+
"testing"
22+
23+
"k8s.io/kube-state-metrics/v2/pkg/options"
24+
)
25+
26+
type LabelsAllowList options.LabelsAllowList
27+
28+
type expectedError struct {
29+
expectedResourceError bool
30+
expectedLabelError bool
31+
expectedNotEqual bool
32+
}
33+
34+
func TestWithAllowLabels(t *testing.T) {
35+
tests := []struct {
36+
Desc string
37+
LabelsAllowlist map[string][]string
38+
EnabledResources []string
39+
Wanted LabelsAllowList
40+
err expectedError
41+
}{
42+
{
43+
Desc: "wildcard key-value as the only element",
44+
LabelsAllowlist: map[string][]string{"*": {"*"}},
45+
EnabledResources: []string{"cronjobs", "pods", "deployments"},
46+
Wanted: LabelsAllowList(map[string][]string{
47+
"deployments": {"*"},
48+
"pods": {"*"},
49+
"cronjobs": {"*"},
50+
}),
51+
},
52+
{
53+
Desc: "wildcard key-value as not the only element",
54+
LabelsAllowlist: map[string][]string{"*": {"*"}, "pods": {"*"}, "cronjobs": {"*"}},
55+
EnabledResources: []string{"cronjobs", "pods", "deployments"},
56+
Wanted: LabelsAllowList(map[string][]string{
57+
"deployments": {"*"},
58+
"pods": {"*"},
59+
"cronjobs": {"*"},
60+
}),
61+
},
62+
{
63+
Desc: "wildcard key-value as not the only element, with resource mismatch",
64+
LabelsAllowlist: map[string][]string{"*": {"*"}, "pods": {"*"}, "cronjobs": {"*"}, "configmaps": {"*"}},
65+
EnabledResources: []string{"cronjobs", "pods", "deployments"},
66+
Wanted: LabelsAllowList{},
67+
err: expectedError{
68+
expectedNotEqual: true,
69+
},
70+
},
71+
{
72+
Desc: "wildcard key-value as not the only element, with other mutually-exclusive keys",
73+
LabelsAllowlist: map[string][]string{"*": {"*"}, "foo": {"*"}, "bar": {"*"}, "cronjobs": {"*"}},
74+
EnabledResources: []string{"cronjobs", "pods", "deployments"},
75+
Wanted: LabelsAllowList(nil),
76+
err: expectedError{
77+
expectedLabelError: true,
78+
},
79+
},
80+
{
81+
Desc: "wildcard key-value as not the only element, with other resources that do not exist",
82+
LabelsAllowlist: map[string][]string{"*": {"*"}, "cronjobs": {"*"}},
83+
EnabledResources: []string{"cronjobs", "pods", "deployments", "foo", "bar"},
84+
Wanted: LabelsAllowList{},
85+
err: expectedError{
86+
expectedResourceError: true,
87+
},
88+
},
89+
}
90+
91+
for _, test := range tests {
92+
b := NewBuilder()
93+
94+
// Set the enabled resources.
95+
err := b.WithEnabledResources(test.EnabledResources)
96+
if err != nil && !test.err.expectedResourceError {
97+
t.Log("Did not expect error while setting resources (--resources).")
98+
t.Errorf("Test error for Desc: %s. Got Error: %v", test.Desc, err)
99+
}
100+
101+
// Resolve the allow list.
102+
err = b.WithAllowLabels(test.LabelsAllowlist)
103+
if err != nil && !test.err.expectedLabelError {
104+
t.Log("Did not expect error while parsing allow list labels (--metric-labels-allowlist).")
105+
t.Errorf("Test error for Desc: %s. Got Error: %v", test.Desc, err)
106+
}
107+
resolvedAllowLabels := LabelsAllowList(b.allowLabelsList)
108+
109+
// Evaluate.
110+
if !reflect.DeepEqual(resolvedAllowLabels, test.Wanted) && !test.err.expectedNotEqual {
111+
t.Log("Expected maps to be equal.")
112+
t.Errorf("Test error for Desc: %s\n Want: \n%+v\n Got: \n%#+v", test.Desc, test.Wanted, resolvedAllowLabels)
113+
}
114+
}
115+
}

pkg/options/options.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ func (o *Options) AddFlags() {
108108
o.flags.Var(&o.MetricDenylist, "metric-denylist", "Comma-separated list of metrics not to be enabled. This list comprises of exact metric names and/or regex patterns. The allowlist and denylist are mutually exclusive.")
109109
o.flags.Var(&o.MetricOptInList, "metric-opt-in-list", "Comma-separated list of metrics which are opt-in and not enabled by default. This is in addition to the metric allow- and denylists")
110110
o.flags.Var(&o.AnnotationsAllowList, "metric-annotations-allowlist", "Comma-separated list of Kubernetes annotations keys that will be used in the resource' labels metric. By default the metric contains only name and namespace labels. To include additional annotations provide a list of resource names in their plural form and Kubernetes annotation keys you would like to allow for them (Example: '=namespaces=[kubernetes.io/team,...],pods=[kubernetes.io/team],...)'. A single '*' can be provided per resource instead to allow any annotations, but that has severe performance implications (Example: '=pods=[*]').")
111-
o.flags.Var(&o.LabelsAllowList, "metric-labels-allowlist", "Comma-separated list of additional Kubernetes label keys that will be used in the resource' labels metric. By default the metric contains only name and namespace labels. To include additional labels provide a list of resource names in their plural form and Kubernetes label keys you would like to allow for them (Example: '=namespaces=[k8s-label-1,k8s-label-n,...],pods=[app],...)'. A single '*' can be provided per resource instead to allow any labels, but that has severe performance implications (Example: '=pods=[*]').")
111+
o.flags.Var(&o.LabelsAllowList, "metric-labels-allowlist", "Comma-separated list of additional Kubernetes label keys that will be used in the resource' labels metric. By default the metric contains only name and namespace labels. To include additional labels provide a list of resource names in their plural form and Kubernetes label keys you would like to allow for them (Example: '=namespaces=[k8s-label-1,k8s-label-n,...],pods=[app],...)'. A single '*' can be provided per resource instead to allow any labels, but that has severe performance implications (Example: '=pods=[*]'). Additionally, an asterisk (*) can be provided as a key, which will resolve to all resources, i.e., assuming '--resources=deployments,pods', '=*=[*]' will resolve to '=deployments=[*],pods=[*]'.")
112112
o.flags.Int32Var(&o.Shard, "shard", int32(0), "The instances shard nominal (zero indexed) within the total number of shards. (default 0)")
113113
o.flags.IntVar(&o.TotalShards, "total-shards", 1, "The total number of shards. Sharding is disabled when total shards is set to 1.")
114114

pkg/options/types_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,15 @@ func TestLabelsAllowListSet(t *testing.T) {
373373
"bar",
374374
"*"}}),
375375
},
376+
{
377+
Desc: "with key as wildcard",
378+
Value: "*=[*]",
379+
Wanted: LabelsAllowList(map[string][]string{
380+
"*": {
381+
"*",
382+
},
383+
}),
384+
},
376385
}
377386

378387
for _, test := range tests {

0 commit comments

Comments
 (0)