1
0
Fork 0
mirror of https://github.com/kubernetes-sigs/node-feature-discovery.git synced 2024-12-15 17:50:49 +00:00

source/custom: use internal api for config parsing

Change the custom feature source of nfd-worker to use the newly added
internal config API for its own configuration. It now uses the internal
types for json/yaml unmarshalling but converts them to external
nfdv1alpha1 API to do the actual rule matching as the internal API does
not duplicate that functionality.
This commit is contained in:
Markus Lehtonen 2023-11-30 10:47:03 +02:00
parent 185b406ee7
commit a8092927fc
3 changed files with 61 additions and 45 deletions

View file

@ -18,22 +18,21 @@ package custom
import ( import (
"fmt" "fmt"
"os"
"k8s.io/klog/v2" "k8s.io/klog/v2"
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1" nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
"sigs.k8s.io/node-feature-discovery/pkg/utils" "sigs.k8s.io/node-feature-discovery/pkg/utils"
"sigs.k8s.io/node-feature-discovery/source" "sigs.k8s.io/node-feature-discovery/source"
api "sigs.k8s.io/node-feature-discovery/source/custom/api"
) )
// Name of this feature source // Name of this feature source
const Name = "custom" const Name = "custom"
type CustomRule struct { // The config files use the internal API type.
nfdv1alpha1.Rule type config []api.Rule
}
type config []CustomRule
// newDefaultConfig returns a new config with pre-populated defaults // newDefaultConfig returns a new config with pre-populated defaults
func newDefaultConfig() *config { func newDefaultConfig() *config {
@ -43,11 +42,17 @@ func newDefaultConfig() *config {
// customSource implements the LabelSource and ConfigurableSource interfaces. // customSource implements the LabelSource and ConfigurableSource interfaces.
type customSource struct { type customSource struct {
config *config config *config
// The rules are stored in the NFD API format that is a superset of our
// internal API and provides the functions for rule matching.
rules []nfdv1alpha1.Rule
} }
// Singleton source instance // Singleton source instance
var ( var (
src = customSource{config: newDefaultConfig()} src = customSource{
config: &config{},
rules: []nfdv1alpha1.Rule{},
}
_ source.LabelSource = &src _ source.LabelSource = &src
_ source.ConfigurableSource = &src _ source.ConfigurableSource = &src
) )
@ -65,6 +70,8 @@ func (s *customSource) GetConfig() source.Config { return s.config }
func (s *customSource) SetConfig(conf source.Config) { func (s *customSource) SetConfig(conf source.Config) {
switch v := conf.(type) { switch v := conf.(type) {
case *config: case *config:
r := []api.Rule(*v)
s.rules = convertInternalRulesToNfdApi(&r)
s.config = v s.config = v
default: default:
panic(fmt.Sprintf("invalid config type: %T", conf)) panic(fmt.Sprintf("invalid config type: %T", conf))
@ -80,8 +87,8 @@ func (s *customSource) GetLabels() (source.FeatureLabels, error) {
features := source.GetAllFeatures() features := source.GetAllFeatures()
labels := source.FeatureLabels{} labels := source.FeatureLabels{}
allFeatureConfig := append(getStaticFeatureConfig(), *s.config...) allFeatureConfig := append(getStaticRules(), s.rules...)
allFeatureConfig = append(allFeatureConfig, getDirectoryFeatureConfig()...) allFeatureConfig = append(allFeatureConfig, getDropinDirRules()...)
klog.V(2).InfoS("resolving custom features", "configuration", utils.DelayedDumper(allFeatureConfig)) klog.V(2).InfoS("resolving custom features", "configuration", utils.DelayedDumper(allFeatureConfig))
// Iterate over features // Iterate over features
for _, rule := range allFeatureConfig { for _, rule := range allFeatureConfig {
@ -102,6 +109,17 @@ func (s *customSource) GetLabels() (source.FeatureLabels, error) {
return labels, nil return labels, nil
} }
func convertInternalRulesToNfdApi(in *[]api.Rule) []nfdv1alpha1.Rule {
out := make([]nfdv1alpha1.Rule, len(*in))
for i := range *in {
if err := api.ConvertRuleToV1alpha1(&(*in)[i], &out[i]); err != nil {
klog.ErrorS(err, "FATAL: API conversion failed")
os.Exit(255)
}
}
return out
}
func init() { func init() {
source.Register(&src) source.Register(&src)
} }

View file

@ -22,22 +22,24 @@ import (
"strings" "strings"
"k8s.io/klog/v2" "k8s.io/klog/v2"
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
api "sigs.k8s.io/node-feature-discovery/source/custom/api"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
) )
// Directory stores the full path for the custom sources folder // Directory stores the full path for the custom sources folder
const Directory = "/etc/kubernetes/node-feature-discovery/custom.d" const Directory = "/etc/kubernetes/node-feature-discovery/custom.d"
// getDirectoryFeatureConfig returns features configured in the "/etc/kubernetes/node-feature-discovery/custom.d" // getDropinDirRules returns features configured in the "/etc/kubernetes/node-feature-discovery/custom.d"
// host directory and its 1st level subdirectories, which can be populated e.g. by ConfigMaps // host directory and its 1st level subdirectories, which can be populated e.g. by ConfigMaps
func getDirectoryFeatureConfig() []CustomRule { func getDropinDirRules() []nfdv1alpha1.Rule {
features := readDir(Directory, true) features := readDir(Directory, true)
klog.V(3).InfoS("all custom feature specs from config dir", "featureSpecs", features) klog.V(3).InfoS("all custom feature specs from config dir", "featureSpecs", features)
return features return features
} }
func readDir(dirName string, recursive bool) []CustomRule { func readDir(dirName string, recursive bool) []nfdv1alpha1.Rule {
features := make([]CustomRule, 0) features := make([]nfdv1alpha1.Rule, 0)
klog.V(4).InfoS("reading directory", "path", dirName) klog.V(4).InfoS("reading directory", "path", dirName)
files, err := os.ReadDir(dirName) files, err := os.ReadDir(dirName)
@ -74,14 +76,14 @@ func readDir(dirName string, recursive bool) []CustomRule {
continue continue
} }
config := &[]CustomRule{} config := &[]api.Rule{}
err = yaml.UnmarshalStrict(bytes, config) err = yaml.UnmarshalStrict(bytes, config)
if err != nil { if err != nil {
klog.ErrorS(err, "could not parse file", "path", fileName) klog.ErrorS(err, "could not parse file", "path", fileName)
continue continue
} }
features = append(features, *config...) features = append(features, convertInternalRulesToNfdApi(config)...)
} }
return features return features
} }

View file

@ -20,11 +20,10 @@ import (
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1" nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
) )
// getStaticFeatures returns statically configured custom features to discover // getStaticRules returns statically configured custom features to discover
// e.g RMDA related features. NFD configuration file may extend these custom features by adding rules. // e.g RMDA related features. NFD configuration file may extend these custom features by adding rules.
func getStaticFeatureConfig() []CustomRule { func getStaticRules() []nfdv1alpha1.Rule {
return []CustomRule{ return []nfdv1alpha1.Rule{
{
nfdv1alpha1.Rule{ nfdv1alpha1.Rule{
Name: "RDMA capable static rule", Name: "RDMA capable static rule",
Labels: map[string]string{"rdma.capable": "true"}, Labels: map[string]string{"rdma.capable": "true"},
@ -39,8 +38,6 @@ func getStaticFeatureConfig() []CustomRule {
}, },
}, },
}, },
},
{
nfdv1alpha1.Rule{ nfdv1alpha1.Rule{
Name: "RDMA available static rule", Name: "RDMA available static rule",
Labels: map[string]string{"rdma.available": "true"}, Labels: map[string]string{"rdma.available": "true"},
@ -58,7 +55,6 @@ func getStaticFeatureConfig() []CustomRule {
}, },
}, },
}, },
},
} }
} }