mirror of
https://github.com/NVIDIA/nvidia-container-toolkit
synced 2024-11-25 21:39:10 +00:00
Add --watch option to create-dev-char-symlinks
This change adds a --watch option to the create-dev-char-symlinks hook. This installs an fsnotify watcher that creates symlinks for ADDED device nodes under /dev/char. Signed-off-by: Evan Lezar <elezar@nvidia.com>
This commit is contained in:
parent
be0e4667a5
commit
f9330a4c2c
@ -19,8 +19,12 @@ package devchar
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/fsnotify/fsnotify"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
@ -37,6 +41,7 @@ type config struct {
|
|||||||
devCharPath string
|
devCharPath string
|
||||||
driverRoot string
|
driverRoot string
|
||||||
dryRun bool
|
dryRun bool
|
||||||
|
watch bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCommand constructs a hook sub-command with the specified logger
|
// NewCommand constructs a hook sub-command with the specified logger
|
||||||
@ -75,6 +80,13 @@ func (m command) build() *cli.Command {
|
|||||||
Destination: &cfg.driverRoot,
|
Destination: &cfg.driverRoot,
|
||||||
EnvVars: []string{"DRIVER_ROOT"},
|
EnvVars: []string{"DRIVER_ROOT"},
|
||||||
},
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "watch",
|
||||||
|
Usage: "If set, the command will watch for changes to the driver root and recreate the symlinks when changes are detected.",
|
||||||
|
Value: false,
|
||||||
|
Destination: &cfg.watch,
|
||||||
|
EnvVars: []string{"WATCH"},
|
||||||
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "dry-run",
|
Name: "dry-run",
|
||||||
Usage: "If set, the command will not create any symlinks.",
|
Usage: "If set, the command will not create any symlinks.",
|
||||||
@ -88,17 +100,67 @@ func (m command) build() *cli.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m command) run(c *cli.Context, cfg *config) error {
|
func (m command) run(c *cli.Context, cfg *config) error {
|
||||||
|
|
||||||
|
var watcher *fsnotify.Watcher
|
||||||
|
var sigs chan os.Signal
|
||||||
|
|
||||||
|
if cfg.watch {
|
||||||
|
watcher, err := newFSWatcher(filepath.Join(cfg.driverRoot, "dev"))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create FS watcher: %v", err)
|
||||||
|
}
|
||||||
|
defer watcher.Close()
|
||||||
|
|
||||||
|
sigs = newOSWatcher(syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
||||||
|
}
|
||||||
|
|
||||||
l := NewSymlinkCreator(
|
l := NewSymlinkCreator(
|
||||||
WithLogger(m.logger),
|
WithLogger(m.logger),
|
||||||
WithDevCharPath(cfg.devCharPath),
|
WithDevCharPath(cfg.devCharPath),
|
||||||
WithDriverRoot(cfg.driverRoot),
|
WithDriverRoot(cfg.driverRoot),
|
||||||
WithDryRun(cfg.dryRun),
|
WithDryRun(cfg.dryRun),
|
||||||
)
|
)
|
||||||
|
create:
|
||||||
err := l.CreateLinks()
|
err := l.CreateLinks()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create links: %v", err)
|
return fmt.Errorf("failed to create links: %v", err)
|
||||||
}
|
}
|
||||||
return nil
|
if !cfg.watch {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
|
||||||
|
case event := <-watcher.Events:
|
||||||
|
deviceNode := filepath.Base(event.Name)
|
||||||
|
if !strings.HasPrefix(deviceNode, "nvidia") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if event.Op&fsnotify.Create == fsnotify.Create {
|
||||||
|
m.logger.Infof("%s created, restarting.", event.Name)
|
||||||
|
goto create
|
||||||
|
}
|
||||||
|
if event.Op&fsnotify.Create == fsnotify.Remove {
|
||||||
|
m.logger.Infof("%s removed. Ignoring", event.Name)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch for any other fs errors and log them.
|
||||||
|
case err := <-watcher.Errors:
|
||||||
|
m.logger.Errorf("inotify: %s", err)
|
||||||
|
|
||||||
|
// React to signals
|
||||||
|
case s := <-sigs:
|
||||||
|
switch s {
|
||||||
|
case syscall.SIGHUP:
|
||||||
|
m.logger.Infof("Received SIGHUP, recreating symlinks.")
|
||||||
|
goto create
|
||||||
|
default:
|
||||||
|
m.logger.Infof("Received signal %q, shutting down.", s)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type linkCreator struct {
|
type linkCreator struct {
|
||||||
@ -207,3 +269,27 @@ type deviceNode struct {
|
|||||||
func (d deviceNode) devCharName() string {
|
func (d deviceNode) devCharName() string {
|
||||||
return fmt.Sprintf("%d:%d", d.major, d.minor)
|
return fmt.Sprintf("%d:%d", d.major, d.minor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newFSWatcher(files ...string) (*fsnotify.Watcher, error) {
|
||||||
|
watcher, err := fsnotify.NewWatcher()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range files {
|
||||||
|
err = watcher.Add(f)
|
||||||
|
if err != nil {
|
||||||
|
watcher.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return watcher, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newOSWatcher(sigs ...os.Signal) chan os.Signal {
|
||||||
|
sigChan := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sigChan, sigs...)
|
||||||
|
|
||||||
|
return sigChan
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user