1
0
Fork 0
mirror of https://github.com/kubernetes-sigs/node-feature-discovery.git synced 2024-12-14 11:57:51 +00:00

Merge pull request #597 from marquiz/devel/source-register

source: make sources register themselves
This commit is contained in:
Kubernetes Prow Robot 2021-09-19 09:10:09 -07:00 committed by GitHub
commit 102003f8b3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 443 additions and 237 deletions

View file

@ -129,7 +129,7 @@ helm-lint:
helm lint --strict deployment/helm/node-feature-discovery/
test:
$(GO_CMD) test ./cmd/... ./pkg/...
$(GO_CMD) test ./cmd/... ./pkg/... ./source/...
e2e-test:
@if [ -z ${KUBECONFIG} ]; then echo "[ERR] KUBECONFIG missing, must be defined"; exit 1; fi

View file

@ -33,7 +33,6 @@ import (
"sigs.k8s.io/node-feature-discovery/pkg/utils"
"sigs.k8s.io/node-feature-discovery/source"
"sigs.k8s.io/node-feature-discovery/source/cpu"
"sigs.k8s.io/node-feature-discovery/source/fake"
"sigs.k8s.io/node-feature-discovery/source/kernel"
"sigs.k8s.io/node-feature-discovery/source/pci"
)
@ -96,15 +95,6 @@ func makeFakeFeatures(names []string) (source.FeatureLabels, Labels) {
return features, labels
}
func (w *nfdWorker) getSource(name string) source.LabelSource {
for _, s := range w.realSources {
if s.Name() == name {
return s
}
}
return nil
}
func TestConfigParse(t *testing.T) {
Convey("When parsing configuration", t, func() {
w, err := NewNfdWorker(&Args{})
@ -130,7 +120,7 @@ func TestConfigParse(t *testing.T) {
Convey("overrides should take effect", func() {
So(worker.config.Core.NoPublish, ShouldBeTrue)
c := worker.getSource("cpu").GetConfig().(*cpu.Config)
c := source.GetConfigurableSource("cpu").GetConfig().(*cpu.Config)
So(c.Cpuid.AttributeBlacklist, ShouldResemble, []string{"foo", "bar"})
})
})
@ -167,9 +157,9 @@ sources:
// Verify feature source config
So(err, ShouldBeNil)
c := worker.getSource("kernel").GetConfig()
c := source.GetConfigurableSource("kernel").GetConfig()
So(c.(*kernel.Config).ConfigOpts, ShouldResemble, []string{"DMI"})
c = worker.getSource("pci").GetConfig()
c = source.GetConfigurableSource("pci").GetConfig()
So(c.(*pci.Config).DeviceClassWhitelist, ShouldResemble, []string{"ff"})
})
})
@ -189,9 +179,9 @@ sources:
// Verify feature source config
So(err, ShouldBeNil)
c := worker.getSource("kernel").GetConfig()
c := source.GetConfigurableSource("kernel").GetConfig()
So(c.(*kernel.Config).ConfigOpts, ShouldResemble, []string{"DMI"})
c = worker.getSource("pci").GetConfig()
c = source.GetConfigurableSource("pci").GetConfig()
So(c.(*pci.Config).DeviceClassWhitelist, ShouldResemble, []string{"03"})
})
})
@ -318,7 +308,7 @@ func TestNewNfdWorker(t *testing.T) {
worker := w.(*nfdWorker)
So(worker.configure("", ""), ShouldBeNil)
Convey("all sources should be enabled and the whitelist regexp should be empty", func() {
So(len(worker.enabledSources), ShouldEqual, len(worker.realSources))
So(len(worker.enabledSources), ShouldEqual, len(source.GetAllLabelSources())-1)
So(worker.config.Core.LabelWhiteList, ShouldResemble, emptyRegexp)
})
})
@ -333,7 +323,7 @@ func TestNewNfdWorker(t *testing.T) {
So(worker.configure("", ""), ShouldBeNil)
Convey("proper sources should be enabled", func() {
So(len(worker.enabledSources), ShouldEqual, 1)
So(worker.enabledSources[0], ShouldHaveSameTypeAs, &fake.Source{})
So(worker.enabledSources[0].Name(), ShouldEqual, "fake")
So(worker.config.Core.LabelWhiteList, ShouldResemble, emptyRegexp)
})
})
@ -356,9 +346,9 @@ func TestNewNfdWorker(t *testing.T) {
func TestCreateFeatureLabels(t *testing.T) {
Convey("When creating feature labels from the configured sources", t, func() {
fakeLabelSource := source.LabelSource(new(fake.Source))
fakeLabelSource.SetConfig(fakeLabelSource.NewConfig())
sources := []source.LabelSource{fakeLabelSource}
cs := source.GetConfigurableSource("fake")
cs.SetConfig(cs.NewConfig())
sources := []source.LabelSource{source.GetLabelSource("fake")}
Convey("When fake feature source is configured", func() {
emptyLabelWL := regexp.MustCompile("")

View file

@ -23,6 +23,7 @@ import (
"os"
"path/filepath"
"regexp"
"sort"
"strings"
"time"
@ -36,18 +37,20 @@ import (
"sigs.k8s.io/node-feature-discovery/pkg/utils"
"sigs.k8s.io/node-feature-discovery/pkg/version"
"sigs.k8s.io/node-feature-discovery/source"
"sigs.k8s.io/node-feature-discovery/source/cpu"
"sigs.k8s.io/node-feature-discovery/source/custom"
"sigs.k8s.io/node-feature-discovery/source/fake"
"sigs.k8s.io/node-feature-discovery/source/iommu"
"sigs.k8s.io/node-feature-discovery/source/kernel"
"sigs.k8s.io/node-feature-discovery/source/local"
"sigs.k8s.io/node-feature-discovery/source/memory"
"sigs.k8s.io/node-feature-discovery/source/network"
"sigs.k8s.io/node-feature-discovery/source/pci"
"sigs.k8s.io/node-feature-discovery/source/storage"
"sigs.k8s.io/node-feature-discovery/source/system"
"sigs.k8s.io/node-feature-discovery/source/usb"
// Register all source packages
_ "sigs.k8s.io/node-feature-discovery/source/cpu"
_ "sigs.k8s.io/node-feature-discovery/source/custom"
_ "sigs.k8s.io/node-feature-discovery/source/fake"
_ "sigs.k8s.io/node-feature-discovery/source/iommu"
_ "sigs.k8s.io/node-feature-discovery/source/kernel"
_ "sigs.k8s.io/node-feature-discovery/source/local"
_ "sigs.k8s.io/node-feature-discovery/source/memory"
_ "sigs.k8s.io/node-feature-discovery/source/network"
_ "sigs.k8s.io/node-feature-discovery/source/pci"
_ "sigs.k8s.io/node-feature-discovery/source/storage"
_ "sigs.k8s.io/node-feature-discovery/source/system"
_ "sigs.k8s.io/node-feature-discovery/source/usb"
)
// Global config
@ -99,9 +102,7 @@ type nfdWorker struct {
client pb.LabelerClient
configFilePath string
config *NFDConfig
realSources []source.LabelSource
stop chan struct{} // channel for signaling stop
testSources []source.LabelSource
enabledSources []source.LabelSource
}
@ -121,24 +122,6 @@ func NewNfdWorker(args *Args) (nfdclient.NfdClient, error) {
args: *args,
config: &NFDConfig{},
realSources: []source.LabelSource{
&cpu.Source{},
&iommu.Source{},
&kernel.Source{},
&memory.Source{},
&network.Source{},
&pci.Source{},
&storage.Source{},
&system.Source{},
&usb.Source{},
&custom.Source{},
// local needs to be the last source so that it is able to override
// labels from other sources
&local.Source{},
},
testSources: []source.LabelSource{
&fake.Source{},
},
stop: make(chan struct{}, 1),
}
@ -301,36 +284,44 @@ func (w *nfdWorker) configureCore(c coreConfig) error {
}
// Determine enabled feature sources
sourceList := map[string]struct{}{}
all := false
for _, s := range c.Sources {
if s == "all" {
all = true
continue
enabled := make(map[string]source.LabelSource)
for _, name := range c.Sources {
if name == "all" {
for n, s := range source.GetAllLabelSources() {
if ts, ok := s.(source.TestSource); !ok || !ts.IsTestSource() {
enabled[n] = s
}
}
} else {
if s := source.GetLabelSource(name); s != nil {
enabled[name] = s
} else {
klog.Warningf("skipping unknown source %q specified in core.sources (or --sources)", name)
}
}
sourceList[strings.TrimSpace(s)] = struct{}{}
}
w.enabledSources = []source.LabelSource{}
for _, s := range w.realSources {
if _, enabled := sourceList[s.Name()]; all || enabled {
w.enabledSources = make([]source.LabelSource, 0, len(enabled))
for _, s := range enabled {
w.enabledSources = append(w.enabledSources, s)
delete(sourceList, s.Name())
}
sort.Slice(w.enabledSources, func(i, j int) bool {
iP, jP := w.enabledSources[i].Priority(), w.enabledSources[j].Priority()
if iP != jP {
return iP < jP
}
for _, s := range w.testSources {
if _, enabled := sourceList[s.Name()]; enabled {
w.enabledSources = append(w.enabledSources, s)
delete(sourceList, s.Name())
return w.enabledSources[i].Name() < w.enabledSources[j].Name()
})
if klog.V(1).Enabled() {
n := make([]string, len(w.enabledSources))
for i, s := range w.enabledSources {
n[i] = s.Name()
}
klog.Infof("enabled label sources: %s", strings.Join(n, ", "))
}
if len(sourceList) > 0 {
names := make([]string, 0, len(sourceList))
for n := range sourceList {
names = append(names, n)
}
klog.Warningf("skipping unknown source(s) %q specified in core.sources (or --sources)", strings.Join(names, ", "))
}
return nil
}
@ -338,9 +329,9 @@ func (w *nfdWorker) configureCore(c coreConfig) error {
func (w *nfdWorker) configure(filepath string, overrides string) error {
// Create a new default config
c := newDefaultConfig()
allSources := append(w.realSources, w.testSources...)
c.Sources = make(map[string]source.Config, len(allSources))
for _, s := range allSources {
confSources := source.GetAllConfigurableSources()
c.Sources = make(map[string]source.Config, len(confSources))
for _, s := range confSources {
c.Sources[s.Name()] = s.NewConfig()
}
@ -388,8 +379,8 @@ func (w *nfdWorker) configure(filepath string, overrides string) error {
return err
}
// (Re-)configure all "real" sources, test sources are not configurable
for _, s := range allSources {
// (Re-)configure sources
for _, s := range confSources {
s.SetConfig(c.Sources[s.Name()])
}
@ -432,8 +423,8 @@ func getFeatureLabels(source source.LabelSource, labelWhiteList regexp.Regexp) (
// Prefix for labels in the default namespace
prefix := source.Name() + "-"
switch source.(type) {
case *local.Source:
switch source.Name() {
case "local":
// Do not prefix labels from the hooks
prefix = ""
}

View file

@ -78,22 +78,29 @@ type keyFilter struct {
whitelist bool
}
// Source implements LabelSource.
type Source struct {
// cpuSource implements the LabelSource and ConfigurableSource interfaces.
type cpuSource struct {
config *Config
cpuidFilter *keyFilter
}
func (s Source) Name() string { return Name }
// Singleton source instance
var (
src cpuSource
_ source.LabelSource = &src
_ source.ConfigurableSource = &src
)
func (s *cpuSource) Name() string { return Name }
// NewConfig method of the LabelSource interface
func (s *Source) NewConfig() source.Config { return newDefaultConfig() }
func (s *cpuSource) NewConfig() source.Config { return newDefaultConfig() }
// GetConfig method of the LabelSource interface
func (s *Source) GetConfig() source.Config { return s.config }
func (s *cpuSource) GetConfig() source.Config { return s.config }
// SetConfig method of the LabelSource interface
func (s *Source) SetConfig(conf source.Config) {
func (s *cpuSource) SetConfig(conf source.Config) {
switch v := conf.(type) {
case *Config:
s.config = v
@ -103,7 +110,10 @@ func (s *Source) SetConfig(conf source.Config) {
}
}
func (s *Source) Discover() (source.FeatureLabels, error) {
// Priority method of the LabelSource interface
func (s *cpuSource) Priority() int { return 0 }
func (s *cpuSource) Discover() (source.FeatureLabels, error) {
features := source.FeatureLabels{}
// Check if hyper-threading seems to be enabled
@ -182,7 +192,7 @@ func haveThreadSiblings() (bool, error) {
return false, nil
}
func (s *Source) initCpuidFilter() {
func (s *cpuSource) initCpuidFilter() {
newFilter := keyFilter{keys: map[string]struct{}{}}
if len(s.config.Cpuid.AttributeWhitelist) > 0 {
for _, k := range s.config.Cpuid.AttributeWhitelist {
@ -210,3 +220,7 @@ func (f keyFilter) unmask(k string) bool {
}
return false
}
func init() {
source.Register(&src)
}

View file

@ -51,22 +51,29 @@ func newDefaultConfig() *config {
return &config{}
}
// Source implements LabelSource.
type Source struct {
// customSource implements the LabelSource and ConfigurableSource interfaces.
type customSource struct {
config *config
}
// Singleton source instance
var (
src customSource
_ source.LabelSource = &src
_ source.ConfigurableSource = &src
)
// Name returns the name of the feature source
func (s Source) Name() string { return Name }
func (s *customSource) Name() string { return Name }
// NewConfig method of the LabelSource interface
func (s *Source) NewConfig() source.Config { return newDefaultConfig() }
func (s *customSource) NewConfig() source.Config { return newDefaultConfig() }
// GetConfig method of the LabelSource interface
func (s *Source) GetConfig() source.Config { return s.config }
func (s *customSource) GetConfig() source.Config { return s.config }
// SetConfig method of the LabelSource interface
func (s *Source) SetConfig(conf source.Config) {
func (s *customSource) SetConfig(conf source.Config) {
switch v := conf.(type) {
case *config:
s.config = v
@ -75,8 +82,11 @@ func (s *Source) SetConfig(conf source.Config) {
}
}
// Priority method of the LabelSource interface
func (s *customSource) Priority() int { return 10 }
// Discover features
func (s Source) Discover() (source.FeatureLabels, error) {
func (s *customSource) Discover() (source.FeatureLabels, error) {
features := source.FeatureLabels{}
allFeatureConfig := append(getStaticFeatureConfig(), *s.config...)
allFeatureConfig = append(allFeatureConfig, getDirectoryFeatureConfig()...)
@ -101,7 +111,7 @@ func (s Source) Discover() (source.FeatureLabels, error) {
// Process a single feature by Matching on the defined rules.
// A feature is present if all defined Rules in a MatchRule return a match.
func (s Source) discoverFeature(feature FeatureSpec) (bool, error) {
func (s *customSource) discoverFeature(feature FeatureSpec) (bool, error) {
for _, matchRules := range feature.MatchOn {
allRules := []rules.Rule{
@ -136,3 +146,7 @@ func (s Source) discoverFeature(feature FeatureSpec) (bool, error) {
}
return false, nil
}
func init() {
source.Register(&src)
}

View file

@ -1,5 +1,5 @@
/*
Copyright 2017 The Kubernetes Authors.
Copyright 2017-2021 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -40,22 +40,29 @@ func newDefaultConfig() *Config {
}
}
// Source implements LabelSource.
type Source struct {
// fakeSource implements the LabelSource and ConfigurableSource interfaces.
type fakeSource struct {
config *Config
}
// Singleton source instance
var (
src fakeSource
_ source.LabelSource = &src
_ source.ConfigurableSource = &src
)
// Name returns an identifier string for this feature source.
func (s Source) Name() string { return Name }
func (s *fakeSource) Name() string { return Name }
// NewConfig method of the LabelSource interface
func (s *Source) NewConfig() source.Config { return newDefaultConfig() }
func (s *fakeSource) NewConfig() source.Config { return newDefaultConfig() }
// GetConfig method of the LabelSource interface
func (s *Source) GetConfig() source.Config { return s.config }
func (s *fakeSource) GetConfig() source.Config { return s.config }
// SetConfig method of the LabelSource interface
func (s *Source) SetConfig(conf source.Config) {
func (s *fakeSource) SetConfig(conf source.Config) {
switch v := conf.(type) {
case *Config:
s.config = v
@ -65,10 +72,13 @@ func (s *Source) SetConfig(conf source.Config) {
}
// Configure method of the LabelSource interface
func (s Source) Configure([]byte) error { return nil }
func (s *fakeSource) Configure([]byte) error { return nil }
// Priority method of the LabelSource interface
func (s *fakeSource) Priority() int { return 0 }
// Discover returns feature names for some fake features.
func (s Source) Discover() (source.FeatureLabels, error) {
func (s *fakeSource) Discover() (source.FeatureLabels, error) {
// Adding three fake features.
features := make(source.FeatureLabels, len(s.config.Labels))
for k, v := range s.config.Labels {
@ -77,3 +87,10 @@ func (s Source) Discover() (source.FeatureLabels, error) {
return features, nil
}
// IsTestSource method of the LabelSource interface
func (s *fakeSource) IsTestSource() bool { return true }
func init() {
source.Register(&src)
}

View file

@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2018-2021 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -25,21 +25,21 @@ import (
const Name = "iommu"
// Source implements LabelSource.
type Source struct{}
// iommuSource implements the LabelSource interface.
type iommuSource struct{}
func (s Source) Name() string { return Name }
func (s *iommuSource) Name() string { return Name }
// NewConfig method of the LabelSource interface
func (s *Source) NewConfig() source.Config { return nil }
// Singleton source instance
var (
src iommuSource
_ source.LabelSource = &src
)
// GetConfig method of the LabelSource interface
func (s *Source) GetConfig() source.Config { return nil }
// Priority method of the LabelSource interface
func (s *iommuSource) Priority() int { return 0 }
// SetConfig method of the LabelSource interface
func (s *Source) SetConfig(source.Config) {}
func (s Source) Discover() (source.FeatureLabels, error) {
func (s *iommuSource) Discover() (source.FeatureLabels, error) {
features := source.FeatureLabels{}
// Check if any iommu devices are available
@ -54,3 +54,7 @@ func (s Source) Discover() (source.FeatureLabels, error) {
return features, nil
}
func init() {
source.Register(&src)
}

View file

@ -47,21 +47,28 @@ func newDefaultConfig() *Config {
}
}
// Source implements LabelSource.
type Source struct {
// kernelSource implements the LabelSource and ConfigurableSource interfaces.
type kernelSource struct {
config *Config
}
func (s *Source) Name() string { return Name }
// Singleton source instance
var (
src kernelSource
_ source.LabelSource = &src
_ source.ConfigurableSource = &src
)
func (s *kernelSource) Name() string { return Name }
// NewConfig method of the LabelSource interface
func (s *Source) NewConfig() source.Config { return newDefaultConfig() }
func (s *kernelSource) NewConfig() source.Config { return newDefaultConfig() }
// GetConfig method of the LabelSource interface
func (s *Source) GetConfig() source.Config { return s.config }
func (s *kernelSource) GetConfig() source.Config { return s.config }
// SetConfig method of the LabelSource interface
func (s *Source) SetConfig(conf source.Config) {
func (s *kernelSource) SetConfig(conf source.Config) {
switch v := conf.(type) {
case *Config:
s.config = v
@ -70,7 +77,10 @@ func (s *Source) SetConfig(conf source.Config) {
}
}
func (s *Source) Discover() (source.FeatureLabels, error) {
// Priority method of the LabelSource interface
func (s *kernelSource) Priority() int { return 0 }
func (s *kernelSource) Discover() (source.FeatureLabels, error) {
features := source.FeatureLabels{}
// Read kernel version
@ -135,3 +145,7 @@ func parseVersion() (map[string]string, error) {
return version, nil
}
func init() {
source.Register(&src)
}

View file

@ -38,23 +38,23 @@ var (
hookDir = "/etc/kubernetes/node-feature-discovery/source.d/"
)
// Source implements LabelSource.
type Source struct{}
// localSource implements the LabelSource interface.
type localSource struct{}
// Singleton source instance
var (
src localSource
_ source.LabelSource = &src
)
// Name method of the LabelSource interface
func (s Source) Name() string { return Name }
func (s *localSource) Name() string { return Name }
// NewConfig method of the LabelSource interface
func (s *Source) NewConfig() source.Config { return nil }
// GetConfig method of the LabelSource interface
func (s *Source) GetConfig() source.Config { return nil }
// SetConfig method of the LabelSource interface
func (s *Source) SetConfig(source.Config) {}
// Priority method of the LabelSource interface
func (s *localSource) Priority() int { return 20 }
// Discover method of the LabelSource interface
func (s Source) Discover() (source.FeatureLabels, error) {
func (s *localSource) Discover() (source.FeatureLabels, error) {
featuresFromHooks, err := getFeaturesFromHooks()
if err != nil {
klog.Error(err)
@ -240,3 +240,7 @@ func getFileContent(fileName string) ([][]byte, error) {
return lines, nil
}
func init() {
source.Register(&src)
}

View file

@ -28,23 +28,23 @@ import (
const Name = "memory"
// Source implements LabelSource.
type Source struct{}
// memorySource implements the LabelSource interface.
type memorySource struct{}
// Singleton source instance
var (
src memorySource
_ source.LabelSource = &src
)
// Name returns an identifier string for this feature source.
func (s Source) Name() string { return Name }
func (s *memorySource) Name() string { return Name }
// NewConfig method of the LabelSource interface
func (s *Source) NewConfig() source.Config { return nil }
// GetConfig method of the LabelSource interface
func (s *Source) GetConfig() source.Config { return nil }
// SetConfig method of the LabelSource interface
func (s *Source) SetConfig(source.Config) {}
// Priority method of the LabelSource interface
func (s *memorySource) Priority() int { return 0 }
// Discover returns feature names for memory: numa if more than one memory node is present.
func (s Source) Discover() (source.FeatureLabels, error) {
func (s *memorySource) Discover() (source.FeatureLabels, error) {
features := source.FeatureLabels{}
// Detect NUMA
@ -118,3 +118,7 @@ func detectNvdimm() (map[string]bool, error) {
return features, nil
}
func init() {
source.Register(&src)
}

View file

@ -34,22 +34,6 @@ func (_m *MockLabelSource) Discover() (FeatureLabels, error) {
return r0, r1
}
// GetConfig provides a mock function with given fields:
func (_m *MockLabelSource) GetConfig() Config {
ret := _m.Called()
var r0 Config
if rf, ok := ret.Get(0).(func() Config); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(Config)
}
}
return r0
}
// Name provides a mock function with given fields:
func (_m *MockLabelSource) Name() string {
ret := _m.Called()
@ -64,23 +48,16 @@ func (_m *MockLabelSource) Name() string {
return r0
}
// NewConfig provides a mock function with given fields:
func (_m *MockLabelSource) NewConfig() Config {
// Priority provides a mock function with given fields:
func (_m *MockLabelSource) Priority() int {
ret := _m.Called()
var r0 Config
if rf, ok := ret.Get(0).(func() Config); ok {
var r0 int
if rf, ok := ret.Get(0).(func() int); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(Config)
}
r0 = ret.Get(0).(int)
}
return r0
}
// SetConfig provides a mock function with given fields: _a0
func (_m *MockLabelSource) SetConfig(_a0 Config) {
_m.Called(_a0)
}

View file

@ -41,23 +41,23 @@ const (
const sysfsBaseDir = "class/net"
// Source implements LabelSource.
type Source struct{}
// networkSource implements the LabelSource interface.
type networkSource struct{}
// Singleton source instance
var (
src networkSource
_ source.LabelSource = &src
)
// Name returns an identifier string for this feature source.
func (s Source) Name() string { return Name }
func (s *networkSource) Name() string { return Name }
// NewConfig method of the LabelSource interface
func (s *Source) NewConfig() source.Config { return nil }
// GetConfig method of the LabelSource interface
func (s *Source) GetConfig() source.Config { return nil }
// SetConfig method of the LabelSource interface
func (s *Source) SetConfig(source.Config) {}
// Priority method of the LabelSource interface
func (s *networkSource) Priority() int { return 0 }
// Discover returns feature names sriov-configured and sriov if SR-IOV capable NICs are present and/or SR-IOV virtual functions are configured on the node
func (s Source) Discover() (source.FeatureLabels, error) {
func (s *networkSource) Discover() (source.FeatureLabels, error) {
features := source.FeatureLabels{}
netInterfaces, err := ioutil.ReadDir(source.SysfsDir.Path(sysfsBaseDir))
@ -128,3 +128,7 @@ func readIfFlags(name string) (uint64, error) {
return flags, nil
}
func init() {
source.Register(&src)
}

View file

@ -41,22 +41,29 @@ func newDefaultConfig() *Config {
}
}
// Source implements LabelSource.
type Source struct {
// pciSource implements the LabelSource and ConfigurableSource interfaces.
type pciSource struct {
config *Config
}
// Singleton source instance
var (
src pciSource
_ source.LabelSource = &src
_ source.ConfigurableSource = &src
)
// Name returns the name of the feature source
func (s Source) Name() string { return Name }
func (s *pciSource) Name() string { return Name }
// NewConfig method of the LabelSource interface
func (s *Source) NewConfig() source.Config { return newDefaultConfig() }
func (s *pciSource) NewConfig() source.Config { return newDefaultConfig() }
// GetConfig method of the LabelSource interface
func (s *Source) GetConfig() source.Config { return s.config }
func (s *pciSource) GetConfig() source.Config { return s.config }
// SetConfig method of the LabelSource interface
func (s *Source) SetConfig(conf source.Config) {
func (s *pciSource) SetConfig(conf source.Config) {
switch v := conf.(type) {
case *Config:
s.config = v
@ -65,8 +72,11 @@ func (s *Source) SetConfig(conf source.Config) {
}
}
// Priority method of the LabelSource interface
func (s *pciSource) Priority() int { return 0 }
// Discover features
func (s Source) Discover() (source.FeatureLabels, error) {
func (s *pciSource) Discover() (source.FeatureLabels, error) {
features := source.FeatureLabels{}
// Construct a device label format, a sorted list of valid attributes
@ -132,3 +142,7 @@ func (s Source) Discover() (source.FeatureLabels, error) {
}
return features, nil
}
func init() {
source.Register(&src)
}

View file

@ -1,5 +1,5 @@
/*
Copyright 2017 The Kubernetes Authors.
Copyright 2017-2021 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -16,20 +16,31 @@ limitations under the License.
package source
// FeatureLabelValue represents the value of one feature label
type FeatureLabelValue interface{}
import (
"fmt"
)
// FeatureLabels is a collection of feature labels
type FeatureLabels map[string]FeatureLabelValue
// Source is the base interface for all other source interfaces
type Source interface {
// Name returns a friendly name for this source
Name() string
}
// LabelSource represents a source of node feature labels
type LabelSource interface {
// Name returns a friendly name for this source
Name() string
Source
// Discover returns discovered feature labels
Discover() (FeatureLabels, error)
// Priority returns the priority of the source
Priority() int
}
// ConfigurableSource is an interface for a source that can be configured
type ConfigurableSource interface {
Source
// NewConfig returns a new default config of the source
NewConfig() Config
@ -40,6 +51,69 @@ type LabelSource interface {
SetConfig(Config)
}
// TestSource represents a source purposed for testing only
type TestSource interface {
Source
// IsTestSource returns true if the source is not for production
IsTestSource() bool
}
// FeatureLabelValue represents the value of one feature label
type FeatureLabelValue interface{}
// FeatureLabels is a collection of feature labels
type FeatureLabels map[string]FeatureLabelValue
// Config is the generic interface for source configuration data
type Config interface {
}
// sources contain all registered sources
var sources = make(map[string]Source)
// RegisterSource registers a source
func Register(s Source) {
if name, ok := sources[s.Name()]; ok {
panic(fmt.Sprintf("source %q already registered", name))
}
sources[s.Name()] = s
}
// GetLabelSource a registered label source
func GetLabelSource(name string) LabelSource {
if s, ok := sources[name].(LabelSource); ok {
return s
}
return nil
}
// GetAllLabelSources returns all registered label sources
func GetAllLabelSources() map[string]LabelSource {
all := make(map[string]LabelSource)
for k, v := range sources {
if s, ok := v.(LabelSource); ok {
all[k] = s
}
}
return all
}
// GetConfigurableSource a registered configurable source
func GetConfigurableSource(name string) ConfigurableSource {
if s, ok := sources[name].(ConfigurableSource); ok {
return s
}
return nil
}
// GetAllConfigurableSources returns all registered configurable sources
func GetAllConfigurableSources() map[string]ConfigurableSource {
all := make(map[string]ConfigurableSource)
for k, v := range sources {
if s, ok := v.(ConfigurableSource); ok {
all[k] = s
}
}
return all
}

63
source/source_test.go Normal file
View file

@ -0,0 +1,63 @@
/*
Copyright 2021 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package source_test
import (
"testing"
"github.com/stretchr/testify/assert"
source "sigs.k8s.io/node-feature-discovery/source"
// Register all source packages
_ "sigs.k8s.io/node-feature-discovery/source/cpu"
_ "sigs.k8s.io/node-feature-discovery/source/custom"
_ "sigs.k8s.io/node-feature-discovery/source/fake"
_ "sigs.k8s.io/node-feature-discovery/source/iommu"
_ "sigs.k8s.io/node-feature-discovery/source/kernel"
_ "sigs.k8s.io/node-feature-discovery/source/local"
_ "sigs.k8s.io/node-feature-discovery/source/memory"
_ "sigs.k8s.io/node-feature-discovery/source/network"
_ "sigs.k8s.io/node-feature-discovery/source/pci"
_ "sigs.k8s.io/node-feature-discovery/source/storage"
_ "sigs.k8s.io/node-feature-discovery/source/system"
_ "sigs.k8s.io/node-feature-discovery/source/usb"
)
func TestLabelSources(t *testing.T) {
sources := source.GetAllLabelSources()
assert.NotZero(t, len(sources))
for n, s := range sources {
assert.Equalf(t, n, s.Name(), "testing labelsource %q failed", n)
}
}
func TestConfigurableSources(t *testing.T) {
sources := source.GetAllConfigurableSources()
assert.NotZero(t, len(sources))
for n, s := range sources {
assert.Equalf(t, n, s.Name(), "testing ConfigurableSource %q failed", n)
c := s.NewConfig()
s.SetConfig(c)
rc := s.GetConfig()
assert.Equalf(t, c, rc, "testing ConfigurableSource %q failed", n)
}
}

View file

@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2018-2021 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -25,23 +25,23 @@ import (
const Name = "storage"
// Source implements LabelSource.
type Source struct{}
// storageSource implements the LabelSource interface.
type storageSource struct{}
// Singleton source instance
var (
src storageSource
_ source.LabelSource = &src
)
// Name returns an identifier string for this feature source.
func (s Source) Name() string { return Name }
func (s *storageSource) Name() string { return Name }
// NewConfig method of the LabelSource interface
func (s *Source) NewConfig() source.Config { return nil }
// GetConfig method of the LabelSource interface
func (s *Source) GetConfig() source.Config { return nil }
// SetConfig method of the LabelSource interface
func (s *Source) SetConfig(source.Config) {}
// Priority method of the LabelSource interface
func (s *storageSource) Priority() int { return 0 }
// Discover returns feature names for storage: nonrotationaldisk if any SSD drive present.
func (s Source) Discover() (source.FeatureLabels, error) {
func (s *storageSource) Discover() (source.FeatureLabels, error) {
features := source.FeatureLabels{}
// Check if there is any non-rotational block devices attached to the node
@ -62,3 +62,7 @@ func (s Source) Discover() (source.FeatureLabels, error) {
}
return features, nil
}
func init() {
source.Register(&src)
}

View file

@ -34,21 +34,21 @@ var osReleaseFields = [...]string{
const Name = "system"
// Source implements LabelSource.
type Source struct{}
// systemSource implements the LabelSource interface.
type systemSource struct{}
func (s Source) Name() string { return Name }
// Singleton source instance
var (
src systemSource
_ source.LabelSource = &src
)
// NewConfig method of the LabelSource interface
func (s *Source) NewConfig() source.Config { return nil }
func (s *systemSource) Name() string { return Name }
// GetConfig method of the LabelSource interface
func (s *Source) GetConfig() source.Config { return nil }
// Priority method of the LabelSource interface
func (s *systemSource) Priority() int { return 0 }
// SetConfig method of the LabelSource interface
func (s *Source) SetConfig(source.Config) {}
func (s Source) Discover() (source.FeatureLabels, error) {
func (s *systemSource) Discover() (source.FeatureLabels, error) {
features := source.FeatureLabels{}
release, err := parseOSRelease()
@ -112,3 +112,7 @@ func splitVersion(version string) map[string]string {
}
return components
}
func init() {
source.Register(&src)
}

View file

@ -44,22 +44,29 @@ func newDefaultConfig() *Config {
}
}
// Source implements LabelSource.
type Source struct {
// usbSource implements the LabelSource and ConfigurableSource interfaces.
type usbSource struct {
config *Config
}
// Singleton source instance
var (
src usbSource
_ source.LabelSource = &src
_ source.ConfigurableSource = &src
)
// Name returns the name of the feature source
func (s Source) Name() string { return Name }
func (s *usbSource) Name() string { return Name }
// NewConfig method of the LabelSource interface
func (s *Source) NewConfig() source.Config { return newDefaultConfig() }
func (s *usbSource) NewConfig() source.Config { return newDefaultConfig() }
// GetConfig method of the LabelSource interface
func (s *Source) GetConfig() source.Config { return s.config }
func (s *usbSource) GetConfig() source.Config { return s.config }
// SetConfig method of the LabelSource interface
func (s *Source) SetConfig(conf source.Config) {
func (s *usbSource) SetConfig(conf source.Config) {
switch v := conf.(type) {
case *Config:
s.config = v
@ -68,8 +75,11 @@ func (s *Source) SetConfig(conf source.Config) {
}
}
// Priority method of the LabelSource interface
func (s *usbSource) Priority() int { return 0 }
// Discover features
func (s Source) Discover() (source.FeatureLabels, error) {
func (s *usbSource) Discover() (source.FeatureLabels, error) {
features := source.FeatureLabels{}
// Construct a device label format, a sorted list of valid attributes
@ -127,3 +137,7 @@ func (s Source) Discover() (source.FeatureLabels, error) {
}
return features, nil
}
func init() {
source.Register(&src)
}