Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions cmd/nfd-master/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ func main() {
args.Overrides.DenyLabelNs = overrides.DenyLabelNs
case "label-whitelist":
args.Overrides.LabelWhiteList = overrides.LabelWhiteList
case "feature-allowlist":
args.Overrides.FeatureAllowList = overrides.FeatureAllowList
case "feature-denylist":
args.Overrides.FeatureDenyList = overrides.FeatureDenyList
case "enable-taints":
args.Overrides.EnableTaints = overrides.EnableTaints
case "no-publish":
Expand Down Expand Up @@ -121,16 +125,22 @@ func initFlags(flagset *flag.FlagSet) (*master.Args, *master.ConfigOverrideArgs)
args.Klog = klogutils.InitKlogFlags(flagset)

overrides := &master.ConfigOverrideArgs{
LabelWhiteList: &utils.RegexpVal{},
DenyLabelNs: &utils.StringSetVal{},
ExtraLabelNs: &utils.StringSetVal{},
ResyncPeriod: &utils.DurationVal{Duration: time.Duration(1) * time.Hour},
LabelWhiteList: &utils.RegexpVal{},
FeatureAlowList: &utils.RegexpVal{},
Copy link
Preview

Copilot AI Sep 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in field name: 'FeatureAlowList' should be 'FeatureAllowList' (missing 'l').

Suggested change
FeatureAlowList: &utils.RegexpVal{},
FeatureAllowList: &utils.RegexpVal{},

Copilot uses AI. Check for mistakes.

FeatureDenyList: &utils.RegexpVal{},
DenyLabelNs: &utils.StringSetVal{},
ExtraLabelNs: &utils.StringSetVal{},
ResyncPeriod: &utils.DurationVal{Duration: time.Duration(1) * time.Hour},
}
flagset.Var(overrides.ExtraLabelNs, "extra-label-ns",
"Comma separated list of allowed extra label namespaces")
flagset.Var(overrides.LabelWhiteList, "label-whitelist",
"Regular expression to filter label names to publish to the Kubernetes API server. "+
"NB: the label namespace is omitted i.e. the filter is only applied to the name part after '/'.")
flagset.Var(overrides.FeatureAllowList, "feature-allowlist",
"Regular expression to filter feature names to publish to the Kubernetes API server")
flagset.Var(overrides.FeatureDenyList, "feature-denylist",
"Regular expression to filter out feature names")
Comment on lines +142 to +143
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need something more structured than plain regexp. I'd suggest to drop the command line flags and make this a config-file only option.

overrides.EnableTaints = flagset.Bool("enable-taints", false,
"Enable node tainting feature")
overrides.NoPublish = flagset.Bool("no-publish", false,
Expand Down
53 changes: 36 additions & 17 deletions pkg/nfd-worker/nfd-worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,16 @@ type NFDConfig struct {
}

type coreConfig struct {
Klog klogutils.KlogConfigOpts
LabelWhiteList utils.RegexpVal
NoPublish bool
NoOwnerRefs bool
FeatureSources []string
Sources *[]string
LabelSources []string
SleepInterval utils.DurationVal
Klog klogutils.KlogConfigOpts
LabelWhiteList utils.RegexpVal
FeatureAllowList utils.RegexpVal
FeatureDenyList utils.RegexpVal
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need something more structured. One idea could be to follow something we have in NodeFeatureRules. We have stuff organized in hierarchy like <source>.<feature>.<element>. So following the NodeFeatureRule model we could have

featureDenyList:
  - feature: "kernel.config"

and then more refined configuration

featureDenyList:
  - feature: "pci.device"
    class: {op: In, value: ["0880"]}

NoPublish bool
NoOwnerRefs bool
FeatureSources []string
Sources *[]string
LabelSources []string
SleepInterval utils.DurationVal
}

type sourcesConfig map[string]source.Config
Expand Down Expand Up @@ -196,11 +198,13 @@ func NewNfdWorker(opts ...NfdWorkerOption) (NfdWorker, error) {
func newDefaultConfig() *NFDConfig {
return &NFDConfig{
Core: coreConfig{
LabelWhiteList: utils.RegexpVal{Regexp: *regexp.MustCompile("")},
SleepInterval: utils.DurationVal{Duration: 60 * time.Second},
FeatureSources: []string{"all"},
LabelSources: []string{"all"},
Klog: make(map[string]string),
LabelWhiteList: utils.RegexpVal{Regexp: *regexp.MustCompile("")},
FeatureAllowList: utils.RegexpVal{Regexp: *regexp.MustCompile("")},
FeatureDenyList: utils.RegexpVal{Regexp: *regexp.MustCompile("")},
SleepInterval: utils.DurationVal{Duration: 60 * time.Second},
FeatureSources: []string{"all"},
LabelSources: []string{"all"},
Klog: make(map[string]string),
},
}
}
Expand Down Expand Up @@ -238,7 +242,7 @@ func (w *nfdWorker) runFeatureDiscovery() error {
klog.InfoS("feature discovery sources took over half of sleep interval ", "duration", discoveryDuration, "sleepInterval", w.config.Core.SleepInterval.Duration)
}
// Get the set of feature labels.
labels := createFeatureLabels(w.labelSources, w.config.Core.LabelWhiteList.Regexp)
labels := createFeatureLabels(w.labelSources, w.config.Core.LabelWhiteList.Regexp, w.config.Core.FeatureAllowList.Regexp, w.config.Core.FeatureDenyList.Regexp)

// Update the node with the feature labels.
if !w.config.Core.NoPublish {
Expand Down Expand Up @@ -531,13 +535,13 @@ func (w *nfdWorker) configure(filepath string, overrides string) error {

// createFeatureLabels returns the set of feature labels from the enabled
// sources and the whitelist argument.
func createFeatureLabels(sources []source.LabelSource, labelWhiteList regexp.Regexp) (labels Labels) {
func createFeatureLabels(sources []source.LabelSource, labelWhiteList regexp.Regexp, featureAllowList regexp.Regexp, featureDenyList regexp.Regexp) (labels Labels) {
labels = Labels{}

// Get labels from all enabled label sources
klog.InfoS("starting feature discovery...")
for _, source := range sources {
labelsFromSource, err := GetFeatureLabels(source, labelWhiteList)
labelsFromSource, err := GetFeatureLabels(source, labelWhiteList, featureAllowList, featureDenyList)
if err != nil {
klog.ErrorS(err, "discovery failed", "source", source.Name())
continue
Expand All @@ -555,7 +559,7 @@ func createFeatureLabels(sources []source.LabelSource, labelWhiteList regexp.Reg

// getFeatureLabels returns node labels for features discovered by the
// supplied source.
func GetFeatureLabels(source source.LabelSource, labelWhiteList regexp.Regexp) (labels Labels, err error) {
func GetFeatureLabels(source source.LabelSource, labelWhiteList regexp.Regexp, featureAllowList regexp.Regexp, featureDenyList regexp.Regexp) (labels Labels, err error) {
labels = Labels{}
features, err := source.GetLabels()
if err != nil {
Expand All @@ -564,6 +568,21 @@ func GetFeatureLabels(source source.LabelSource, labelWhiteList regexp.Regexp) (

for k, v := range features {
name := k

allowed := featureAllowList.MatchString(name)
if !allowed {
klog.InfoS("feature does not match the allowlist", "feature", name, "regexp", featureAllowList.String())
Copy link
Preview

Copilot AI Sep 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logging when a feature doesn't match the allowlist will generate excessive log entries for every filtered feature. Consider only logging at debug level or when verbose logging is enabled to avoid log spam.

Suggested change
klog.InfoS("feature does not match the allowlist", "feature", name, "regexp", featureAllowList.String())
klog.V(1).InfoS("feature does not match the allowlist", "feature", name, "regexp", featureAllowList.String())

Copilot uses AI. Check for mistakes.

}

denied := featureDenyList.MatchString(name)
if denied {
klog.InfoS("feature matches the denylist", "feature", name, "regexp", featureDenyList.String())
}

if !(!denied && allowed) {
Copy link
Preview

Copilot AI Sep 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic condition !(!denied && allowed) is unnecessarily complex and hard to read. It should be simplified to denied || !allowed using De Morgan's law for better clarity.

Suggested change
if !(!denied && allowed) {
if denied || !allowed {

Copilot uses AI. Check for mistakes.

continue
}

switch sourceName := source.Name(); sourceName {
case "local", "custom":
// No mangling of labels from the custom rules or feature files
Expand Down