mirror of
https://github.com/kubernetes-sigs/node-feature-discovery.git
synced 2024-12-15 17:50:49 +00:00
Merge pull request #307 from marquiz/devel/label-whitelist
nfd-worker: fix --label-whitelist
This commit is contained in:
commit
ad5eef1514
5 changed files with 78 additions and 39 deletions
12
README.md
12
README.md
|
@ -74,7 +74,10 @@ nfd-master.
|
|||
has been enabled.
|
||||
--no-publish Do not publish feature labels
|
||||
--label-whitelist=<pattern> Regular expression to filter label names to
|
||||
publish to the Kubernetes API server. [Default: ]
|
||||
publish to the Kubernetes API server.
|
||||
NB: the label namespace is omitted i.e. the filter
|
||||
is only applied to the name part after '/'.
|
||||
[Default: ]
|
||||
--extra-label-ns=<list> Comma separated list of allowed extra label namespaces
|
||||
[Default: ]
|
||||
--resource-labels=<list> Comma separated list of labels to be exposed as extended resources.
|
||||
|
@ -129,11 +132,14 @@ nfd-worker.
|
|||
in testing
|
||||
[Default: ]
|
||||
--sources=<sources> Comma separated list of feature sources.
|
||||
[Default: cpu,iommu,kernel,local,memory,network,pci,storage,system,usb]
|
||||
[Default: cpu,custom,iommu,kernel,local,memory,network,pci,storage,system,usb]
|
||||
--no-publish Do not publish discovered features to the
|
||||
cluster-local Kubernetes API server.
|
||||
--label-whitelist=<pattern> Regular expression to filter label names to
|
||||
publish to the Kubernetes API server. [Default: ]
|
||||
publish to the Kubernetes API server.
|
||||
NB: the label namespace is omitted i.e. the filter
|
||||
is only applied to the name part after '/'.
|
||||
[Default: ]
|
||||
--oneshot Label once and exit.
|
||||
--sleep-interval=<seconds> Time to sleep between re-labeling. Non-positive
|
||||
value implies no re-labeling (i.e. infinite
|
||||
|
|
|
@ -85,7 +85,10 @@ func argsParse(argv []string) (master.Args, error) {
|
|||
has been enabled.
|
||||
--no-publish Do not publish feature labels
|
||||
--label-whitelist=<pattern> Regular expression to filter label names to
|
||||
publish to the Kubernetes API server. [Default: ]
|
||||
publish to the Kubernetes API server.
|
||||
NB: the label namespace is omitted i.e. the filter
|
||||
is only applied to the name part after '/'.
|
||||
[Default: ]
|
||||
--extra-label-ns=<list> Comma separated list of allowed extra label namespaces
|
||||
[Default: ]
|
||||
--resource-labels=<list> Comma separated list of labels to be exposed as extended resources.
|
||||
|
|
|
@ -95,7 +95,10 @@ func argsParse(argv []string) (worker.Args, error) {
|
|||
--no-publish Do not publish discovered features to the
|
||||
cluster-local Kubernetes API server.
|
||||
--label-whitelist=<pattern> Regular expression to filter label names to
|
||||
publish to the Kubernetes API server. [Default: ]
|
||||
publish to the Kubernetes API server.
|
||||
NB: the label namespace is omitted i.e. the filter
|
||||
is only applied to the name part after '/'.
|
||||
[Default: ]
|
||||
--oneshot Label once and exit.
|
||||
--sleep-interval=<seconds> Time to sleep between re-labeling. Non-positive
|
||||
value implies no re-labeling (i.e. infinite
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
|
@ -32,25 +33,26 @@ import (
|
|||
"sigs.k8s.io/node-feature-discovery/source/panic_fake"
|
||||
)
|
||||
|
||||
const fakeFeatureSourceName string = "testSource"
|
||||
|
||||
func TestDiscoveryWithMockSources(t *testing.T) {
|
||||
Convey("When I discover features from fake source and update the node using fake client", t, func() {
|
||||
mockFeatureSource := new(source.MockFeatureSource)
|
||||
fakeFeatureSourceName := string("testSource")
|
||||
fakeFeatureNames := []string{"testfeature1", "testfeature2", "testfeature3"}
|
||||
fakeFeatures := source.Features{}
|
||||
fakeFeatureLabels := Labels{}
|
||||
for _, f := range fakeFeatureNames {
|
||||
fakeFeatures[f] = true
|
||||
labelName := fakeFeatureSourceName + "-" + f
|
||||
fakeFeatureLabels[labelName] = "true"
|
||||
}
|
||||
allFeatureNames := []string{"testfeature1", "testfeature2", "test.ns/test", "test.ns/foo", "/no-ns-label", "invalid/test/feature"}
|
||||
whiteListFeatureNames := []string{"testfeature1", "testfeature2", "test.ns/test"}
|
||||
|
||||
fakeFeatures, _ := makeFakeFeatures(allFeatureNames)
|
||||
_, fakeFeatureLabels := makeFakeFeatures(whiteListFeatureNames)
|
||||
|
||||
fakeFeatureSource := source.FeatureSource(mockFeatureSource)
|
||||
|
||||
labelWhiteList := regexp.MustCompile("^test")
|
||||
|
||||
Convey("When I successfully get the labels from the mock source", func() {
|
||||
mockFeatureSource.On("Name").Return(fakeFeatureSourceName)
|
||||
mockFeatureSource.On("Discover").Return(fakeFeatures, nil)
|
||||
|
||||
returnedLabels, err := getFeatureLabels(fakeFeatureSource)
|
||||
returnedLabels, err := getFeatureLabels(fakeFeatureSource, labelWhiteList)
|
||||
Convey("Proper label is returned", func() {
|
||||
So(returnedLabels, ShouldResemble, fakeFeatureLabels)
|
||||
})
|
||||
|
@ -63,7 +65,7 @@ func TestDiscoveryWithMockSources(t *testing.T) {
|
|||
expectedError := errors.New("fake error")
|
||||
mockFeatureSource.On("Discover").Return(nil, expectedError)
|
||||
|
||||
returnedLabels, err := getFeatureLabels(fakeFeatureSource)
|
||||
returnedLabels, err := getFeatureLabels(fakeFeatureSource, labelWhiteList)
|
||||
Convey("No label is returned", func() {
|
||||
So(returnedLabels, ShouldBeNil)
|
||||
})
|
||||
|
@ -74,6 +76,21 @@ func TestDiscoveryWithMockSources(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func makeFakeFeatures(names []string) (source.Features, Labels) {
|
||||
features := source.Features{}
|
||||
labels := Labels{}
|
||||
for _, f := range names {
|
||||
features[f] = true
|
||||
labelName := fakeFeatureSourceName + "-" + f
|
||||
if strings.IndexByte(f, '/') >= 0 {
|
||||
labelName = f
|
||||
}
|
||||
labels[labelName] = "true"
|
||||
}
|
||||
|
||||
return features, labels
|
||||
}
|
||||
|
||||
func TestConfigParse(t *testing.T) {
|
||||
Convey("When parsing configuration file", t, func() {
|
||||
Convey("When non-accessible file is given", func() {
|
||||
|
@ -209,7 +226,7 @@ func TestGetFeatureLabels(t *testing.T) {
|
|||
Convey("When I get feature labels and panic occurs during discovery of a feature source", t, func() {
|
||||
fakePanicFeatureSource := source.FeatureSource(new(panicfake.Source))
|
||||
|
||||
returnedLabels, err := getFeatureLabels(fakePanicFeatureSource)
|
||||
returnedLabels, err := getFeatureLabels(fakePanicFeatureSource, regexp.MustCompile(""))
|
||||
Convey("No label is returned", func() {
|
||||
So(len(returnedLabels), ShouldEqual, 0)
|
||||
})
|
||||
|
|
|
@ -315,7 +315,7 @@ func createFeatureLabels(sources []source.FeatureSource, labelWhiteList *regexp.
|
|||
|
||||
// Do feature discovery from all configured sources.
|
||||
for _, source := range sources {
|
||||
labelsFromSource, err := getFeatureLabels(source)
|
||||
labelsFromSource, err := getFeatureLabels(source, labelWhiteList)
|
||||
if err != nil {
|
||||
stderrLogger.Printf("discovery failed for source [%s]: %s", source.Name(), err.Error())
|
||||
stderrLogger.Printf("continuing ...")
|
||||
|
@ -325,11 +325,6 @@ func createFeatureLabels(sources []source.FeatureSource, labelWhiteList *regexp.
|
|||
for name, value := range labelsFromSource {
|
||||
// Log discovered feature.
|
||||
stdoutLogger.Printf("%s = %s", name, value)
|
||||
// Skip if label doesn't match labelWhiteList
|
||||
if !labelWhiteList.Match([]byte(name)) {
|
||||
stderrLogger.Printf("%s does not match the whitelist (%s) and will not be published.", name, labelWhiteList.String())
|
||||
continue
|
||||
}
|
||||
labels[name] = value
|
||||
}
|
||||
}
|
||||
|
@ -338,7 +333,7 @@ func createFeatureLabels(sources []source.FeatureSource, labelWhiteList *regexp.
|
|||
|
||||
// getFeatureLabels returns node labels for features discovered by the
|
||||
// supplied source.
|
||||
func getFeatureLabels(source source.FeatureSource) (labels Labels, err error) {
|
||||
func getFeatureLabels(source source.FeatureSource, labelWhiteList *regexp.Regexp) (labels Labels, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
stderrLogger.Printf("panic occurred during discovery of source [%s]: %v", source.Name(), r)
|
||||
|
@ -351,24 +346,33 @@ func getFeatureLabels(source source.FeatureSource) (labels Labels, err error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Prefix for labels in the default namespace
|
||||
prefix := source.Name() + "-"
|
||||
switch source.(type) {
|
||||
case local.Source:
|
||||
// Do not prefix labels from the hooks
|
||||
prefix = ""
|
||||
}
|
||||
|
||||
for k, v := range features {
|
||||
// Validate label name
|
||||
prefix := source.Name() + "-"
|
||||
switch source.(type) {
|
||||
case local.Source:
|
||||
// Do not prefix labels from the hooks
|
||||
prefix = ""
|
||||
// Split label name into namespace and name compoents. Use dummy 'ns'
|
||||
// default namespace because there is no function to validate just
|
||||
// the name part
|
||||
split := strings.SplitN(k, "/", 2)
|
||||
|
||||
label := prefix + split[0]
|
||||
nameForValidation := "ns/" + label
|
||||
nameForWhiteListing := label
|
||||
|
||||
if len(split) == 2 {
|
||||
label = k
|
||||
nameForValidation = label
|
||||
nameForWhiteListing = split[1]
|
||||
}
|
||||
|
||||
label := prefix + k
|
||||
// Validate label name. Use dummy namespace 'ns' because there is no
|
||||
// function to validate just the name part
|
||||
labelName := "ns/" + label
|
||||
// Do not use dummy namespace if there is already a namespace
|
||||
if strings.Contains(label, "/") {
|
||||
labelName = label
|
||||
}
|
||||
errs := validation.IsQualifiedName(labelName)
|
||||
// Validate label name.
|
||||
errs := validation.IsQualifiedName(nameForValidation)
|
||||
if len(errs) > 0 {
|
||||
stderrLogger.Printf("Ignoring invalid feature name '%s': %s", label, errs)
|
||||
continue
|
||||
|
@ -382,6 +386,12 @@ func getFeatureLabels(source source.FeatureSource) (labels Labels, err error) {
|
|||
continue
|
||||
}
|
||||
|
||||
// Skip if label doesn't match labelWhiteList
|
||||
if !labelWhiteList.MatchString(nameForWhiteListing) {
|
||||
stderrLogger.Printf("%q does not match the whitelist (%s) and will not be published.", nameForWhiteListing, labelWhiteList.String())
|
||||
continue
|
||||
}
|
||||
|
||||
labels[label] = value
|
||||
}
|
||||
return labels, nil
|
||||
|
|
Loading…
Reference in a new issue