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

Support for non-binary labels

Make it possible to advertise also other than simple 'true' values for
feature labels.
This commit is contained in:
Markus Lehtonen 2018-06-21 19:02:30 +03:00
parent b0fedab786
commit 56c2ab3d58
16 changed files with 99 additions and 54 deletions

View file

@ -96,6 +96,7 @@ The published node labels encode a few pieces of information:
- The source for each label (e.g. `cpuid`).
- The name of the discovered feature as it appears in the underlying
source, (e.g. `AESNI` from cpuid).
- The value of the discovered feature.
Feature label names adhere to the following pattern:
```

View file

@ -332,8 +332,8 @@ func getFeatureLabels(source source.FeatureSource) (labels Labels, err error) {
if err != nil {
return nil, err
}
for _, f := range features {
labels[fmt.Sprintf("%s-%s-%s", prefix, source.Name(), f)] = "true"
for k := range features {
labels[fmt.Sprintf("%s-%s-%s", prefix, source.Name(), k)] = fmt.Sprintf("%v", features[k])
}
return labels, nil
}

View file

@ -22,9 +22,11 @@ func TestDiscoveryWithMockSources(t *testing.T) {
Convey("When I discover features from fake source and update the node using fake client", t, func() {
mockFeatureSource := new(MockFeatureSource)
fakeFeatureSourceName := string("testSource")
fakeFeatures := []string{"testfeature1", "testfeature2", "testfeature3"}
fakeFeatureNames := []string{"testfeature1", "testfeature2", "testfeature3"}
fakeFeatures := source.Features{}
fakeFeatureLabels := Labels{}
for _, f := range fakeFeatures {
for _, f := range fakeFeatureNames {
fakeFeatures[f] = true
fakeFeatureLabels[fmt.Sprintf("%s-testSource-%s", prefix, f)] = "true"
}
fakeFeatureSource := source.FeatureSource(mockFeatureSource)

View file

@ -1,6 +1,9 @@
package main
import "github.com/stretchr/testify/mock"
import (
"github.com/kubernetes-incubator/node-feature-discovery/source"
"github.com/stretchr/testify/mock"
)
type MockFeatureSource struct {
mock.Mock
@ -23,15 +26,15 @@ func (_m *MockFeatureSource) Name() string {
// Discover provides a mock function with no input arguments
// and []string and error as the return values
func (_m *MockFeatureSource) Discover() ([]string, error) {
func (_m *MockFeatureSource) Discover() (source.Features, error) {
ret := _m.Called()
var r0 []string
if rf, ok := ret.Get(0).(func() []string); ok {
var r0 source.Features
if rf, ok := ret.Get(0).(func() source.Features); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]string)
r0 = ret.Get(0).(source.Features)
}
}

View file

@ -16,7 +16,10 @@ limitations under the License.
package cpuid
import "github.com/klauspost/cpuid"
import (
"github.com/klauspost/cpuid"
"github.com/kubernetes-incubator/node-feature-discovery/source"
)
// Source implements FeatureSource.
type Source struct{}
@ -25,7 +28,11 @@ type Source struct{}
func (s Source) Name() string { return "cpuid" }
// Discover returns feature names for all the supported CPU features.
func (s Source) Discover() ([]string, error) {
func (s Source) Discover() (source.Features, error) {
// Get the cpu features as strings
return cpuid.CPU.Features.Strings(), nil
features := source.Features{}
for _, f := range cpuid.CPU.Features.Strings() {
features[f] = true
}
return features, nil
}

View file

@ -16,6 +16,8 @@ limitations under the License.
package fake
import "github.com/kubernetes-incubator/node-feature-discovery/source"
// Source implements FeatureSource.
type Source struct{}
@ -23,11 +25,13 @@ type Source struct{}
func (s Source) Name() string { return "fake" }
// Discover returns feature names for some fake features.
func (s Source) Discover() ([]string, error) {
features := []string{}
func (s Source) Discover() (source.Features, error) {
// Adding three fake features.
features = append(features, "fakefeature1", "fakefeature2", "fakefeature3")
features := source.Features{
"fakefeature1": true,
"fakefeature2": true,
"fakefeature3": true,
}
return features, nil
}

View file

@ -19,6 +19,8 @@ package iommu
import (
"fmt"
"io/ioutil"
"github.com/kubernetes-incubator/node-feature-discovery/source"
)
// Implement FeatureSource interface
@ -26,8 +28,8 @@ type Source struct{}
func (s Source) Name() string { return "iommu" }
func (s Source) Discover() ([]string, error) {
features := []string{}
func (s Source) Discover() (source.Features, error) {
features := source.Features{}
// Check if any iommu devices are available
devices, err := ioutil.ReadDir("/sys/class/iommu/")
@ -36,7 +38,7 @@ func (s Source) Discover() ([]string, error) {
}
if len(devices) > 0 {
features = append(features, "enabled")
features["enabled"] = true
}
return features, nil

View file

@ -20,6 +20,8 @@ import (
"fmt"
"io/ioutil"
"strings"
"github.com/kubernetes-incubator/node-feature-discovery/source"
)
// Source implements FeatureSource.
@ -29,8 +31,8 @@ type Source struct{}
func (s Source) Name() string { return "memory" }
// Discover returns feature names for memory: numa if more than one memory node is present.
func (s Source) Discover() ([]string, error) {
features := []string{}
func (s Source) Discover() (source.Features, error) {
features := source.Features{}
// Find out how many nodes are online
// Multiple nodes is a sign of NUMA
@ -44,7 +46,7 @@ func (s Source) Discover() ([]string, error) {
// presence of newline requires TrimSpace
if strings.TrimSpace(string(bytes)) != "0" {
// more than one node means NUMA
features = append(features, "numa")
features["numa"] = true
}
return features, nil

View file

@ -24,6 +24,8 @@ import (
"net"
"strconv"
"strings"
"github.com/kubernetes-incubator/node-feature-discovery/source"
)
// Source implements FeatureSource.
@ -33,8 +35,8 @@ type Source struct{}
func (s Source) Name() string { return "network" }
// 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() ([]string, error) {
features := []string{}
func (s Source) Discover() (source.Features, error) {
features := source.Features{}
netInterfaces, err := net.Interfaces()
if err != nil {
return nil, fmt.Errorf("can't obtain the network interfaces details: %s", err.Error())
@ -57,7 +59,7 @@ func (s Source) Discover() ([]string, error) {
if t > 0 {
glog.Infof("SR-IOV capability is detected on the network interface: %s", netInterface.Name)
glog.Infof("%d maximum supported number of virtual functions on network interface: %s", t, netInterface.Name)
features = append(features, "sriov.capable")
features["sriov.capable"] = true
numVfsPath := "/sys/class/net/" + netInterface.Name + "/device/sriov_numvfs"
numBytes, err := ioutil.ReadFile(numVfsPath)
if err != nil {
@ -72,7 +74,7 @@ func (s Source) Discover() ([]string, error) {
}
if n > 0 {
glog.Infof("%d virtual functions configured on network interface: %s", n, netInterface.Name)
features = append(features, "sriov.configured")
features["sriov.configured"] = true
break
} else if n == 0 {
glog.Errorf("SR-IOV not configured on network interface: %s", netInterface.Name)

View file

@ -16,6 +16,8 @@ limitations under the License.
package panic_fake
import "github.com/kubernetes-incubator/node-feature-discovery/source"
// Source implements FeatureSource.
type Source struct{}
@ -23,6 +25,6 @@ type Source struct{}
func (s Source) Name() string { return "panic_fake" }
// Discover calls panic().
func (s Source) Discover() ([]string, error) {
func (s Source) Discover() (source.Features, error) {
panic("fake panic error")
}

View file

@ -23,6 +23,8 @@ import (
"os"
"path"
"strings"
"github.com/kubernetes-incubator/node-feature-discovery/source"
)
type pciDeviceInfo map[string]string
@ -48,8 +50,8 @@ type Source struct{}
func (s Source) Name() string { return "pci" }
// Discover features
func (s Source) Discover() ([]string, error) {
features := map[string]bool{}
func (s Source) Discover() (source.Features, error) {
features := source.Features{}
devs, err := detectPci()
if err != nil {
@ -100,12 +102,7 @@ func (s Source) Discover() ([]string, error) {
}
}
feature_list := []string{}
for feature := range features {
feature_list = append(feature_list, feature)
}
return feature_list, nil
return features, nil
}
// Read information of one PCI device

View file

@ -20,6 +20,8 @@ import (
"fmt"
"io/ioutil"
"runtime"
"github.com/kubernetes-incubator/node-feature-discovery/source"
)
// Source implements FeatureSource.
@ -29,8 +31,8 @@ type Source struct{}
func (s Source) Name() string { return "pstate" }
// Discover returns feature names for p-state related features such as turbo boost.
func (s Source) Discover() ([]string, error) {
features := []string{}
func (s Source) Discover() (source.Features, error) {
features := source.Features{}
// On Arm platform, the frequency boost mechanism is software-based.
// So skip pstate detection on Arm.
@ -46,7 +48,7 @@ func (s Source) Discover() ([]string, error) {
}
if bytes[0] == byte('0') {
// Turbo boost is enabled.
features = append(features, "turbo")
features["turbo"] = true
}
return features, nil

View file

@ -20,6 +20,7 @@ import (
"os/exec"
"github.com/golang/glog"
"github.com/kubernetes-incubator/node-feature-discovery/source"
)
// Source implements FeatureSource.
@ -29,15 +30,15 @@ type Source struct{}
func (s Source) Name() string { return "rdt" }
// Discover returns feature names for CMT and CAT if supported.
func (s Source) Discover() ([]string, error) {
features := []string{}
func (s Source) Discover() (source.Features, error) {
features := source.Features{}
cmd := exec.Command("bash", "-c", "mon-discovery")
if err := cmd.Run(); err != nil {
glog.Errorf("support for RDT monitoring was not detected: %v", err)
} else {
// RDT monitoring detected.
features = append(features, "RDTMON")
features["RDTMON"] = true
}
cmd = exec.Command("bash", "-c", "mon-cmt-discovery")
@ -45,7 +46,7 @@ func (s Source) Discover() ([]string, error) {
glog.Errorf("support for RDT CMT monitoring was not detected: %v", err)
} else {
// RDT CMT monitoring detected.
features = append(features, "RDTCMT")
features["RDTCMT"] = true
}
cmd = exec.Command("bash", "-c", "mon-mbm-discovery")
@ -53,7 +54,7 @@ func (s Source) Discover() ([]string, error) {
glog.Errorf("support for RDT MBM monitoring was not detected: %v", err)
} else {
// RDT MBM monitoring detected.
features = append(features, "RDTMBM")
features["RDTMBM"] = true
}
cmd = exec.Command("bash", "-c", "l3-alloc-discovery")
@ -61,7 +62,7 @@ func (s Source) Discover() ([]string, error) {
glog.Errorf("support for RDT L3 allocation was not detected: %v", err)
} else {
// RDT L3 cache allocation detected.
features = append(features, "RDTL3CA")
features["RDTL3CA"] = true
}
cmd = exec.Command("bash", "-c", "l2-alloc-discovery")
@ -69,7 +70,7 @@ func (s Source) Discover() ([]string, error) {
glog.Errorf("support for RDT L2 allocation was not detected: %v", err)
} else {
// RDT L2 cache allocation detected.
features = append(features, "RDTL2CA")
features["RDTL2CA"] = true
}
cmd = exec.Command("bash", "-c", "mem-bandwidth-alloc-discovery")
@ -77,7 +78,7 @@ func (s Source) Discover() ([]string, error) {
glog.Errorf("support for RDT Memory bandwidth allocation was not detected: %v", err)
} else {
// RDT Memory bandwidth allocation detected.
features = append(features, "RDTMBA")
features["RDTMBA"] = true
}
return features, nil

View file

@ -17,23 +17,25 @@ limitations under the License.
package selinux
import (
"io/ioutil"
"fmt"
"io/ioutil"
"github.com/kubernetes-incubator/node-feature-discovery/source"
)
type Source struct{}
func (s Source) Name() string { return "selinux" }
func (s Source) Discover() ([]string, error) {
features := []string{}
func (s Source) Discover() (source.Features, error) {
features := source.Features{}
status, err := ioutil.ReadFile("/host-sys/fs/selinux/enforce")
if err != nil {
return nil, fmt.Errorf("Failed to detect the status of selinux, please check if the system supports selinux and make sure /sys on the host is mounted into the container: %s", err.Error())
}
if status[0] == byte('1') {
// selinux is enabled.
features = append(features, "enabled")
features["enabled"] = true
}
return features, nil
}

View file

@ -16,11 +16,27 @@ limitations under the License.
package source
// Value of a feature
type FeatureValue interface {
}
// Boolean feature value
type BoolFeatureValue bool
func (b BoolFeatureValue) String() string {
if b == true {
return "true"
}
return "false"
}
type Features map[string]FeatureValue
// FeatureSource represents a source of a discovered node feature.
type FeatureSource interface {
// Name returns a friendly name for this source of node feature.
Name() string
// Discover returns discovered features for this node.
Discover() ([]string, error)
Discover() (Features, error)
}

View file

@ -19,6 +19,8 @@ package storage
import (
"fmt"
"io/ioutil"
"github.com/kubernetes-incubator/node-feature-discovery/source"
)
// Source implements FeatureSource.
@ -28,8 +30,8 @@ type Source struct{}
func (s Source) Name() string { return "storage" }
// Discover returns feature names for storage: nonrotationaldisk if any SSD drive present.
func (s Source) Discover() ([]string, error) {
features := []string{}
func (s Source) Discover() (source.Features, error) {
features := source.Features{}
// Check if there is any non-rotational block devices attached to the node
blockdevices, err := ioutil.ReadDir("/sys/block/")
@ -42,7 +44,7 @@ func (s Source) Discover() ([]string, error) {
}
if bytes[0] == byte('0') {
// Non-rotational storage is present, add label.
features = append(features, "nonrotationaldisk")
features["nonrotationaldisk"] = true
break
}
}