mirror of
https://github.com/kubernetes-sigs/node-feature-discovery.git
synced 2024-12-14 11:57:51 +00:00
Drop support for hooks
Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
This commit is contained in:
parent
65b5e0c255
commit
62f4eddce6
10 changed files with 19 additions and 234 deletions
|
@ -19,9 +19,6 @@
|
|||
- name: host-lib
|
||||
hostPath:
|
||||
path: "/lib"
|
||||
- name: source-d
|
||||
hostPath:
|
||||
path: "/etc/kubernetes/node-feature-discovery/source.d/"
|
||||
- name: features-d
|
||||
hostPath:
|
||||
path: "/etc/kubernetes/node-feature-discovery/features.d/"
|
||||
|
@ -50,9 +47,6 @@
|
|||
- name: host-lib
|
||||
mountPath: "/host-lib"
|
||||
readOnly: true
|
||||
- name: source-d
|
||||
mountPath: "/etc/kubernetes/node-feature-discovery/source.d/"
|
||||
readOnly: true
|
||||
- name: features-d
|
||||
mountPath: "/etc/kubernetes/node-feature-discovery/features.d/"
|
||||
readOnly: true
|
||||
|
|
|
@ -77,8 +77,6 @@
|
|||
# - "class"
|
||||
# - "vendor"
|
||||
# - "device"
|
||||
# local:
|
||||
# hooksEnabled: false
|
||||
# custom:
|
||||
# # The following feature demonstrates the capabilities of the matchFeatures
|
||||
# - name: "my custom rule"
|
||||
|
|
|
@ -141,9 +141,6 @@ spec:
|
|||
mountPath: "/host-usr/src"
|
||||
readOnly: true
|
||||
{{- end }}
|
||||
- name: source-d
|
||||
mountPath: "/etc/kubernetes/node-feature-discovery/source.d/"
|
||||
readOnly: true
|
||||
- name: features-d
|
||||
mountPath: "/etc/kubernetes/node-feature-discovery/features.d/"
|
||||
readOnly: true
|
||||
|
@ -174,9 +171,6 @@ spec:
|
|||
hostPath:
|
||||
path: "/usr/src"
|
||||
{{- end }}
|
||||
- name: source-d
|
||||
hostPath:
|
||||
path: "/etc/kubernetes/node-feature-discovery/source.d/"
|
||||
- name: features-d
|
||||
hostPath:
|
||||
path: "/etc/kubernetes/node-feature-discovery/features.d/"
|
||||
|
|
|
@ -255,8 +255,6 @@ worker:
|
|||
# - "class"
|
||||
# - "vendor"
|
||||
# - "device"
|
||||
# local:
|
||||
# hooksEnabled: false
|
||||
# custom:
|
||||
# # The following feature demonstrates the capabilities of the matchFeatures
|
||||
# - name: "my custom rule"
|
||||
|
|
|
@ -24,8 +24,8 @@ For backwards compatibility a container image tag with suffix `-minimal`
|
|||
## Full
|
||||
|
||||
This image is based on [debian:bookworm-slim](https://hub.docker.com/_/debian)
|
||||
and contains a full Linux system for running shell-based nfd-worker hooks and
|
||||
doing live debugging and diagnosis of the NFD images.
|
||||
and contains a full Linux system for doing live debugging and diagnosis
|
||||
of the NFD images.
|
||||
|
||||
The container image tag has suffix `-full`
|
||||
(e.g. `{{ site.container_image }}-full`).
|
||||
|
|
|
@ -71,7 +71,7 @@ Feature discovery is divided into domain-specific feature sources:
|
|||
- System
|
||||
- USB
|
||||
- Custom (rule-based custom features)
|
||||
- Local (hooks for user-specific features)
|
||||
- Local (features files)
|
||||
|
||||
Each feature source is responsible for detecting a set of features which. in
|
||||
turn, are turned into node feature labels. Feature labels are prefixed with
|
||||
|
|
|
@ -304,32 +304,6 @@ sources:
|
|||
|
||||
### sources.local
|
||||
|
||||
### sources.local.hooksEnabled
|
||||
|
||||
**DEPRECATED**: Hooks are DEPRECATED since v0.12.0 release and support (and
|
||||
this configuration option) will be removed in NFD v0.17. Use
|
||||
[feature files](../usage//customization-guide.md#feature-files) instead.
|
||||
|
||||
Configuration option to disable/enable hooks execution. Disabled by default.
|
||||
|
||||
> **NOTE:** The default NFD container image only supports statically linked
|
||||
> binaries. Use the [full](../deployment/image-variants.md#full) image variant
|
||||
> for a slightly more extensive environment that additionally supports bash and
|
||||
> perl runtimes.
|
||||
|
||||
GitHub tracking issue:
|
||||
[Drop support for hooks (#856)](https://github.com/kubernetes-sigs/node-feature-discovery/issues/856).
|
||||
|
||||
Default: false
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
sources:
|
||||
local:
|
||||
hooksEnabled: true
|
||||
```
|
||||
|
||||
### sources.pci
|
||||
|
||||
#### sources.pci.deviceClassWhitelist
|
||||
|
|
|
@ -26,7 +26,7 @@ labeling:
|
|||
- [`NodeFeatureRule`](#nodefeaturerule-custom-resource) objects provide a way to
|
||||
deploy custom labeling rules via the Kubernetes API.
|
||||
- [`local`](#local-feature-source) feature source of nfd-worker creates
|
||||
labels by reading text files and executing hooks.
|
||||
labels by reading text files.
|
||||
- [`custom`](#custom-feature-source) feature source of nfd-worker creates
|
||||
labels based on user-specified rules.
|
||||
|
||||
|
@ -232,13 +232,12 @@ point for external feature detectors. It provides a mechanism for pluggable
|
|||
extensions, allowing the creation of new user-specific features and even
|
||||
overriding built-in labels.
|
||||
|
||||
The `local` feature source has two methods for detecting features, feature
|
||||
files and hooks (hooks are deprecated and slated for removal in NFD v0.17). The
|
||||
features discovered by the `local` source can further be used in label rules
|
||||
specified in [`NodeFeatureRule`](#nodefeaturerule-custom-resource) objects and
|
||||
The `local` feature source uses feature files. The features discovered by the
|
||||
`local` source can further be used in label rules specified in
|
||||
[`NodeFeatureRule`](#nodefeaturerule-custom-resource) objects and
|
||||
the [`custom`](#custom-feature-source) feature source.
|
||||
|
||||
> **NOTE:** Be careful when creating and/or updating hook or feature files
|
||||
> **NOTE:** Be careful when creating and/or updating feature files
|
||||
> while NFD is running. To avoid race conditions you should write
|
||||
> into a temporary file, and atomically create/update the original file by
|
||||
> doing a file rename operation. NFD ignores dot files,
|
||||
|
@ -250,9 +249,7 @@ the [`custom`](#custom-feature-source) feature source.
|
|||
|
||||
Consider a plaintext file
|
||||
`/etc/kubernetes/node-feature-discovery/features.d/my-features`
|
||||
having the following contents (or alternatively a shell script
|
||||
`/etc/kubernetes/node-feature-discovery/source.d/my-hook.sh` having the
|
||||
following stdout output):
|
||||
having the following contents:
|
||||
|
||||
```plaintext
|
||||
feature.node.kubernetes.io/my-feature.1
|
||||
|
@ -274,47 +271,9 @@ The `local` source reads files found in
|
|||
`/etc/kubernetes/node-feature-discovery/features.d/`. File content is parsed
|
||||
and translated into node labels, see the [input format below](#input-format).
|
||||
|
||||
### Hooks
|
||||
|
||||
**DEPRECATED** Hooks are deprecated and will be completely removed in NFD
|
||||
v0.17.
|
||||
|
||||
The `local` source executes hooks found in
|
||||
`/etc/kubernetes/node-feature-discovery/source.d/`. The hook files must be
|
||||
executable and they are supposed to print all discovered features in `stdout`.
|
||||
Since NFD v0.13 the default container image only supports statically linked ELF
|
||||
binaries.
|
||||
|
||||
`stderr` output of hooks is propagated to NFD log so it can be used for
|
||||
debugging and logging.
|
||||
|
||||
NFD tries to execute any regular files found from the hooks directory.
|
||||
Any additional data files the hook might need (e.g. a configuration file)
|
||||
should be placed in a separate directory to avoid NFD unnecessarily
|
||||
trying to execute them. A subdirectory under the hooks directory can be used,
|
||||
for example `/etc/kubernetes/node-feature-discovery/source.d/conf/`.
|
||||
|
||||
> **NOTE:** Starting from release v0.14 hooks are disabled by default and can
|
||||
> be enabled via `sources.local.hooksEnabled` field in the worker
|
||||
> configuration.
|
||||
|
||||
```yaml
|
||||
sources:
|
||||
local:
|
||||
hooksEnabled: true # true by default at this point
|
||||
```
|
||||
|
||||
> **NOTE:** NFD will blindly run any executables placed/mounted in the hooks
|
||||
> directory. It is the user's responsibility to review the hooks for e.g.
|
||||
> possible security implications.
|
||||
>
|
||||
> **NOTE:** The [full](../deployment/image-variants.md#full) image variant
|
||||
> provides backwards-compatibility with older NFD versions by including a more
|
||||
> expanded environment, supporting bash and perl runtimes.
|
||||
|
||||
### Input format
|
||||
|
||||
The hook stdout and feature files are expected to contain features in simple
|
||||
The feature files are expected to contain features in simple
|
||||
key-value pairs, separated by newlines:
|
||||
|
||||
```plaintext
|
||||
|
@ -410,19 +369,16 @@ vendor.io/my-feature=value
|
|||
### Mounts
|
||||
|
||||
The standard NFD deployments contain `hostPath` mounts for
|
||||
`/etc/kubernetes/node-feature-discovery/source.d/` and
|
||||
`/etc/kubernetes/node-feature-discovery/features.d/`, making these directories
|
||||
from the host available inside the nfd-worker container.
|
||||
|
||||
#### Injecting labels from other pods
|
||||
|
||||
One use case for the feature files and hooks is detecting features in other
|
||||
One use case for the feature files is detecting features in other
|
||||
Pods outside NFD, e.g. in Kubernetes device plugins. By using the same
|
||||
`hostPath` mounts for `/etc/kubernetes/node-feature-discovery/source.d/` and
|
||||
`/etc/kubernetes/node-feature-discovery/features.d/` in the side-car (e.g.
|
||||
device plugin) creates a shared area for deploying feature files and hooks to
|
||||
NFD. NFD periodically scans the directories and reads any feature files and
|
||||
runs any hooks it finds.
|
||||
`hostPath` mounts `/etc/kubernetes/node-feature-discovery/features.d/`
|
||||
in the side-car (e.g. device plugin) creates a shared area for
|
||||
deploying feature files to NFD.
|
||||
|
||||
## Custom feature source
|
||||
|
||||
|
@ -1000,8 +956,8 @@ The following features are available for matching:
|
|||
| | | **`major`** | int | First component of the kernel version (e.g. ‘4') |
|
||||
| | | **`minor`** | int | Second component of the kernel version (e.g. ‘5') |
|
||||
| | | **`revision`** | int | Third component of the kernel version (e.g. ‘6') |
|
||||
| **`local.label`** | attribute | | | Labels from feature files and hooks, i.e. labels from the [*local* feature source](#local-feature-source) |
|
||||
| **`local.feature`** | attribute | | | Features from feature files and hooks, i.e. features from the [*local* feature source](#local-feature-source) |
|
||||
| **`local.label`** | attribute | | | Labels from feature files, i.e. labels from the [*local* feature source](#local-feature-source) |
|
||||
| **`local.feature`** | attribute | | | Features from feature files, i.e. features from the [*local* feature source](#local-feature-source) |
|
||||
| | | **`<label-name>`** | string | Label `<label-name>` created by the local feature source, value equals the value of the label |
|
||||
| **`memory.nv`** | instance | | | NVDIMM devices present in the system |
|
||||
| | | **`<sysfs-attribute>`** | string | Value of the sysfs device attribute, available attributes: `devtype`, `mode` |
|
||||
|
|
|
@ -572,7 +572,7 @@ func getFeatureLabels(source source.LabelSource, labelWhiteList regexp.Regexp) (
|
|||
name := k
|
||||
switch sourceName := source.Name(); sourceName {
|
||||
case "local", "custom":
|
||||
// No mangling of labels from the custom rules, hooks or feature files
|
||||
// No mangling of labels from the custom rules or feature files
|
||||
default:
|
||||
// Prefix for labels from other sources
|
||||
if !strings.Contains(name, "/") {
|
||||
|
|
|
@ -20,7 +20,6 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -64,7 +63,6 @@ const MaxFeatureFileSize = 65536
|
|||
// Config
|
||||
var (
|
||||
featureFilesDir = "/etc/kubernetes/node-feature-discovery/features.d/"
|
||||
hookDir = "/etc/kubernetes/node-feature-discovery/source.d/"
|
||||
)
|
||||
|
||||
// localSource implements the FeatureSource and LabelSource interfaces.
|
||||
|
@ -74,7 +72,6 @@ type localSource struct {
|
|||
}
|
||||
|
||||
type Config struct {
|
||||
HooksEnabled bool `json:"hooksEnabled,omitempty"`
|
||||
}
|
||||
|
||||
// parsingOpts contains options used for directives parsing
|
||||
|
@ -86,7 +83,7 @@ type parsingOpts struct {
|
|||
|
||||
// Singleton source instance
|
||||
var (
|
||||
src = localSource{config: newDefaultConfig()}
|
||||
src = localSource{}
|
||||
_ source.FeatureSource = &src
|
||||
_ source.LabelSource = &src
|
||||
_ source.ConfigurableSource = &src
|
||||
|
@ -96,7 +93,7 @@ var (
|
|||
func (s *localSource) Name() string { return Name }
|
||||
|
||||
// NewConfig method of the LabelSource interface
|
||||
func (s *localSource) NewConfig() source.Config { return newDefaultConfig() }
|
||||
func (s *localSource) NewConfig() source.Config { return &Config{} }
|
||||
|
||||
// GetConfig method of the LabelSource interface
|
||||
func (s *localSource) GetConfig() source.Config { return s.config }
|
||||
|
@ -125,13 +122,6 @@ func (s *localSource) GetLabels() (source.FeatureLabels, error) {
|
|||
return labels, nil
|
||||
}
|
||||
|
||||
// newDefaultConfig returns a new config with pre-populated defaults
|
||||
func newDefaultConfig() *Config {
|
||||
return &Config{
|
||||
HooksEnabled: false,
|
||||
}
|
||||
}
|
||||
|
||||
// Discover method of the FeatureSource interface
|
||||
func (s *localSource) Discover() error {
|
||||
s.features = nfdv1alpha1.NewFeatures()
|
||||
|
@ -141,33 +131,6 @@ func (s *localSource) Discover() error {
|
|||
klog.ErrorS(err, "failed to read feature files")
|
||||
}
|
||||
|
||||
if s.config.HooksEnabled {
|
||||
|
||||
klog.InfoS("starting hooks...")
|
||||
klog.InfoS("NOTE: hooks are deprecated and will be completely removed in a future release.")
|
||||
|
||||
featuresFromHooks, labelsFromHooks, err := getFeaturesFromHooks()
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "failed to run hooks")
|
||||
}
|
||||
|
||||
// Merge features from hooks and files
|
||||
for k, v := range featuresFromHooks {
|
||||
if old, ok := featuresFromFiles[k]; ok {
|
||||
klog.InfoS("overriding feature value", "featureKey", k, "oldValue", old, "newValue", v)
|
||||
}
|
||||
featuresFromFiles[k] = v
|
||||
}
|
||||
|
||||
// Merge labels from hooks and files
|
||||
for k, v := range labelsFromHooks {
|
||||
if old, ok := labelsFromFiles[k]; ok {
|
||||
klog.InfoS("overriding label value", "labelKey", k, "oldValue", old, "newValue", v)
|
||||
}
|
||||
labelsFromFiles[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
s.features.Attributes[LabelFeature] = nfdv1alpha1.NewAttributeFeatures(labelsFromFiles)
|
||||
s.features.Attributes[RawFeature] = nfdv1alpha1.NewAttributeFeatures(featuresFromFiles)
|
||||
|
||||
|
@ -279,98 +242,6 @@ func updateFeatures(m map[string]string, lineSplit []string) {
|
|||
}
|
||||
}
|
||||
|
||||
// Run all hooks and get features
|
||||
func getFeaturesFromHooks() (map[string]string, map[string]string, error) {
|
||||
|
||||
features := make(map[string]string)
|
||||
labels := make(map[string]string)
|
||||
|
||||
files, err := os.ReadDir(hookDir)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
klog.InfoS("hook directory does not exist", "path", hookDir)
|
||||
return features, labels, nil
|
||||
}
|
||||
return features, labels, fmt.Errorf("unable to access %v: %w", hookDir, err)
|
||||
}
|
||||
if len(files) > 0 {
|
||||
klog.InfoS("hooks are DEPRECATED since v0.12.0 and support will be removed in a future release; use feature files instead")
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
fileName := file.Name()
|
||||
// ignore hidden feature file
|
||||
if strings.HasPrefix(fileName, ".") {
|
||||
continue
|
||||
}
|
||||
lines, err := runHook(fileName)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "failed to run hook", "fileName", fileName)
|
||||
continue
|
||||
}
|
||||
|
||||
// Append features
|
||||
fileFeatures, fileLabels := parseFeatureFile(lines, fileName)
|
||||
klog.V(4).InfoS("hook executed", "fileName", fileName, "features", utils.DelayedDumper(fileFeatures), "labels", utils.DelayedDumper(fileLabels))
|
||||
for k, v := range fileFeatures {
|
||||
if old, ok := features[k]; ok {
|
||||
klog.InfoS("overriding feature value from another hook", "featureKey", k, "oldValue", old, "newValue", v, "fileName", fileName)
|
||||
}
|
||||
features[k] = v
|
||||
}
|
||||
|
||||
for k, v := range fileLabels {
|
||||
if old, ok := labels[k]; ok {
|
||||
klog.InfoS("overriding label value from another hook", "labelKey", k, "oldValue", old, "newValue", v, "fileName", fileName)
|
||||
}
|
||||
labels[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return features, labels, nil
|
||||
}
|
||||
|
||||
// Run one hook
|
||||
func runHook(file string) ([][]byte, error) {
|
||||
var lines [][]byte
|
||||
|
||||
path := filepath.Join(hookDir, file)
|
||||
filestat, err := os.Stat(path)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "failed to get filestat, skipping hook", "path", path)
|
||||
return lines, err
|
||||
}
|
||||
|
||||
if filestat.Mode().IsRegular() {
|
||||
cmd := exec.Command(path)
|
||||
var stdout bytes.Buffer
|
||||
var stderr bytes.Buffer
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
|
||||
// Run hook
|
||||
err = cmd.Run()
|
||||
|
||||
// Forward stderr to our logger
|
||||
errLines := bytes.Split(stderr.Bytes(), []byte("\n"))
|
||||
for i, line := range errLines {
|
||||
if i == len(errLines)-1 && len(line) == 0 {
|
||||
// Don't print the last empty string
|
||||
break
|
||||
}
|
||||
klog.InfoS(fmt.Sprintf("%s: %s", file, line))
|
||||
}
|
||||
|
||||
// Do not return any lines if an error occurred
|
||||
if err != nil {
|
||||
return lines, err
|
||||
}
|
||||
lines = bytes.Split(stdout.Bytes(), []byte("\n"))
|
||||
}
|
||||
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
// Read all files to get features
|
||||
func getFeaturesFromFiles() (map[string]string, map[string]string, error) {
|
||||
features := make(map[string]string)
|
||||
|
|
Loading…
Reference in a new issue