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:
parent
b0fedab786
commit
56c2ab3d58
16 changed files with 99 additions and 54 deletions
|
@ -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:
|
||||
```
|
||||
|
|
4
main.go
4
main.go
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue