@@ -38,9 +38,22 @@ const Name = "local"
38
38
// LabelFeature of this feature source
39
39
const LabelFeature = "label"
40
40
41
- // ExpiryTimeKey is the key of this feature source indicating
42
- // when features should be removed.
43
- const ExpiryTimeKey = "expiry-time"
41
+ // RawFeature of this feature source
42
+ const RawFeature = "feature"
43
+
44
+ const (
45
+ // ExpiryTimeKey is the key of this feature source indicating
46
+ // when features should be removed.
47
+ DirectiveExpiryTime = "expiry-time"
48
+
49
+ // NoLabel indicates whether the feature should be included
50
+ // in exposed labels or not.
51
+ DirectiveNoLabel = "no-label"
52
+
53
+ // NoFeature indicates whether the feature should be included
54
+ // in exposed raw features or not.
55
+ DirectiveNoFeature = "no-feature"
56
+ )
44
57
45
58
// DirectivePrefix defines the prefix of directives that should be parsed
46
59
const DirectivePrefix = "# +"
@@ -66,7 +79,9 @@ type Config struct {
66
79
67
80
// parsingOpts contains options used for directives parsing
68
81
type parsingOpts struct {
69
- ExpiryTime time.Time
82
+ ExpiryTime time.Time
83
+ SkipLabel bool
84
+ SkipFeature bool
70
85
}
71
86
72
87
// Singleton source instance
@@ -121,7 +136,7 @@ func newDefaultConfig() *Config {
121
136
func (s * localSource ) Discover () error {
122
137
s .features = nfdv1alpha1 .NewFeatures ()
123
138
124
- featuresFromFiles , err := getFeaturesFromFiles ()
139
+ featuresFromFiles , labelsFromFiles , err := getFeaturesFromFiles ()
125
140
if err != nil {
126
141
klog .ErrorS (err , "failed to read feature files" )
127
142
}
@@ -131,21 +146,30 @@ func (s *localSource) Discover() error {
131
146
klog .InfoS ("starting hooks..." )
132
147
klog .InfoS ("NOTE: hooks are deprecated and will be completely removed in a future release." )
133
148
134
- featuresFromHooks , err := getFeaturesFromHooks ()
149
+ featuresFromHooks , labelsFromHooks , err := getFeaturesFromHooks ()
135
150
if err != nil {
136
151
klog .ErrorS (err , "failed to run hooks" )
137
152
}
138
153
139
154
// Merge features from hooks and files
140
155
for k , v := range featuresFromHooks {
141
156
if old , ok := featuresFromFiles [k ]; ok {
142
- klog .InfoS ("overriding label value" , "labelKey " , k , "oldValue" , old , "newValue" , v )
157
+ klog .InfoS ("overriding feature value" , "featureKey " , k , "oldValue" , old , "newValue" , v )
143
158
}
144
159
featuresFromFiles [k ] = v
145
160
}
161
+
162
+ // Merge labels from hooks and files
163
+ for k , v := range labelsFromHooks {
164
+ if old , ok := labelsFromFiles [k ]; ok {
165
+ klog .InfoS ("overriding label value" , "labelKey" , k , "oldValue" , old , "newValue" , v )
166
+ }
167
+ labelsFromHooks [k ] = v
168
+ }
146
169
}
147
170
148
- s .features .Attributes [LabelFeature ] = nfdv1alpha1 .NewAttributeFeatures (featuresFromFiles )
171
+ s .features .Attributes [LabelFeature ] = nfdv1alpha1 .NewAttributeFeatures (labelsFromFiles )
172
+ s .features .Attributes [RawFeature ] = nfdv1alpha1 .NewAttributeFeatures (featuresFromFiles )
149
173
150
174
klog .V (3 ).InfoS ("discovered features" , "featureSource" , s .Name (), "features" , utils .DelayedDumper (s .features ))
151
175
@@ -169,30 +193,37 @@ func parseDirectives(line string, opts *parsingOpts) error {
169
193
split := strings .SplitN (directive , "=" , 2 )
170
194
key := split [0 ]
171
195
172
- if len (split ) == 1 {
173
- return fmt .Errorf ("invalid directive format in %q, should be '# +key=value'" , line )
174
- }
175
- value := split [1 ]
176
-
177
196
switch key {
178
- case ExpiryTimeKey :
197
+ case DirectiveExpiryTime :
198
+ if len (split ) == 1 {
199
+ return fmt .Errorf ("invalid directive format in %q, should be '# +expiry-time=value'" , line )
200
+ }
201
+ value := split [1 ]
179
202
expiryDate , err := time .Parse (time .RFC3339 , strings .TrimSpace (value ))
180
203
if err != nil {
181
204
return fmt .Errorf ("failed to parse expiry-date directive: %w" , err )
182
205
}
183
206
opts .ExpiryTime = expiryDate
207
+ case DirectiveNoFeature :
208
+ opts .SkipFeature = true
209
+ case DirectiveNoLabel :
210
+ opts .SkipLabel = true
184
211
default :
185
212
return fmt .Errorf ("unknown feature file directive %q" , key )
186
213
}
187
214
188
215
return nil
189
216
}
190
217
191
- func parseFeatures (lines [][]byte , fileName string ) map [string ]string {
218
+ func parseFeatureFile (lines [][]byte , fileName string ) ( map [string ]string , map [ string ] string ) {
192
219
features := make (map [string ]string )
220
+ labels := make (map [string ]string )
221
+
193
222
now := time .Now ()
194
223
parsingOpts := & parsingOpts {
195
- ExpiryTime : now ,
224
+ ExpiryTime : now ,
225
+ SkipLabel : false ,
226
+ SkipFeature : false ,
196
227
}
197
228
198
229
for _ , l := range lines {
@@ -217,30 +248,50 @@ func parseFeatures(lines [][]byte, fileName string) map[string]string {
217
248
218
249
key := lineSplit [0 ]
219
250
220
- // Check if it's a boolean value
221
- if len (lineSplit ) == 1 {
222
- features [key ] = "true"
251
+ if ! parsingOpts .SkipFeature {
252
+ updateFeatures (features , lineSplit )
253
+ } else {
254
+ delete (features , key )
255
+ }
256
+
257
+ if ! parsingOpts .SkipLabel {
258
+ updateFeatures (labels , lineSplit )
223
259
} else {
224
- features [ key ] = lineSplit [ 1 ]
260
+ delete ( labels , key )
225
261
}
262
+ // SkipFeature and SkipLabel only take effect for one feature
263
+ parsingOpts .SkipFeature = false
264
+ parsingOpts .SkipLabel = false
226
265
}
227
266
}
228
267
229
- return features
268
+ return features , labels
269
+ }
270
+
271
+ func updateFeatures (m map [string ]string , lineSplit []string ) {
272
+ key := lineSplit [0 ]
273
+ // Check if it's a boolean value
274
+ if len (lineSplit ) == 1 {
275
+ m [key ] = "true"
276
+
277
+ } else {
278
+ m [key ] = lineSplit [1 ]
279
+ }
230
280
}
231
281
232
282
// Run all hooks and get features
233
- func getFeaturesFromHooks () (map [string ]string , error ) {
283
+ func getFeaturesFromHooks () (map [string ]string , map [ string ] string , error ) {
234
284
235
285
features := make (map [string ]string )
286
+ labels := make (map [string ]string )
236
287
237
288
files , err := os .ReadDir (hookDir )
238
289
if err != nil {
239
290
if os .IsNotExist (err ) {
240
291
klog .InfoS ("hook directory does not exist" , "path" , hookDir )
241
- return features , nil
292
+ return features , labels , nil
242
293
}
243
- return features , fmt .Errorf ("unable to access %v: %v" , hookDir , err )
294
+ return features , labels , fmt .Errorf ("unable to access %v: %v" , hookDir , err )
244
295
}
245
296
if len (files ) > 0 {
246
297
klog .InfoS ("hooks are DEPRECATED since v0.12.0 and support will be removed in a future release; use feature files instead" )
@@ -259,17 +310,24 @@ func getFeaturesFromHooks() (map[string]string, error) {
259
310
}
260
311
261
312
// Append features
262
- fileFeatures := parseFeatures (lines , fileName )
263
- klog .V (4 ).InfoS ("hook executed" , "fileName" , fileName , "features" , utils .DelayedDumper (fileFeatures ))
313
+ fileFeatures , fileLabels := parseFeatureFile (lines , fileName )
314
+ klog .V (4 ).InfoS ("hook executed" , "fileName" , fileName , "features" , utils .DelayedDumper (fileFeatures ), "labels" , utils . DelayedDumper ( fileLabels ) )
264
315
for k , v := range fileFeatures {
265
316
if old , ok := features [k ]; ok {
266
- klog .InfoS ("overriding label value from another hook" , "labelKey " , k , "oldValue" , old , "newValue" , v , "fileName" , fileName )
317
+ klog .InfoS ("overriding feature value from another hook" , "featureKey " , k , "oldValue" , old , "newValue" , v , "fileName" , fileName )
267
318
}
268
319
features [k ] = v
269
320
}
321
+
322
+ for k , v := range fileLabels {
323
+ if old , ok := labels [k ]; ok {
324
+ klog .InfoS ("overriding label value from another hook" , "labelKey" , k , "oldValue" , old , "newValue" , v , "fileName" , fileName )
325
+ }
326
+ labels [k ] = v
327
+ }
270
328
}
271
329
272
- return features , nil
330
+ return features , labels , nil
273
331
}
274
332
275
333
// Run one hook
@@ -314,16 +372,17 @@ func runHook(file string) ([][]byte, error) {
314
372
}
315
373
316
374
// Read all files to get features
317
- func getFeaturesFromFiles () (map [string ]string , error ) {
375
+ func getFeaturesFromFiles () (map [string ]string , map [ string ] string , error ) {
318
376
features := make (map [string ]string )
377
+ labels := make (map [string ]string )
319
378
320
379
files , err := os .ReadDir (featureFilesDir )
321
380
if err != nil {
322
381
if os .IsNotExist (err ) {
323
382
klog .InfoS ("features directory does not exist" , "path" , featureFilesDir )
324
- return features , nil
383
+ return features , labels , nil
325
384
}
326
- return features , fmt .Errorf ("unable to access %v: %v" , featureFilesDir , err )
385
+ return features , labels , fmt .Errorf ("unable to access %v: %v" , featureFilesDir , err )
327
386
}
328
387
329
388
for _ , file := range files {
@@ -339,18 +398,25 @@ func getFeaturesFromFiles() (map[string]string, error) {
339
398
}
340
399
341
400
// Append features
342
- fileFeatures := parseFeatures (lines , fileName )
401
+ fileFeatures , fileLabels := parseFeatureFile (lines , fileName )
343
402
344
403
klog .V (4 ).InfoS ("feature file read" , "fileName" , fileName , "features" , utils .DelayedDumper (fileFeatures ))
345
404
for k , v := range fileFeatures {
346
405
if old , ok := features [k ]; ok {
347
- klog .InfoS ("overriding label value from another feature file" , "labelKey " , k , "oldValue" , old , "newValue" , v , "fileName" , fileName )
406
+ klog .InfoS ("overriding label value from another feature file" , "featureKey " , k , "oldValue" , old , "newValue" , v , "fileName" , fileName )
348
407
}
349
408
features [k ] = v
350
409
}
410
+
411
+ for k , v := range fileLabels {
412
+ if old , ok := labels [k ]; ok {
413
+ klog .InfoS ("overriding label value from another feature file" , "labelKey" , k , "oldValue" , old , "newValue" , v , "fileName" , fileName )
414
+ }
415
+ labels [k ] = v
416
+ }
351
417
}
352
418
353
- return features , nil
419
+ return features , labels , nil
354
420
}
355
421
356
422
// Read one file
0 commit comments