1
0
Fork 0
mirror of https://github.com/kubernetes-sigs/node-feature-discovery.git synced 2025-03-28 02:37:11 +00:00

Merge pull request #432 from marquiz/devel/config-watch

nfd-worker: use fsnotify for watching for config file changes
This commit is contained in:
Kubernetes Prow Robot 2021-02-11 02:14:15 -08:00 committed by GitHub
commit a8c7135eda
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 95 additions and 21 deletions

1
go.mod
View file

@ -4,6 +4,7 @@ go 1.15
require (
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
github.com/fsnotify/fsnotify v1.4.9
github.com/golang/protobuf v1.4.3
github.com/klauspost/cpuid/v2 v2.0.2
github.com/onsi/ginkgo v1.11.0

View file

@ -24,10 +24,12 @@ import (
"io/ioutil"
"log"
"os"
"path/filepath"
"regexp"
"strings"
"time"
"github.com/fsnotify/fsnotify"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
@ -178,6 +180,40 @@ func NewNfdWorker(args Args) (NfdWorker, error) {
return nfd, nil
}
func addConfigWatch(path string) (*fsnotify.Watcher, map[string]struct{}, error) {
paths := make(map[string]struct{})
// Create watcher
w, err := fsnotify.NewWatcher()
if err != nil {
return w, paths, fmt.Errorf("failed to create fsnotify watcher: %v", err)
}
// Add watches for all directory components so that we catch e.g. renames
// upper in the tree
added := false
for p := path; ; p = filepath.Dir(p) {
if err := w.Add(p); err != nil {
stdoutLogger.Printf("failed to add fsnotify watch for %q: %v", p, err)
} else {
stdoutLogger.Printf("added fsnotify watch %q", p)
added = true
}
paths[p] = struct{}{}
if filepath.Dir(p) == p {
break
}
}
if !added {
// Want to be sure that we watch something
return w, paths, fmt.Errorf("failed to add any watch")
}
return w, paths, nil
}
// Run NfdWorker client. Returns if a fatal error is encountered, or, after
// one request if OneShot is set to 'true' in the worker args.
func (w *nfdWorker) Run() error {
@ -191,34 +227,71 @@ func (w *nfdWorker) Run() error {
}
defer w.disconnect()
// Create watcher for config file and read initial configuration
configFilePath := filepath.Clean(w.args.ConfigFile)
configWatch, paths, err := addConfigWatch(configFilePath)
if err != nil {
return (err)
}
w.configure(configFilePath, w.args.Options)
labelTrigger := time.After(0)
var configTrigger <-chan time.Time
for {
// Parse and apply configuration
w.configure(w.args.ConfigFile, w.args.Options)
select {
case <-labelTrigger:
// Get the set of feature labels.
labels := createFeatureLabels(w.sources, w.labelWhiteList)
// Get the set of feature labels.
labels := createFeatureLabels(w.sources, w.labelWhiteList)
// Update the node with the feature labels.
if w.client != nil {
err := advertiseFeatureLabels(w.client, labels)
if err != nil {
return fmt.Errorf("failed to advertise labels: %s", err.Error())
// Update the node with the feature labels.
if w.client != nil {
err := advertiseFeatureLabels(w.client, labels)
if err != nil {
return fmt.Errorf("failed to advertise labels: %s", err.Error())
}
}
}
if w.args.Oneshot {
break
}
if w.args.Oneshot {
return nil
}
if w.args.SleepInterval > 0 {
time.Sleep(w.args.SleepInterval)
} else {
w.disconnect()
// Sleep forever
select {}
if w.args.SleepInterval > 0 {
labelTrigger = time.After(w.args.SleepInterval)
}
case e := <-configWatch.Events:
name := filepath.Clean(e.Name)
// If any of our paths (directories or the file itself) change
if _, ok := paths[name]; ok {
stdoutLogger.Printf("fsnotify event in %q detected, reconfiguring fsnotify and reloading configuration", name)
// Blindly remove existing watch and add a new one
if err := configWatch.Close(); err != nil {
stderrLogger.Printf("WARNING: failed to close fsnotify watcher: %v", err)
}
configWatch, paths, err = addConfigWatch(configFilePath)
if err != nil {
return err
}
// Rate limiter. In certain filesystem operations we get
// numerous events in quick succession and we only want one
// config re-load
configTrigger = time.After(time.Second)
}
case e := <-configWatch.Errors:
stderrLogger.Printf("ERROR: config file watcher error: %v", e)
case <-configTrigger:
w.configure(configFilePath, w.args.Options)
// Always re-label after a re-config event. This way the new config
// comes into effect even if the sleep interval is long (or infinite)
labelTrigger = time.After(0)
}
}
return nil
}
// connect creates a client connection to the NFD master