Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions cmd/nvidia-validator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/NVIDIA/go-nvlib/pkg/nvmdev"
"github.com/NVIDIA/go-nvlib/pkg/nvpci"
devchar "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/system/create-dev-char-symlinks"
"github.com/moby/sys/symlink"
log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert/yaml"
cli "github.com/urfave/cli/v3"
Expand Down Expand Up @@ -135,6 +136,7 @@ var (
hostRootFlag string
driverInstallDirFlag string
driverInstallDirCtrPathFlag string
hostRootCtrPath = "/host"
)

// defaultGPUWorkloadConfig is "vm-passthrough" unless
Expand Down Expand Up @@ -744,20 +746,26 @@ func isDriverManagedByOperator(ctx context.Context) (bool, error) {

func validateHostDriver(silent bool) error {
log.Info("Attempting to validate a pre-installed driver on the host")
if fileInfo, err := os.Lstat(filepath.Join("/host", wslNvidiaSMIPath)); err == nil && fileInfo.Size() != 0 {
if fileInfo, err := os.Lstat(filepath.Join(hostRootCtrPath, wslNvidiaSMIPath)); err == nil && fileInfo.Size() != 0 {
log.Infof("WSL2 system detected, assuming driver is pre-installed")
disableDevCharSymlinkCreation = true
return nil
}
fileInfo, err := os.Lstat("/host/usr/bin/nvidia-smi")

nvidiaSMIPath, err := symlink.FollowSymlinkInScope(filepath.Join(hostRootCtrPath, "usr/bin/nvidia-smi"), hostRootCtrPath)
if err != nil {
return fmt.Errorf("failed to resolve 'nvidia-smi' path on the host: %w", err)
}

fileInfo, err := os.Lstat(nvidiaSMIPath)
if err != nil {
return fmt.Errorf("no 'nvidia-smi' file present on the host: %w", err)
}
if fileInfo.Size() == 0 {
return fmt.Errorf("empty 'nvidia-smi' file found on the host")
}
command := "chroot"
args := []string{"/host", "nvidia-smi"}
args := []string{hostRootCtrPath, "nvidia-smi"}

return runCommand(command, args, silent)
}
Expand Down
52 changes: 52 additions & 0 deletions cmd/nvidia-validator/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,61 @@ package main
import (
"context"
"os"
"path/filepath"
"reflect"
"strings"
"testing"
)

func Test_validateHostDriverWithAbsoluteUsrBinSymlink(t *testing.T) {
hostRoot := t.TempDir()

targetDir := filepath.Join(hostRoot, "run/current-system/sw/bin")
if err := os.MkdirAll(targetDir, 0755); err != nil {
t.Fatalf("failed to create target directory: %v", err)
}
if err := os.WriteFile(filepath.Join(targetDir, "nvidia-smi"), []byte("fake nvidia-smi"), 0600); err != nil {
t.Fatalf("failed to create nvidia-smi: %v", err)
}

usrDir := filepath.Join(hostRoot, "usr")
if err := os.MkdirAll(usrDir, 0755); err != nil {
t.Fatalf("failed to create usr directory: %v", err)
}
if err := os.Symlink("/run/current-system/sw/bin", filepath.Join(usrDir, "bin")); err != nil {
t.Fatalf("failed to create usr/bin symlink: %v", err)
}

originalHostRootCtrPath := hostRootCtrPath
hostRootCtrPath = hostRoot
defer func() { hostRootCtrPath = originalHostRootCtrPath }()

binDir := filepath.Join(t.TempDir(), "bin")
if err := os.MkdirAll(binDir, 0755); err != nil {
t.Fatalf("failed to create fake bin directory: %v", err)
}
argsFile := filepath.Join(t.TempDir(), "chroot-args")
chrootScript := "#!/bin/sh\nprintf '%s\\n' \"$@\" > \"$CHROOT_ARGS_FILE\"\n"
if err := os.WriteFile(filepath.Join(binDir, "chroot"), []byte(chrootScript), 0700); err != nil { //nolint:gosec // Test creates a private executable stub.
t.Fatalf("failed to create fake chroot: %v", err)
}
t.Setenv("CHROOT_ARGS_FILE", argsFile)
t.Setenv("PATH", binDir+string(os.PathListSeparator)+os.Getenv("PATH"))

if err := validateHostDriver(true); err != nil {
t.Fatalf("validateHostDriver() unexpected error: %v", err)
}
argsBytes, err := os.ReadFile(argsFile)
if err != nil {
t.Fatal("validateHostDriver() did not run nvidia-smi validation command")
}
wantArgs := []string{hostRoot, "nvidia-smi"}
gotArgs := strings.Split(strings.TrimSpace(string(argsBytes)), "\n")
if !reflect.DeepEqual(gotArgs, wantArgs) {
t.Fatalf("args = %v, want %v", gotArgs, wantArgs)
}
}

func Test_isValidComponent(t *testing.T) {
tests := []struct {
name string
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
github.com/go-logr/logr v1.4.3
github.com/go-logr/zapr v1.3.0
github.com/moby/sys/symlink v0.3.0
github.com/onsi/ginkgo/v2 v2.28.3
github.com/onsi/gomega v1.40.0
github.com/openshift/api v0.0.0-20260213204242-d34f11c515b3
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
github.com/moby/sys/symlink v0.3.0 h1:GZX89mEZ9u53f97npBy4Rc3vJKj7JBDj/PN2I22GrNU=
github.com/moby/sys/symlink v0.3.0/go.mod h1:3eNdhduHmYPcgsJtZXW1W4XUJdZGBIkttZ8xKqPUJq0=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
Expand Down
202 changes: 202 additions & 0 deletions vendor/github.com/moby/sys/symlink/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading