mirror of
https://github.com/kubernetes-sigs/node-feature-discovery.git
synced 2025-03-31 04:04:51 +00:00
Implement kernel config detection
This implementation only detects kconfig options ("NO_HZ", "NO_HZ_IDLE", "NO_HZ_FULL" and "PREEMPT"). The corresponding node labels will be node.alpha.kubernetes-incubator.io/nfd-kernel-config.<option name> Currently, only bool and tristate (i.e. '=y' or '=m') kernel config options are supported. Other kconfig types (e.g. string or int) are simply ignored. If the kconfig flag is set to '=y' or '=m', the corresponding node label will be present and it's value will be 'true'.
This commit is contained in:
parent
607e95f290
commit
ce129aef88
4 changed files with 113 additions and 8 deletions
17
README.md
17
README.md
|
@ -116,6 +116,7 @@ the only label value published for features is the string `"true"`._
|
||||||
"feature.node.kubernetes.io/node-feature-discovery.version": "v0.3.0",
|
"feature.node.kubernetes.io/node-feature-discovery.version": "v0.3.0",
|
||||||
"feature.node.kubernetes.io/nfd-cpuid-<feature-name>": "true",
|
"feature.node.kubernetes.io/nfd-cpuid-<feature-name>": "true",
|
||||||
"feature.node.kubernetes.io/nfd-iommu-<feature-name>": "true",
|
"feature.node.kubernetes.io/nfd-iommu-<feature-name>": "true",
|
||||||
|
"feature.node.kubernetes.io/kernel-config.<option-name>": "true",
|
||||||
"feature.node.kubernetes.io/nfd-kernel-version.<version component>": "<version number>",
|
"feature.node.kubernetes.io/nfd-kernel-version.<version component>": "<version number>",
|
||||||
"feature.node.kubernetes.io/nfd-memory-<feature-name>": "true",
|
"feature.node.kubernetes.io/nfd-memory-<feature-name>": "true",
|
||||||
"feature.node.kubernetes.io/nfd-network-<feature-name>": "true",
|
"feature.node.kubernetes.io/nfd-network-<feature-name>": "true",
|
||||||
|
@ -171,12 +172,16 @@ such as restricting discovered features with the --label-whitelist option._
|
||||||
|
|
||||||
### Kernel Features
|
### Kernel Features
|
||||||
|
|
||||||
| Feature | Attribute | Description |
|
| Feature | Attribute | Description |
|
||||||
| ------- | --------- | ------------------------------------------------------ |
|
| ------- | ----------- | ---------------------------------------------------- |
|
||||||
| version | full | Full kernel version as reported by `/proc/sys/kernel/osrelease` (e.g. '4.5.6-7-g123abcde')
|
| config | NO_HZ | Kernel config option is enabled
|
||||||
| <br> | major | First component of the kernel version (e.g. '4')
|
| <br> | NO_HZ_FULL |
|
||||||
| <br> | minor | Second component of the kernel version (e.g. '5')
|
| <br> | NO_HZ_IDLE |
|
||||||
| <br> | revision | Third component of the kernel version (e.g. '6')
|
| <br> | PREEMPT |
|
||||||
|
| version | full | Full kernel version as reported by `/proc/sys/kernel/osrelease` (e.g. '4.5.6-7-g123abcde')
|
||||||
|
| <br> | major | First component of the kernel version (e.g. '4')
|
||||||
|
| <br> | minor | Second component of the kernel version (e.g. '5')
|
||||||
|
| <br> | revision | Third component of the kernel version (e.g. '6')
|
||||||
|
|
||||||
### Local (User-specific Features)
|
### Local (User-specific Features)
|
||||||
|
|
||||||
|
|
|
@ -26,9 +26,15 @@ spec:
|
||||||
args:
|
args:
|
||||||
- "--sleep-interval=60s"
|
- "--sleep-interval=60s"
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
|
- name: host-boot
|
||||||
|
mountPath: "/host-boot"
|
||||||
|
readOnly: true
|
||||||
- name: host-sys
|
- name: host-sys
|
||||||
mountPath: "/host-sys"
|
mountPath: "/host-sys"
|
||||||
volumes:
|
volumes:
|
||||||
|
- name: host-boot
|
||||||
|
hostPath:
|
||||||
|
path: "/boot"
|
||||||
- name: host-sys
|
- name: host-sys
|
||||||
hostPath:
|
hostPath:
|
||||||
path: "/sys"
|
path: "/sys"
|
||||||
|
|
|
@ -28,10 +28,16 @@ spec:
|
||||||
- containerPort: 7156
|
- containerPort: 7156
|
||||||
hostPort: 7156
|
hostPort: 7156
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
|
- name: host-boot
|
||||||
|
mountPath: "/host-boot"
|
||||||
|
readOnly: true
|
||||||
- name: host-sys
|
- name: host-sys
|
||||||
mountPath: "/host-sys"
|
mountPath: "/host-sys"
|
||||||
restartPolicy: Never
|
restartPolicy: Never
|
||||||
volumes:
|
volumes:
|
||||||
|
- name: host-boot
|
||||||
|
hostPath:
|
||||||
|
path: "/boot"
|
||||||
- name: host-sys
|
- name: host-sys
|
||||||
hostPath:
|
hostPath:
|
||||||
path: "/sys"
|
path: "/sys"
|
||||||
|
|
|
@ -17,14 +17,27 @@ limitations under the License.
|
||||||
package kernel
|
package kernel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"compress/gzip"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
|
||||||
"github.com/kubernetes-incubator/node-feature-discovery/source"
|
"github.com/kubernetes-incubator/node-feature-discovery/source"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Default kconfig flags
|
||||||
|
var defaultKconfigFlags = [...]string{
|
||||||
|
"NO_HZ",
|
||||||
|
"NO_HZ_IDLE",
|
||||||
|
"NO_HZ_FULL",
|
||||||
|
"PREEMPT",
|
||||||
|
}
|
||||||
|
|
||||||
|
var logger = log.New(os.Stderr, "", log.LstdFlags)
|
||||||
|
|
||||||
// Implement FeatureSource interface
|
// Implement FeatureSource interface
|
||||||
type Source struct{}
|
type Source struct{}
|
||||||
|
|
||||||
|
@ -36,12 +49,26 @@ func (s Source) Discover() (source.Features, error) {
|
||||||
// Read kernel version
|
// Read kernel version
|
||||||
version, err := parseVersion()
|
version, err := parseVersion()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Failed to get kernel version: %v", err)
|
logger.Printf("ERROR: Failed to get kernel version: %s", err)
|
||||||
} else {
|
} else {
|
||||||
for key := range version {
|
for key := range version {
|
||||||
features["version."+key] = version[key]
|
features["version."+key] = version[key]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read kconfig
|
||||||
|
kconfig, err := parseKconfig()
|
||||||
|
if err != nil {
|
||||||
|
logger.Printf("ERROR: Failed to read kconfig: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check flags
|
||||||
|
for _, flag := range defaultKconfigFlags {
|
||||||
|
if _, ok := kconfig[flag]; ok {
|
||||||
|
features["config."+flag] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return features, nil
|
return features, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,3 +97,64 @@ func parseVersion() (map[string]string, error) {
|
||||||
|
|
||||||
return version, nil
|
return version, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read gzipped kernel config
|
||||||
|
func readKconfigGzip(filename string) ([]byte, error) {
|
||||||
|
// Open file for reading
|
||||||
|
f, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
// Uncompress data
|
||||||
|
r, err := gzip.NewReader(f)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer r.Close()
|
||||||
|
|
||||||
|
return ioutil.ReadAll(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read kconfig into a map
|
||||||
|
func parseKconfig() (map[string]bool, error) {
|
||||||
|
kconfig := map[string]bool{}
|
||||||
|
raw := []byte(nil)
|
||||||
|
|
||||||
|
// First, try to read from /proc as this is the most reliable source
|
||||||
|
raw, err := readKconfigGzip("/proc/config.gz")
|
||||||
|
if err != nil {
|
||||||
|
logger.Printf("ERROR: Failed to read /proc/config.gz: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last, try to read from /boot/
|
||||||
|
if raw == nil {
|
||||||
|
// Get kernel version
|
||||||
|
unameRaw, err := ioutil.ReadFile("/proc/sys/kernel/osrelease")
|
||||||
|
uname := strings.TrimSpace(string(unameRaw))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Read kconfig
|
||||||
|
raw, err = ioutil.ReadFile("/host-boot/config-" + uname)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regexp for matching kconfig flags
|
||||||
|
re := regexp.MustCompile(`^CONFIG_(?P<flag>\w+)=(?P<value>.+)`)
|
||||||
|
|
||||||
|
// Process data, line-by-line
|
||||||
|
lines := bytes.Split(raw, []byte("\n"))
|
||||||
|
for _, line := range lines {
|
||||||
|
if m := re.FindStringSubmatch(string(line)); m != nil {
|
||||||
|
if m[2] == "y" || m[2] == "m" {
|
||||||
|
kconfig[m[1]] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return kconfig, nil
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue