Skip to content

Commit 539f57d

Browse files
committed
simplified configuration
Signed-off-by: mickeyzzc <[email protected]>
1 parent f8b0cb7 commit 539f57d

File tree

5 files changed

+102
-49
lines changed

5 files changed

+102
-49
lines changed

examples/daemonsetsharding/deployment-no-node-pods.yaml

-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ spec:
2424
- args:
2525
- --resources=pods
2626
- --node=""
27-
- --enable-no-node-scrape
2827
image: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.10.0
2928
livenessProbe:
3029
httpGet:

pkg/app/server.go

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

205205
namespaces := opts.Namespaces.GetNamespaces()
206206
nsFieldSelector := namespaces.GetExcludeNSFieldSelector(opts.NamespacesDenylist)
207-
nodeFieldSelector := opts.Node.GetNodeFieldSelector(opts.NoNodeScrape)
207+
nodeFieldSelector := opts.Node.GetNodeFieldSelector()
208208
merged, err := storeBuilder.MergeFieldSelectors([]string{nsFieldSelector, nodeFieldSelector})
209209
if err != nil {
210210
return err

pkg/options/options.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ func NewOptions() *Options {
7474
MetricAllowlist: MetricSet{},
7575
MetricDenylist: MetricSet{},
7676
MetricOptInList: MetricSet{},
77+
Node: NodeType{},
7778
AnnotationsAllowList: LabelsAllowList{},
7879
LabelsAllowList: LabelsAllowList{},
7980
}
@@ -121,7 +122,6 @@ func (o *Options) AddFlags(cmd *cobra.Command) {
121122

122123
o.cmd.Flags().BoolVar(&o.CustomResourcesOnly, "custom-resource-state-only", false, "Only provide Custom Resource State metrics (experimental)")
123124
o.cmd.Flags().BoolVar(&o.EnableGZIPEncoding, "enable-gzip-encoding", false, "Gzip responses when requested by clients via 'Accept-Encoding: gzip' header.")
124-
o.cmd.Flags().BoolVar(&o.NoNodeScrape, "enable-no-node-scrape", false, "This configuration is used in conjunction with node configuration. When this configuration is true, node configuration is empty and the metric of no scheduled pods is scraped. This is experimental.")
125125
o.cmd.Flags().BoolVarP(&o.Help, "help", "h", false, "Print Help text")
126126
o.cmd.Flags().BoolVarP(&o.UseAPIServerCache, "use-apiserver-cache", "", false, "Sets resourceVersion=0 for ListWatch requests, using cached resources from the apiserver instead of an etcd quorum read.")
127127
o.cmd.Flags().Int32Var(&o.Shard, "shard", int32(0), "The instances shard nominal (zero indexed) within the total number of shards. (default 0)")
@@ -138,7 +138,7 @@ func (o *Options) AddFlags(cmd *cobra.Command) {
138138
o.cmd.Flags().StringVar(&o.TLSConfig, "tls-config", "", "Path to the TLS configuration file")
139139
o.cmd.Flags().StringVar(&o.TelemetryHost, "telemetry-host", "::", `Host to expose kube-state-metrics self metrics on.`)
140140
o.cmd.Flags().StringVar(&o.Config, "config", "", "Path to the kube-state-metrics options config file")
141-
o.cmd.Flags().StringVar((*string)(&o.Node), "node", "", "Name of the node that contains the kube-state-metrics pod. Most likely it should be passed via the downward API. This is used for daemonset sharding. Only available for resources (pod metrics) that support spec.nodeName fieldSelector. This is experimental.")
141+
o.cmd.Flags().Var(&o.Node, "node", "Name of the node that contains the kube-state-metrics pod. Most likely it should be passed via the downward API. This is used for daemonset sharding. Only available for resources (pod metrics) that support spec.nodeName fieldSelector. This is experimental.")
142142
o.cmd.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 annotations metrics are not exposed. To include them, 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=[*]').")
143143
o.cmd.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 labels metrics are not exposed. To include them, 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=[*]'.")
144144
o.cmd.Flags().Var(&o.MetricAllowlist, "metric-allowlist", "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.")
@@ -163,7 +163,7 @@ func (o *Options) Usage() {
163163
// Validate validates arguments
164164
func (o *Options) Validate() error {
165165
shardableResource := "pods"
166-
if o.Node == "" {
166+
if o.Node.String() == "" {
167167
return nil
168168
}
169169
for _, x := range o.Resources.AsSlice() {

pkg/options/types.go

+44-8
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package options
1818

1919
import (
2020
"errors"
21+
"regexp"
2122
"sort"
2223
"strings"
2324

@@ -105,17 +106,52 @@ func (r *ResourceSet) Type() string {
105106
}
106107

107108
// NodeType represents a nodeName to query from.
108-
type NodeType string
109+
type NodeType map[string]struct{}
109110

110-
// GetNodeFieldSelector returns a nodename field selector.
111-
func (n *NodeType) GetNodeFieldSelector(b bool) string {
112-
if string(*n) != "" {
113-
return fields.OneTermEqualSelector("spec.nodeName", string(*n)).String()
111+
func (n *NodeType) Set(value string) error {
112+
s := *n
113+
cols := strings.Split(value, ",")
114+
for _, col := range cols {
115+
col = strings.TrimSpace(col)
116+
if len(col) != 0 {
117+
s[col] = struct{}{}
118+
}
119+
}
120+
return nil
121+
}
122+
123+
func (n NodeType) AsSlice() []string {
124+
cols := make([]string, 0, len(n))
125+
for col := range n {
126+
cols = append(cols, col)
114127
}
115-
if b {
116-
return fields.OneTermEqualSelector("spec.nodeName", "").String()
128+
return cols
129+
}
130+
131+
func (n NodeType) String() string {
132+
return strings.Join(n.AsSlice(), ",")
133+
}
134+
135+
func (n *NodeType) Type() string {
136+
return "string"
137+
}
138+
139+
// GetNodeFieldSelector returns a nodename field selector.
140+
func (n *NodeType) GetNodeFieldSelector() string {
141+
if nil == n || len(*n) == 0 {
142+
klog.InfoS("Using node type is nil")
143+
return EmptyFieldSelector()
117144
}
118-
return EmptyFieldSelector()
145+
pattern := "[^a-zA-Z0-9_,-]+"
146+
re := regexp.MustCompile(pattern)
147+
result := re.ReplaceAllString(n.String(), "")
148+
klog.InfoS("Using node type", "node", result)
149+
return fields.OneTermEqualSelector("spec.nodeName", result).String()
150+
151+
}
152+
153+
type NodeValue interface {
154+
GetNodeFieldSelector() string
119155
}
120156

121157
// EmptyFieldSelector returns an empty field selector.

pkg/options/types_test.go

+54-36
Original file line numberDiff line numberDiff line change
@@ -162,38 +162,32 @@ func TestNodeFieldSelector(t *testing.T) {
162162
Wanted string
163163
}{
164164
{
165-
Desc: "empty node name",
166-
Node: "",
165+
Desc: "with node name",
167166
Wanted: "",
168167
},
169168
{
170-
Desc: "with node name",
171-
Node: "k8s-node-1",
169+
Desc: "empty node name",
170+
Node: NodeType(
171+
map[string]struct{}{
172+
"": {},
173+
},
174+
),
175+
Wanted: "spec.nodeName=",
176+
},
177+
{
178+
Desc: "with node name",
179+
Node: NodeType(
180+
map[string]struct{}{
181+
"k8s-node-1": {},
182+
},
183+
),
172184
Wanted: "spec.nodeName=k8s-node-1",
173185
},
174186
}
175187

176188
for _, test := range tests {
177189
node := test.Node
178-
actual := node.GetNodeFieldSelector(false)
179-
if !reflect.DeepEqual(actual, test.Wanted) {
180-
t.Errorf("Test error for Desc: %s. Want: %+v. Got: %+v.", test.Desc, test.Wanted, actual)
181-
}
182-
}
183-
tests1 := []struct {
184-
Desc string
185-
Node NodeType
186-
Wanted string
187-
}{
188-
{
189-
Desc: "empty node name",
190-
Node: "",
191-
Wanted: "spec.nodeName=",
192-
},
193-
}
194-
for _, test := range tests1 {
195-
node := test.Node
196-
actual := node.GetNodeFieldSelector(true)
190+
actual := node.GetNodeFieldSelector()
197191
if !reflect.DeepEqual(actual, test.Wanted) {
198192
t.Errorf("Test error for Desc: %s. Want: %+v. Got: %+v.", test.Desc, test.Wanted, actual)
199193
}
@@ -212,51 +206,75 @@ func TestMergeFieldSelectors(t *testing.T) {
212206
Desc: "empty DeniedNamespaces",
213207
Namespaces: NamespaceList{"default", "kube-system"},
214208
DeniedNamespaces: NamespaceList{},
215-
Node: "",
216-
Wanted: "",
209+
Node: NodeType(
210+
map[string]struct{}{
211+
"": {},
212+
},
213+
),
214+
Wanted: "spec.nodeName=",
217215
},
218216
{
219217
Desc: "all DeniedNamespaces",
220218
Namespaces: DefaultNamespaces,
221219
DeniedNamespaces: NamespaceList{"some-system"},
222-
Node: "",
223-
Wanted: "metadata.namespace!=some-system",
220+
Node: NodeType(
221+
map[string]struct{}{
222+
"": {},
223+
},
224+
),
225+
Wanted: "metadata.namespace!=some-system,spec.nodeName=",
224226
},
225227
{
226228
Desc: "general case",
227229
Namespaces: DefaultNamespaces,
228230
DeniedNamespaces: NamespaceList{"case1-system", "case2-system"},
229-
Node: "",
230-
Wanted: "metadata.namespace!=case1-system,metadata.namespace!=case2-system",
231+
Node: NodeType(
232+
map[string]struct{}{
233+
"": {},
234+
},
235+
),
236+
Wanted: "metadata.namespace!=case1-system,metadata.namespace!=case2-system,spec.nodeName=",
231237
},
232238
{
233239
Desc: "empty DeniedNamespaces",
234240
Namespaces: NamespaceList{"default", "kube-system"},
235241
DeniedNamespaces: NamespaceList{},
236-
Node: "k8s-node-1",
237-
Wanted: "spec.nodeName=k8s-node-1",
242+
Node: NodeType(
243+
map[string]struct{}{
244+
"k8s-node-1": {},
245+
},
246+
),
247+
Wanted: "spec.nodeName=k8s-node-1",
238248
},
239249
{
240250
Desc: "all DeniedNamespaces",
241251
Namespaces: DefaultNamespaces,
242252
DeniedNamespaces: NamespaceList{"some-system"},
243-
Node: "k8s-node-1",
244-
Wanted: "metadata.namespace!=some-system,spec.nodeName=k8s-node-1",
253+
Node: NodeType(
254+
map[string]struct{}{
255+
"k8s-node-1": {},
256+
},
257+
),
258+
Wanted: "metadata.namespace!=some-system,spec.nodeName=k8s-node-1",
245259
},
246260
{
247261
Desc: "general case",
248262
Namespaces: DefaultNamespaces,
249263
DeniedNamespaces: NamespaceList{"case1-system", "case2-system"},
250-
Node: "k8s-node-1",
251-
Wanted: "metadata.namespace!=case1-system,metadata.namespace!=case2-system,spec.nodeName=k8s-node-1",
264+
Node: NodeType(
265+
map[string]struct{}{
266+
"k8s-node-1": {},
267+
},
268+
),
269+
Wanted: "metadata.namespace!=case1-system,metadata.namespace!=case2-system,spec.nodeName=k8s-node-1",
252270
},
253271
}
254272

255273
for _, test := range tests {
256274
ns := test.Namespaces
257275
deniedNS := test.DeniedNamespaces
258276
selector1 := ns.GetExcludeNSFieldSelector(deniedNS)
259-
selector2 := test.Node.GetNodeFieldSelector(false)
277+
selector2 := test.Node.GetNodeFieldSelector()
260278
actual, err := MergeFieldSelectors([]string{selector1, selector2})
261279
if err != nil {
262280
t.Errorf("Test error for Desc: %s. Can't merge field selector %v.", test.Desc, err)

0 commit comments

Comments
 (0)